1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <initializer_list> 20 #include <memory> 21 #include <type_traits> 22 23 #if (!defined(_MSC_VER) && __has_include(<optional>)) || \ 24 (defined(_MSC_VER) && (__cplusplus >= 201703L || _MSVC_LANG >= 201703L)) 25 #include <optional> 26 // Technically it should be 201606 but std::optional is present with 201603. 27 #if __cpp_lib_optional >= 201603 || _LIBCPP_STD_VER > 14 28 #define THRIFT_HAS_OPTIONAL 29 #endif 30 #endif 31 32 #include <assert.h> 33 #include <limits.h> 34 #include <folly/CPortability.h> 35 #include <folly/CppAttributes.h> 36 #include <folly/Portability.h> 37 #include <folly/Traits.h> 38 #include <thrift/lib/cpp2/BoxedValuePtr.h> 39 #include <thrift/lib/cpp2/Thrift.h> 40 41 namespace apache { 42 namespace thrift { 43 namespace detail { 44 45 template <typename T> 46 using is_set_t = 47 std::conditional_t<std::is_const<T>::value, const uint8_t, uint8_t>; 48 49 [[noreturn]] void throw_on_bad_field_access(); 50 51 struct ensure_isset_unsafe_fn; 52 struct unset_unsafe_fn; 53 struct alias_isset_fn; 54 55 template <typename T> 56 class BitSet { 57 template <typename U> 58 friend class BitSet; 59 60 public: value_(value)61 explicit BitSet(T value = 0) : value_(value) {} 62 63 template <typename U> BitSet(const BitSet<U> & other)64 explicit BitSet(const BitSet<U>& other) noexcept : value_(other.value_) {} 65 66 class reference { 67 public: reference(BitSet & bitSet,const uint8_t bit)68 reference(BitSet& bitSet, const uint8_t bit) : bitSet_(bitSet), bit_(bit) {} 69 70 reference& operator=(bool flag) { 71 if (flag) { 72 bitSet_.set(bit_); 73 } else { 74 bitSet_.reset(bit_); 75 } 76 return *this; 77 } 78 79 operator bool() const { return bitSet_.get(bit_); } 80 81 reference& operator=(reference& other) { return *this = bool(other); } 82 83 private: 84 BitSet& bitSet_; 85 const uint8_t bit_; 86 }; 87 88 bool operator[](const uint8_t bit) const { return get(bit); } 89 90 reference operator[](const uint8_t bit) { 91 assert(bit < NUM_BITS); 92 return reference(*this, bit); 93 } 94 value()95 T& value() { return value_; } 96 value()97 const T& value() const { return value_; } 98 99 private: set(const uint8_t bit)100 void set(const uint8_t bit) { value_ |= (1 << bit); } 101 reset(const uint8_t bit)102 void reset(const uint8_t bit) { value_ &= ~(1 << bit); } 103 get(const uint8_t bit)104 bool get(const uint8_t bit) const { 105 assert(bit < NUM_BITS); 106 return (value_ >> bit) & 1; 107 } 108 109 T value_; 110 111 static constexpr int NUM_BITS = sizeof(T) * CHAR_BIT; 112 }; 113 } // namespace detail 114 115 // A reference to an unqualified field of the possibly const-qualified type 116 // std::remove_reference_t<T> in a Thrift-generated struct. 117 template <typename T> 118 class field_ref { 119 static_assert(std::is_reference<T>::value, "not a reference"); 120 121 template <typename U> 122 friend class field_ref; 123 friend struct apache::thrift::detail::unset_unsafe_fn; 124 125 public: 126 using value_type = std::remove_reference_t<T>; 127 using reference_type = T; 128 129 FOLLY_ERASE field_ref( 130 reference_type value, 131 apache::thrift::detail::is_set_t<value_type>& is_set, 132 const uint8_t bit = 0) noexcept value_(value)133 : value_(value), is_set_(is_set), bit_(bit) {} 134 135 template < 136 typename U, 137 std::enable_if_t< 138 std::is_same< 139 std::add_const_t<std::remove_reference_t<U>>, 140 value_type>{} && 141 !(std::is_rvalue_reference<T>{} && std::is_lvalue_reference<U>{}), 142 int> = 0> 143 FOLLY_ERASE /* implicit */ field_ref(const field_ref<U>& other) noexcept 144 : value_(other.value_), is_set_(other.is_set_), bit_(other.bit_) {} 145 146 template <typename U = value_type> 147 FOLLY_ERASE 148 std::enable_if_t<std::is_assignable<value_type&, U&&>::value, field_ref&> noexcept(std::is_nothrow_assignable<value_type &,U &&>::value)149 operator=(U&& value) noexcept( 150 std::is_nothrow_assignable<value_type&, U&&>::value) { 151 value_ = static_cast<U&&>(value); 152 is_set_[bit_] = true; 153 return *this; 154 } 155 156 // Workaround for https://bugs.llvm.org/show_bug.cgi?id=49442 noexcept(std::is_nothrow_assignable<value_type &,value_type &&>::value)157 FOLLY_ERASE field_ref& operator=(value_type&& value) noexcept( 158 std::is_nothrow_assignable<value_type&, value_type&&>::value) { 159 value_ = static_cast<value_type&&>(value); 160 is_set_[bit_] = true; 161 return *this; 162 value.~value_type(); // Force emit destructor... 163 } 164 165 // Assignment from field_ref is intentionally not provided to prevent 166 // potential confusion between two possible behaviors, copying and reference 167 // rebinding. The copy_from method is provided instead. 168 template <typename U> copy_from(field_ref<U> other)169 FOLLY_ERASE void copy_from(field_ref<U> other) noexcept( 170 std::is_nothrow_assignable<value_type&, U>::value) { 171 value_ = other.value(); 172 is_set_[bit_] = other.is_set(); 173 } 174 has_value()175 [[deprecated("Use is_set() method instead")]] FOLLY_ERASE bool has_value() 176 const noexcept { 177 return is_set_[bit_]; 178 } 179 180 // Returns true iff the field is set. field_ref doesn't provide conversion to 181 // bool to avoid confusion between checking if the field is set and getting 182 // the field's value, particularly for bool fields. is_set()183 FOLLY_ERASE bool is_set() const noexcept { return is_set_[bit_]; } 184 185 // Returns a reference to the value. value()186 FOLLY_ERASE reference_type value() const noexcept { 187 return static_cast<reference_type>(value_); 188 } 189 190 FOLLY_ERASE reference_type operator*() const noexcept { 191 return static_cast<reference_type>(value_); 192 } 193 194 FOLLY_ERASE value_type* operator->() const noexcept { return &value_; } 195 ensure()196 FOLLY_ERASE reference_type ensure() noexcept { 197 is_set_[bit_] = true; 198 return static_cast<reference_type>(value_); 199 } 200 201 template <typename Index> 202 FOLLY_ERASE auto operator[](const Index& index) const -> decltype(auto) { 203 return value_[index]; 204 } 205 206 template <typename... Args> emplace(Args &&...args)207 FOLLY_ERASE value_type& emplace(Args&&... args) { 208 is_set_[bit_] = false; // C++ Standard requires *this to be empty if 209 // `std::optional::emplace(...)` throws 210 value_ = value_type(static_cast<Args&&>(args)...); 211 is_set_[bit_] = true; 212 return value_; 213 } 214 215 template <class U, class... Args> 216 FOLLY_ERASE std::enable_if_t< 217 std::is_constructible<value_type, std::initializer_list<U>, Args&&...>:: 218 value, 219 value_type&> emplace(std::initializer_list<U> ilist,Args &&...args)220 emplace(std::initializer_list<U> ilist, Args&&... args) { 221 is_set_[bit_] = false; 222 value_ = value_type(ilist, static_cast<Args&&>(args)...); 223 is_set_[bit_] = true; 224 return value_; 225 } 226 227 private: 228 value_type& value_; 229 apache::thrift::detail::BitSet<apache::thrift::detail::is_set_t<value_type>&> 230 is_set_; 231 const uint8_t bit_; 232 }; 233 234 template <typename T, typename U> 235 bool operator==(field_ref<T> lhs, field_ref<U> rhs) { 236 return *lhs == *rhs; 237 } 238 239 template <typename T, typename U> 240 bool operator!=(field_ref<T> lhs, field_ref<U> rhs) { 241 return *lhs != *rhs; 242 } 243 244 template <typename T, typename U> 245 bool operator<(field_ref<T> lhs, field_ref<U> rhs) { 246 return *lhs < *rhs; 247 } 248 249 template <typename T, typename U> 250 bool operator>(field_ref<T> lhs, field_ref<U> rhs) { 251 return *lhs > *rhs; 252 } 253 254 template <typename T, typename U> 255 bool operator<=(field_ref<T> lhs, field_ref<U> rhs) { 256 return *lhs <= *rhs; 257 } 258 259 template <typename T, typename U> 260 bool operator>=(field_ref<T> lhs, field_ref<U> rhs) { 261 return *lhs >= *rhs; 262 } 263 264 template <typename T, typename U> 265 bool operator==(field_ref<T> lhs, const U& rhs) { 266 return *lhs == rhs; 267 } 268 269 template <typename T, typename U> 270 bool operator!=(field_ref<T> lhs, const U& rhs) { 271 return *lhs != rhs; 272 } 273 274 template <typename T, typename U> 275 bool operator<(field_ref<T> lhs, const U& rhs) { 276 return *lhs < rhs; 277 } 278 279 template <typename T, typename U> 280 bool operator>(field_ref<T> lhs, const U& rhs) { 281 return *lhs > rhs; 282 } 283 284 template <typename T, typename U> 285 bool operator<=(field_ref<T> lhs, const U& rhs) { 286 return *lhs <= rhs; 287 } 288 289 template <typename T, typename U> 290 bool operator>=(field_ref<T> lhs, const U& rhs) { 291 return *lhs >= rhs; 292 } 293 294 template <typename T, typename U> 295 bool operator==(const T& lhs, field_ref<U> rhs) { 296 return lhs == *rhs; 297 } 298 299 template <typename T, typename U> 300 bool operator!=(const T& lhs, field_ref<U> rhs) { 301 return lhs != *rhs; 302 } 303 304 template <typename T, typename U> 305 bool operator<(const T& lhs, field_ref<U> rhs) { 306 return lhs < *rhs; 307 } 308 309 template <typename T, typename U> 310 bool operator>(const T& lhs, field_ref<U> rhs) { 311 return lhs > *rhs; 312 } 313 314 template <typename T, typename U> 315 bool operator<=(const T& lhs, field_ref<U> rhs) { 316 return lhs <= *rhs; 317 } 318 319 template <typename T, typename U> 320 bool operator>=(const T& lhs, field_ref<U> rhs) { 321 return lhs >= *rhs; 322 } 323 324 // A reference to an optional field of the possibly const-qualified type 325 // std::remove_reference_t<T> in a Thrift-generated struct. 326 template <typename T> 327 class optional_field_ref { 328 static_assert(std::is_reference<T>::value, "not a reference"); 329 330 template <typename U> 331 friend class optional_field_ref; 332 friend struct apache::thrift::detail::ensure_isset_unsafe_fn; 333 friend struct apache::thrift::detail::unset_unsafe_fn; 334 friend struct apache::thrift::detail::alias_isset_fn; 335 336 public: 337 using value_type = std::remove_reference_t<T>; 338 using reference_type = T; 339 340 FOLLY_ERASE optional_field_ref( 341 reference_type value, 342 apache::thrift::detail::is_set_t<value_type>& is_set, 343 const uint8_t bit = 0) noexcept value_(value)344 : value_(value), is_set_(is_set), bit_(bit) {} 345 346 template < 347 typename U, 348 std::enable_if_t< 349 std::is_same< 350 std::add_const_t<std::remove_reference_t<U>>, 351 value_type>{} && 352 !(std::is_rvalue_reference<T>{} && std::is_lvalue_reference<U>{}), 353 int> = 0> 354 FOLLY_ERASE /* implicit */ optional_field_ref( 355 const optional_field_ref<U>& other) noexcept 356 : value_(other.value_), is_set_(other.is_set_), bit_(other.bit_) {} 357 358 template < 359 typename U, 360 std::enable_if_t< 361 std::is_same<T, U&&>{} || std::is_same<T, const U&&>{}, 362 int> = 0> 363 FOLLY_ERASE explicit optional_field_ref( 364 const optional_field_ref<U&>& other) noexcept 365 : value_(other.value_), is_set_(other.is_set_), bit_(other.bit_) {} 366 367 template <typename U = value_type> 368 FOLLY_ERASE std::enable_if_t< 369 std::is_assignable<value_type&, U&&>::value, 370 optional_field_ref&> noexcept(std::is_nothrow_assignable<value_type &,U &&>::value)371 operator=(U&& value) noexcept( 372 std::is_nothrow_assignable<value_type&, U&&>::value) { 373 value_ = static_cast<U&&>(value); 374 is_set_[bit_] = true; 375 return *this; 376 } 377 378 // Workaround for https://bugs.llvm.org/show_bug.cgi?id=49442 noexcept(std::is_nothrow_assignable<value_type &,value_type &&>::value)379 FOLLY_ERASE optional_field_ref& operator=(value_type&& value) noexcept( 380 std::is_nothrow_assignable<value_type&, value_type&&>::value) { 381 value_ = static_cast<value_type&&>(value); 382 is_set_[bit_] = true; 383 return *this; 384 value.~value_type(); // Force emit destructor... 385 } 386 387 // Copies the data (the set flag and the value if available) from another 388 // optional_field_ref object. 389 // 390 // Assignment from optional_field_ref is intentionally not provided to prevent 391 // potential confusion between two possible behaviors, copying and reference 392 // rebinding. This copy_from method is provided instead. 393 template <typename U> copy_from(const optional_field_ref<U> & other)394 FOLLY_ERASE void copy_from(const optional_field_ref<U>& other) noexcept( 395 std::is_nothrow_assignable<value_type&, U>::value) { 396 value_ = other.value_unchecked(); 397 is_set_[bit_] = other.has_value() ? true : false; 398 } 399 400 template <typename U> move_from(optional_field_ref<U> other)401 FOLLY_ERASE void move_from(optional_field_ref<U> other) noexcept( 402 std::is_nothrow_assignable<value_type&, std::remove_reference_t<U>&&>:: 403 value) { 404 value_ = static_cast<std::remove_reference_t<U>&&>(other.value_); 405 is_set_[bit_] = other.is_set_[other.bit_]; 406 } 407 408 #ifdef THRIFT_HAS_OPTIONAL 409 template <typename U> from_optional(const std::optional<U> & other)410 FOLLY_ERASE void from_optional(const std::optional<U>& other) noexcept( 411 std::is_nothrow_assignable<value_type&, const U&>::value) { 412 // Use if instead of a shorter ternary expression to prevent a potential 413 // copy if T and U mismatch. 414 if (other) { 415 value_ = *other; 416 } else { 417 value_ = {}; 418 } 419 is_set_[bit_] = other.has_value() ? true : false; 420 } 421 422 // Moves the value from std::optional. As std::optional's move constructor, 423 // move_from doesn't make other empty. 424 template <typename U> from_optional(std::optional<U> && other)425 FOLLY_ERASE void from_optional(std::optional<U>&& other) noexcept( 426 std::is_nothrow_assignable<value_type&, U&&>::value) { 427 // Use if instead of a shorter ternary expression to prevent a potential 428 // copy if T and U mismatch. 429 if (other) { 430 value_ = static_cast<U&&>(*other); 431 } else { 432 value_ = {}; 433 } 434 is_set_[bit_] = other.has_value() ? true : false; 435 } 436 to_optional()437 FOLLY_ERASE std::optional<std::remove_const_t<value_type>> to_optional() 438 const { 439 using type = std::optional<std::remove_const_t<value_type>>; 440 return is_set_[bit_] ? type(value_) : type(); 441 } 442 #endif 443 has_value()444 FOLLY_ERASE bool has_value() const noexcept { return is_set_[bit_]; } 445 446 FOLLY_ERASE explicit operator bool() const noexcept { return is_set_[bit_]; } 447 reset()448 FOLLY_ERASE void reset() noexcept { 449 value_ = value_type(); 450 is_set_[bit_] = false; 451 } 452 453 // Returns a reference to the value if this optional_field_ref has one; throws 454 // bad_field_access otherwise. value()455 FOLLY_ERASE reference_type value() const { 456 throw_if_unset(); 457 return static_cast<reference_type>(value_); 458 } 459 460 template <typename U = std::remove_const_t<value_type>> value_or(U && default_value)461 FOLLY_ERASE std::remove_const_t<value_type> value_or( 462 U&& default_value) const { 463 using type = std::remove_const_t<value_type>; 464 return is_set_[bit_] ? type(static_cast<reference_type>(value_)) 465 : type(static_cast<U&&>(default_value)); 466 } 467 468 // Returns a reference to the value without checking whether it is available. value_unchecked()469 FOLLY_ERASE reference_type value_unchecked() const { 470 return static_cast<reference_type>(value_); 471 } 472 473 FOLLY_ERASE reference_type operator*() const { return value(); } 474 475 FOLLY_ERASE value_type* operator->() const { 476 throw_if_unset(); 477 return &value_; 478 } 479 ensure()480 FOLLY_ERASE reference_type ensure() noexcept { 481 if (!is_set_[bit_]) { 482 emplace(); 483 } 484 return static_cast<reference_type>(value_); 485 } 486 487 template <typename... Args> emplace(Args &&...args)488 FOLLY_ERASE value_type& emplace(Args&&... args) { 489 reset(); // C++ Standard requires *this to be empty if 490 // `std::optional::emplace(...)` throws 491 value_ = value_type(static_cast<Args&&>(args)...); 492 is_set_[bit_] = true; 493 return value_; 494 } 495 496 template <class U, class... Args> 497 FOLLY_ERASE std::enable_if_t< 498 std::is_constructible<value_type, std::initializer_list<U>&, Args&&...>:: 499 value, 500 value_type&> emplace(std::initializer_list<U> ilist,Args &&...args)501 emplace(std::initializer_list<U> ilist, Args&&... args) { 502 reset(); 503 value_ = value_type(ilist, static_cast<Args&&>(args)...); 504 is_set_[bit_] = true; 505 return value_; 506 } 507 508 private: throw_if_unset()509 FOLLY_ERASE void throw_if_unset() const { 510 if (!is_set_[bit_]) { 511 apache::thrift::detail::throw_on_bad_field_access(); 512 } 513 } 514 515 value_type& value_; 516 apache::thrift::detail::BitSet<apache::thrift::detail::is_set_t<value_type>&> 517 is_set_; 518 const uint8_t bit_; 519 }; 520 521 template <typename T1, typename T2> 522 bool operator==(optional_field_ref<T1> a, optional_field_ref<T2> b) { 523 return a && b ? *a == *b : a.has_value() == b.has_value(); 524 } 525 526 template <typename T1, typename T2> 527 bool operator!=(optional_field_ref<T1> a, optional_field_ref<T2> b) { 528 return !(a == b); 529 } 530 531 template <typename T1, typename T2> 532 bool operator<(optional_field_ref<T1> a, optional_field_ref<T2> b) { 533 if (a.has_value() != b.has_value()) { 534 return a.has_value() < b.has_value(); 535 } 536 return a ? *a < *b : false; 537 } 538 539 template <typename T1, typename T2> 540 bool operator>(optional_field_ref<T1> a, optional_field_ref<T2> b) { 541 return b < a; 542 } 543 544 template <typename T1, typename T2> 545 bool operator<=(optional_field_ref<T1> a, optional_field_ref<T2> b) { 546 return !(a > b); 547 } 548 549 template <typename T1, typename T2> 550 bool operator>=(optional_field_ref<T1> a, optional_field_ref<T2> b) { 551 return !(a < b); 552 } 553 554 template <typename T, typename U> 555 bool operator==(optional_field_ref<T> a, const U& b) { 556 return a ? *a == b : false; 557 } 558 559 template <typename T, typename U> 560 bool operator!=(optional_field_ref<T> a, const U& b) { 561 return !(a == b); 562 } 563 564 template <typename T, typename U> 565 bool operator==(const U& a, optional_field_ref<T> b) { 566 return b == a; 567 } 568 569 template <typename T, typename U> 570 bool operator!=(const U& a, optional_field_ref<T> b) { 571 return b != a; 572 } 573 574 template <typename T, typename U> 575 bool operator<(optional_field_ref<T> a, const U& b) { 576 return a ? *a < b : true; 577 } 578 579 template <typename T, typename U> 580 bool operator>(optional_field_ref<T> a, const U& b) { 581 return a ? *a > b : false; 582 } 583 584 template <typename T, typename U> 585 bool operator<=(optional_field_ref<T> a, const U& b) { 586 return !(a > b); 587 } 588 589 template <typename T, typename U> 590 bool operator>=(optional_field_ref<T> a, const U& b) { 591 return !(a < b); 592 } 593 594 template <typename T, typename U> 595 bool operator<(const U& a, optional_field_ref<T> b) { 596 return b > a; 597 } 598 599 template <typename T, typename U> 600 bool operator<=(const U& a, optional_field_ref<T> b) { 601 return b >= a; 602 } 603 604 template <typename T, typename U> 605 bool operator>(const U& a, optional_field_ref<T> b) { 606 return b < a; 607 } 608 609 template <typename T, typename U> 610 bool operator>=(const U& a, optional_field_ref<T> b) { 611 return b <= a; 612 } 613 614 #ifdef THRIFT_HAS_OPTIONAL 615 template <class T> 616 bool operator==(const optional_field_ref<T>& a, std::nullopt_t) { 617 return !a.has_value(); 618 } 619 template <class T> 620 bool operator==(std::nullopt_t, const optional_field_ref<T>& a) { 621 return !a.has_value(); 622 } 623 template <class T> 624 bool operator!=(const optional_field_ref<T>& a, std::nullopt_t) { 625 return a.has_value(); 626 } 627 template <class T> 628 bool operator!=(std::nullopt_t, const optional_field_ref<T>& a) { 629 return a.has_value(); 630 } 631 #endif 632 633 namespace detail { 634 635 template <typename T> 636 struct is_boxed_value_ptr : std::false_type {}; 637 638 template <typename T> 639 struct is_boxed_value_ptr<boxed_value_ptr<T>> : std::true_type {}; 640 641 template <typename From, typename To> 642 using copy_reference_t = std::conditional_t< 643 std::is_lvalue_reference<From>{}, 644 std::add_lvalue_reference_t<To>, 645 std::add_rvalue_reference_t<To>>; 646 647 template <typename From, typename To> 648 using copy_const_t = std::conditional_t< 649 std::is_const<std::remove_reference_t<From>>{}, 650 std::add_const_t<To>, 651 To>; 652 653 } // namespace detail 654 655 template <typename T> 656 class optional_boxed_field_ref { 657 static_assert(std::is_reference<T>::value, "not a reference"); 658 static_assert( 659 detail::is_boxed_value_ptr<folly::remove_cvref_t<T>>::value, 660 "not a boxed_value_ptr"); 661 662 using element_type = typename folly::remove_cvref_t<T>::element_type; 663 664 template <typename U> 665 friend class optional_boxed_field_ref; 666 667 public: 668 using value_type = detail::copy_const_t<T, element_type>; 669 using reference_type = detail::copy_reference_t<T, value_type>; 670 671 FOLLY_ERASE optional_boxed_field_ref(T value) noexcept : value_(value) {} 672 673 template < 674 typename U, 675 std::enable_if_t< 676 std::is_same< 677 std::add_const_t<std::remove_reference_t<U>>, 678 std::remove_reference_t<T>>{} && 679 !(std::is_rvalue_reference<T>{} && std::is_lvalue_reference<U>{}), 680 int> = 0> 681 FOLLY_ERASE /* implicit */ optional_boxed_field_ref( 682 const optional_boxed_field_ref<U>& other) noexcept 683 : value_(other.value_) {} 684 685 template < 686 typename U, 687 std::enable_if_t< 688 std::is_same<T, U&&>{} || std::is_same<T, const U&&>{}, 689 int> = 0> 690 FOLLY_ERASE explicit optional_boxed_field_ref( 691 const optional_boxed_field_ref<U&>& other) noexcept 692 : value_(other.value_) {} 693 694 template <typename U = value_type> 695 FOLLY_ERASE std::enable_if_t< 696 std::is_assignable<value_type&, U&&>::value, 697 optional_boxed_field_ref&> 698 operator=(U&& value) { 699 value_ = static_cast<U&&>(value); 700 return *this; 701 } 702 703 // Copies the data (the set flag and the value if available) from another 704 // optional_boxed_field_ref object. 705 // 706 // Assignment from optional_boxed_field_ref is intentionally not provided to 707 // prevent potential confusion between two possible behaviors, copying and 708 // reference rebinding. This copy_from method is provided instead. 709 template <typename U> 710 FOLLY_ERASE void copy_from(const optional_boxed_field_ref<U>& other) { 711 value_ = T(other.value_); 712 } 713 714 template <typename U> 715 FOLLY_ERASE void move_from(optional_boxed_field_ref<U> other) noexcept { 716 value_ = static_cast<std::remove_reference_t<U>&&>(other.value_); 717 } 718 719 #ifdef THRIFT_HAS_OPTIONAL 720 template <typename U> 721 FOLLY_ERASE void from_optional(const std::optional<U>& other) { 722 // Use if instead of a shorter ternary expression to prevent a potential 723 // copy if T and U mismatch. 724 if (other) { 725 value_ = *other; 726 } else { 727 value_ = {}; 728 } 729 } 730 731 // Moves the value from std::optional. As std::optional's move constructor, 732 // move_from doesn't make other empty. 733 template <typename U> 734 FOLLY_ERASE void from_optional(std::optional<U>&& other) { 735 // Use if instead of a shorter ternary expression to prevent a potential 736 // copy if T and U mismatch. 737 if (other) { 738 value_ = static_cast<U&&>(*other); 739 } else { 740 value_ = {}; 741 } 742 } 743 744 FOLLY_ERASE std::optional<std::remove_const_t<value_type>> to_optional() 745 const { 746 using type = std::optional<std::remove_const_t<value_type>>; 747 return has_value() ? type(*value_) : type(); 748 } 749 #endif 750 751 FOLLY_ERASE bool has_value() const noexcept { 752 return static_cast<bool>(value_); 753 } 754 755 FOLLY_ERASE explicit operator bool() const noexcept { return has_value(); } 756 757 FOLLY_ERASE void reset() noexcept { value_.reset(); } 758 759 // Returns a reference to the value if this optional_boxed_field_ref has one; 760 // throws bad_field_access otherwise. 761 FOLLY_ERASE reference_type value() const { 762 throw_if_unset(); 763 return static_cast<reference_type>(*value_); 764 } 765 766 template <typename U = std::remove_const_t<value_type>> 767 FOLLY_ERASE std::remove_const_t<value_type> value_or( 768 U&& default_value) const { 769 using type = std::remove_const_t<value_type>; 770 return has_value() ? type(static_cast<reference_type>(*value_)) 771 : type(static_cast<U&&>(default_value)); 772 } 773 774 FOLLY_ERASE reference_type operator*() const { return value(); } 775 776 FOLLY_ERASE value_type* operator->() const { 777 throw_if_unset(); 778 return &*value_; 779 } 780 781 FOLLY_ERASE reference_type ensure() { 782 if (!has_value()) { 783 emplace(); 784 } 785 return static_cast<reference_type>(*value_); 786 } 787 788 template <typename... Args> 789 FOLLY_ERASE value_type& emplace(Args&&... args) { 790 reset(); // C++ Standard requires *this to be empty if 791 // `std::optional::emplace(...)` throws 792 value_ = value_type(static_cast<Args&&>(args)...); 793 return *value_; 794 } 795 796 template <class U, class... Args> 797 FOLLY_ERASE std::enable_if_t< 798 std::is_constructible<value_type, std::initializer_list<U>&, Args&&...>:: 799 value, 800 value_type&> 801 emplace(std::initializer_list<U> ilist, Args&&... args) { 802 reset(); 803 value_ = value_type(ilist, static_cast<Args&&>(args)...); 804 return *value_; 805 } 806 807 private: 808 FOLLY_ERASE void throw_if_unset() const { 809 if (!has_value()) { 810 apache::thrift::detail::throw_on_bad_field_access(); 811 } 812 } 813 814 std::remove_reference_t<T>& value_; 815 }; 816 817 template <typename T1, typename T2> 818 bool operator==( 819 optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 820 return a && b ? *a == *b : a.has_value() == b.has_value(); 821 } 822 823 template <typename T1, typename T2> 824 bool operator!=( 825 optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 826 return !(a == b); 827 } 828 829 template <typename T1, typename T2> 830 bool operator<(optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 831 if (a.has_value() != b.has_value()) { 832 return a.has_value() < b.has_value(); 833 } 834 return a ? *a < *b : false; 835 } 836 837 template <typename T1, typename T2> 838 bool operator>(optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 839 return b < a; 840 } 841 842 template <typename T1, typename T2> 843 bool operator<=( 844 optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 845 return !(a > b); 846 } 847 848 template <typename T1, typename T2> 849 bool operator>=( 850 optional_boxed_field_ref<T1> a, optional_boxed_field_ref<T2> b) { 851 return !(a < b); 852 } 853 854 template <typename T, typename U> 855 bool operator==(optional_boxed_field_ref<T> a, const U& b) { 856 return a ? *a == b : false; 857 } 858 859 template <typename T, typename U> 860 bool operator!=(optional_boxed_field_ref<T> a, const U& b) { 861 return !(a == b); 862 } 863 864 template <typename T, typename U> 865 bool operator==(const U& a, optional_boxed_field_ref<T> b) { 866 return b == a; 867 } 868 869 template <typename T, typename U> 870 bool operator!=(const U& a, optional_boxed_field_ref<T> b) { 871 return b != a; 872 } 873 874 template <typename T, typename U> 875 bool operator<(optional_boxed_field_ref<T> a, const U& b) { 876 return a ? *a < b : true; 877 } 878 879 template <typename T, typename U> 880 bool operator>(optional_boxed_field_ref<T> a, const U& b) { 881 return a ? *a > b : false; 882 } 883 884 template <typename T, typename U> 885 bool operator<=(optional_boxed_field_ref<T> a, const U& b) { 886 return !(a > b); 887 } 888 889 template <typename T, typename U> 890 bool operator>=(optional_boxed_field_ref<T> a, const U& b) { 891 return !(a < b); 892 } 893 894 template <typename T, typename U> 895 bool operator<(const U& a, optional_boxed_field_ref<T> b) { 896 return b > a; 897 } 898 899 template <typename T, typename U> 900 bool operator<=(const U& a, optional_boxed_field_ref<T> b) { 901 return b >= a; 902 } 903 904 template <typename T, typename U> 905 bool operator>(const U& a, optional_boxed_field_ref<T> b) { 906 return b < a; 907 } 908 909 template <typename T, typename U> 910 bool operator>=(const U& a, optional_boxed_field_ref<T> b) { 911 return b <= a; 912 } 913 914 #ifdef THRIFT_HAS_OPTIONAL 915 template <class T> 916 bool operator==(const optional_boxed_field_ref<T>& a, std::nullopt_t) { 917 return !a.has_value(); 918 } 919 template <class T> 920 bool operator==(std::nullopt_t, const optional_boxed_field_ref<T>& a) { 921 return !a.has_value(); 922 } 923 template <class T> 924 bool operator!=(const optional_boxed_field_ref<T>& a, std::nullopt_t) { 925 return a.has_value(); 926 } 927 template <class T> 928 bool operator!=(std::nullopt_t, const optional_boxed_field_ref<T>& a) { 929 return a.has_value(); 930 } 931 #endif 932 933 namespace detail { 934 935 struct get_pointer_fn { 936 template <class T> 937 T* operator()(optional_field_ref<T&> field) const { 938 return field ? &*field : nullptr; 939 } 940 941 template <class T> 942 auto* operator()(optional_boxed_field_ref<T&> field) const { 943 return field ? &*field : nullptr; 944 } 945 }; 946 947 struct can_throw_fn { 948 template <typename T> 949 FOLLY_ERASE T&& operator()(T&& value) const { 950 return static_cast<T&&>(value); 951 } 952 }; 953 954 struct ensure_isset_unsafe_fn { 955 template <typename T> 956 void operator()(optional_field_ref<T> ref) const noexcept { 957 ref.is_set_[ref.bit_] = true; 958 } 959 }; 960 961 struct unset_unsafe_fn { 962 template <typename T> 963 void operator()(field_ref<T> ref) const noexcept { 964 ref.is_set_[ref.bit_] = false; 965 } 966 967 template <typename T> 968 void operator()(optional_field_ref<T> ref) const noexcept { 969 ref.is_set_[ref.bit_] = false; 970 } 971 }; 972 973 struct alias_isset_fn { 974 template <typename T, typename F> 975 auto operator()(optional_field_ref<T> ref, F functor) const 976 noexcept(noexcept(functor(ref.value_))) { 977 auto&& result = functor(ref.value_); 978 return optional_field_ref<decltype(result)>( 979 static_cast<decltype(result)>(result), ref.is_set_.value()); 980 } 981 }; 982 983 template <typename T> 984 FOLLY_ERASE apache::thrift::optional_field_ref<T&&> make_optional_field_ref( 985 T&& ref, 986 apache::thrift::detail::is_set_t<std::remove_reference_t<T>>& is_set) { 987 return {std::forward<T>(ref), is_set}; 988 } 989 990 template <typename T> 991 FOLLY_ERASE apache::thrift::field_ref<T&&> make_field_ref( 992 T&& ref, 993 apache::thrift::detail::is_set_t<std::remove_reference_t<T>>& is_set) { 994 return {std::forward<T>(ref), is_set}; 995 } 996 997 } // namespace detail 998 999 constexpr apache::thrift::detail::get_pointer_fn get_pointer; 1000 1001 // can_throw 1002 // 1003 // Used to annotate optional field accesses that can throw, 1004 // suppressing any linter warning about unchecked access. 1005 // 1006 // Example: 1007 // 1008 // auto value = apache::thrift::can_throw(*obj.field_ref()); 1009 constexpr apache::thrift::detail::can_throw_fn can_throw; 1010 1011 [[deprecated("Use `emplace` or `operator=` to set Thrift fields.")]] // 1012 constexpr apache::thrift::detail::ensure_isset_unsafe_fn ensure_isset_unsafe; 1013 1014 constexpr apache::thrift::detail::ensure_isset_unsafe_fn 1015 ensure_isset_unsafe_deprecated; 1016 1017 [[deprecated("Use `reset` to clear Thrift fields.")]] // 1018 constexpr apache::thrift::detail::unset_unsafe_fn unset_unsafe; 1019 1020 constexpr apache::thrift::detail::unset_unsafe_fn unset_unsafe_deprecated; 1021 1022 [[deprecated]] // 1023 constexpr apache::thrift::detail::alias_isset_fn alias_isset; 1024 1025 // A reference to an required field of the possibly const-qualified type 1026 // std::remove_reference_t<T> in a Thrift-generated struct. 1027 template <typename T> 1028 class required_field_ref { 1029 static_assert(std::is_reference<T>::value, "not a reference"); 1030 1031 template <typename U> 1032 friend class required_field_ref; 1033 1034 public: 1035 using value_type = std::remove_reference_t<T>; 1036 using reference_type = T; 1037 1038 FOLLY_ERASE explicit required_field_ref(reference_type value) noexcept 1039 : value_(value) {} 1040 1041 template < 1042 typename U, 1043 std::enable_if_t< 1044 std::is_same< 1045 std::add_const_t<std::remove_reference_t<U>>, 1046 value_type>{} && 1047 !(std::is_rvalue_reference<T>{} && std::is_lvalue_reference<U>{}), 1048 int> = 0> 1049 FOLLY_ERASE /* implicit */ required_field_ref( 1050 const required_field_ref<U>& other) noexcept 1051 : value_(other.value_) {} 1052 1053 template <typename U = value_type> 1054 FOLLY_ERASE std::enable_if_t< 1055 std::is_assignable<value_type&, U&&>::value, 1056 required_field_ref&> 1057 operator=(U&& value) noexcept( 1058 std::is_nothrow_assignable<value_type&, U&&>::value) { 1059 value_ = static_cast<U&&>(value); 1060 return *this; 1061 } 1062 1063 // Workaround for https://bugs.llvm.org/show_bug.cgi?id=49442 1064 FOLLY_ERASE required_field_ref& operator=(value_type&& value) noexcept( 1065 std::is_nothrow_assignable<value_type&, value_type&&>::value) { 1066 value_ = static_cast<value_type&&>(value); 1067 return *this; 1068 value.~value_type(); // Force emit destructor... 1069 } 1070 1071 // Assignment from required_field_ref is intentionally not provided to prevent 1072 // potential confusion between two possible behaviors, copying and reference 1073 // rebinding. The copy_from method is provided instead. 1074 template <typename U> 1075 FOLLY_ERASE void copy_from(required_field_ref<U> other) noexcept( 1076 std::is_nothrow_assignable<value_type&, U>::value) { 1077 value_ = other.value(); 1078 } 1079 1080 // Returns true iff the field is set. required_field_ref doesn't provide 1081 // conversion to bool to avoid confusion between checking if the field is set 1082 // and getting the field's value, particularly for bool fields. 1083 FOLLY_ERASE bool has_value() const noexcept { return true; } 1084 1085 // Returns a reference to the value. 1086 FOLLY_ERASE reference_type value() const noexcept { 1087 return static_cast<reference_type>(value_); 1088 } 1089 1090 FOLLY_ERASE reference_type operator*() const noexcept { 1091 return static_cast<reference_type>(value_); 1092 } 1093 1094 FOLLY_ERASE value_type* operator->() const noexcept { return &value_; } 1095 1096 FOLLY_ERASE reference_type ensure() noexcept { 1097 return static_cast<reference_type>(value_); 1098 } 1099 1100 template <typename Index> 1101 FOLLY_ERASE auto operator[](const Index& index) const -> decltype(auto) { 1102 return value_[index]; 1103 } 1104 1105 template <typename... Args> 1106 FOLLY_ERASE value_type& emplace(Args&&... args) { 1107 return value_ = value_type(static_cast<Args&&>(args)...); 1108 } 1109 1110 template <class U, class... Args> 1111 FOLLY_ERASE std::enable_if_t< 1112 std::is_constructible<value_type, std::initializer_list<U>, Args&&...>:: 1113 value, 1114 value_type&> 1115 emplace(std::initializer_list<U> ilist, Args&&... args) { 1116 return value_ = value_type(ilist, static_cast<Args&&>(args)...); 1117 } 1118 1119 private: 1120 value_type& value_; 1121 }; 1122 1123 template <typename T, typename U> 1124 bool operator==(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1125 return *lhs == *rhs; 1126 } 1127 1128 template <typename T, typename U> 1129 bool operator!=(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1130 return *lhs != *rhs; 1131 } 1132 1133 template <typename T, typename U> 1134 bool operator<(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1135 return *lhs < *rhs; 1136 } 1137 1138 template <typename T, typename U> 1139 bool operator>(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1140 return *lhs > *rhs; 1141 } 1142 1143 template <typename T, typename U> 1144 bool operator<=(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1145 return *lhs <= *rhs; 1146 } 1147 1148 template <typename T, typename U> 1149 bool operator>=(required_field_ref<T> lhs, required_field_ref<U> rhs) { 1150 return *lhs >= *rhs; 1151 } 1152 1153 template <typename T, typename U> 1154 bool operator==(required_field_ref<T> lhs, const U& rhs) { 1155 return *lhs == rhs; 1156 } 1157 1158 template <typename T, typename U> 1159 bool operator!=(required_field_ref<T> lhs, const U& rhs) { 1160 return *lhs != rhs; 1161 } 1162 1163 template <typename T, typename U> 1164 bool operator<(required_field_ref<T> lhs, const U& rhs) { 1165 return *lhs < rhs; 1166 } 1167 1168 template <typename T, typename U> 1169 bool operator>(required_field_ref<T> lhs, const U& rhs) { 1170 return *lhs > rhs; 1171 } 1172 1173 template <typename T, typename U> 1174 bool operator<=(required_field_ref<T> lhs, const U& rhs) { 1175 return *lhs <= rhs; 1176 } 1177 1178 template <typename T, typename U> 1179 bool operator>=(required_field_ref<T> lhs, const U& rhs) { 1180 return *lhs >= rhs; 1181 } 1182 1183 template <typename T, typename U> 1184 bool operator==(const T& lhs, required_field_ref<U> rhs) { 1185 return lhs == *rhs; 1186 } 1187 1188 template <typename T, typename U> 1189 bool operator!=(const T& lhs, required_field_ref<U> rhs) { 1190 return lhs != *rhs; 1191 } 1192 1193 template <typename T, typename U> 1194 bool operator<(const T& lhs, required_field_ref<U> rhs) { 1195 return lhs < *rhs; 1196 } 1197 1198 template <typename T, typename U> 1199 bool operator>(const T& lhs, required_field_ref<U> rhs) { 1200 return lhs > *rhs; 1201 } 1202 1203 template <typename T, typename U> 1204 bool operator<=(const T& lhs, required_field_ref<U> rhs) { 1205 return lhs <= *rhs; 1206 } 1207 1208 template <typename T, typename U> 1209 bool operator>=(const T& lhs, required_field_ref<U> rhs) { 1210 return lhs >= *rhs; 1211 } 1212 1213 namespace detail { 1214 1215 struct union_field_ref_owner_vtable { 1216 using reset_t = void(void*); 1217 1218 reset_t* reset; 1219 }; 1220 1221 struct union_field_ref_owner_vtable_impl { 1222 template <typename T> 1223 static void reset(void* obj) { 1224 apache::thrift::clear(*static_cast<T*>(obj)); 1225 } 1226 }; 1227 1228 template <typename T> 1229 FOLLY_INLINE_VARIABLE constexpr union_field_ref_owner_vtable // 1230 union_field_ref_owner_vtable_for{nullptr}; 1231 template <typename T> 1232 FOLLY_INLINE_VARIABLE constexpr union_field_ref_owner_vtable // 1233 union_field_ref_owner_vtable_for<T&>{ 1234 &union_field_ref_owner_vtable_impl::reset<T>}; 1235 template <typename T> 1236 FOLLY_INLINE_VARIABLE constexpr union_field_ref_owner_vtable // 1237 union_field_ref_owner_vtable_for<T const&>{nullptr}; 1238 1239 template <class T, class = void> 1240 struct element_type { 1241 using type = T; 1242 }; 1243 1244 template <class T> 1245 struct element_type<T, folly::void_t<typename T::element_type>> { 1246 using type = typename T::element_type; 1247 }; 1248 1249 template <class T> 1250 using is_boxed = folly::detail::is_instantiation_of<boxed_value_ptr, T>; 1251 1252 } // namespace detail 1253 1254 // A reference to an union field of the possibly const-qualified type 1255 template <typename T> 1256 class union_field_ref { 1257 static_assert(std::is_reference<T>::value, "not a reference"); 1258 1259 template <typename> 1260 friend class union_field_ref; 1261 1262 using element_type = 1263 typename detail::element_type<folly::remove_cvref_t<T>>::type; 1264 using is_boxed = detail::is_boxed<folly::remove_cvref_t<T>>; 1265 1266 using storage_reference_type = T; 1267 using storage_value_type = std::remove_reference_t<T>; 1268 1269 public: 1270 using value_type = detail::copy_const_t<T, element_type>; 1271 using reference_type = detail::copy_reference_t<T, value_type>; 1272 1273 private: 1274 using int_t = 1275 std::conditional_t<std::is_const<value_type>::value, const int, int>; 1276 using owner = 1277 std::conditional_t<std::is_const<value_type>::value, void const*, void*>; 1278 using vtable = apache::thrift::detail::union_field_ref_owner_vtable; 1279 1280 public: 1281 FOLLY_ERASE union_field_ref( 1282 storage_reference_type storage_value, 1283 int_t& type, 1284 int field_type, 1285 owner ow, 1286 vtable const& vt) noexcept 1287 : storage_value_(storage_value), 1288 type_(type), 1289 field_type_(field_type), 1290 owner_(ow), 1291 vtable_(vt) {} 1292 1293 template < 1294 typename U = value_type, 1295 std::enable_if_t< 1296 std::is_assignable<reference_type, U&&>::value && 1297 std::is_constructible<value_type, U&&>::value, 1298 int> = 0> 1299 FOLLY_ERASE union_field_ref& operator=(U&& other) noexcept( 1300 std::is_nothrow_constructible<value_type, U>::value&& 1301 std::is_nothrow_assignable<value_type, U>::value) { 1302 if (has_value()) { 1303 get_value() = static_cast<U&&>(other); 1304 } else { 1305 emplace(static_cast<U&&>(other)); 1306 } 1307 return *this; 1308 } 1309 1310 FOLLY_ERASE bool has_value() const { return type_ == field_type_; } 1311 1312 FOLLY_ERASE explicit operator bool() const { return has_value(); } 1313 1314 // Returns a reference to the value if this is union's active field, 1315 // bad_field_access otherwise. 1316 FOLLY_ERASE reference_type value() const { 1317 throw_if_unset(); 1318 return static_cast<reference_type>(get_value()); 1319 } 1320 1321 FOLLY_ERASE reference_type operator*() const { return value(); } 1322 1323 FOLLY_ERASE value_type* operator->() const { 1324 throw_if_unset(); 1325 return &get_value(); 1326 } 1327 1328 FOLLY_ERASE reference_type ensure() { 1329 if (!has_value()) { 1330 emplace(); 1331 } 1332 return static_cast<reference_type>(get_value()); 1333 } 1334 1335 template <typename... Args> 1336 FOLLY_ERASE value_type& emplace(Args&&... args) { 1337 vtable_.reset(owner_); 1338 ::new (&storage_value_) storage_value_type(static_cast<Args&&>(args)...); 1339 type_ = field_type_; 1340 return get_value(); 1341 } 1342 1343 template <class U, class... Args> 1344 FOLLY_ERASE std::enable_if_t< 1345 std::is_constructible<value_type, std::initializer_list<U>, Args&&...>:: 1346 value, 1347 value_type&> 1348 emplace(std::initializer_list<U> ilist, Args&&... args) { 1349 vtable_.reset(owner_); 1350 ::new (&storage_value_) 1351 storage_value_type(ilist, static_cast<Args&&>(args)...); 1352 type_ = field_type_; 1353 return get_value(); 1354 } 1355 1356 private: 1357 FOLLY_ERASE void throw_if_unset() const { 1358 if (!has_value()) { 1359 apache::thrift::detail::throw_on_bad_field_access(); 1360 } 1361 } 1362 1363 FOLLY_ERASE value_type& get_value() const { return get_value(is_boxed{}); } 1364 FOLLY_ERASE value_type& get_value(std::true_type) const { 1365 return *storage_value_; 1366 } 1367 FOLLY_ERASE value_type& get_value(std::false_type) const { 1368 return storage_value_; 1369 } 1370 1371 storage_value_type& storage_value_; 1372 int_t& type_; 1373 const int field_type_; 1374 owner owner_; 1375 vtable const& vtable_; 1376 }; 1377 1378 template <typename T1, typename T2> 1379 bool operator==(union_field_ref<T1> a, union_field_ref<T2> b) { 1380 return a && b ? *a == *b : a.has_value() == b.has_value(); 1381 } 1382 1383 template <typename T1, typename T2> 1384 bool operator!=(union_field_ref<T1> a, union_field_ref<T2> b) { 1385 return !(a == b); 1386 } 1387 1388 template <typename T1, typename T2> 1389 bool operator<(union_field_ref<T1> a, union_field_ref<T2> b) { 1390 if (a.has_value() != b.has_value()) { 1391 return a.has_value() < b.has_value(); 1392 } 1393 return a ? *a < *b : false; 1394 } 1395 1396 template <typename T1, typename T2> 1397 bool operator>(union_field_ref<T1> a, union_field_ref<T2> b) { 1398 return b < a; 1399 } 1400 1401 template <typename T1, typename T2> 1402 bool operator<=(union_field_ref<T1> a, union_field_ref<T2> b) { 1403 return !(a > b); 1404 } 1405 1406 template <typename T1, typename T2> 1407 bool operator>=(union_field_ref<T1> a, union_field_ref<T2> b) { 1408 return !(a < b); 1409 } 1410 1411 template <typename T, typename U> 1412 bool operator==(union_field_ref<T> a, const U& b) { 1413 return a ? *a == b : false; 1414 } 1415 1416 template <typename T, typename U> 1417 bool operator!=(union_field_ref<T> a, const U& b) { 1418 return !(a == b); 1419 } 1420 1421 template <typename T, typename U> 1422 bool operator==(const U& a, union_field_ref<T> b) { 1423 return b == a; 1424 } 1425 1426 template <typename T, typename U> 1427 bool operator!=(const U& a, union_field_ref<T> b) { 1428 return b != a; 1429 } 1430 1431 template <typename T, typename U> 1432 bool operator<(union_field_ref<T> a, const U& b) { 1433 return a ? *a < b : true; 1434 } 1435 1436 template <typename T, typename U> 1437 bool operator>(union_field_ref<T> a, const U& b) { 1438 return a ? *a > b : false; 1439 } 1440 1441 template <typename T, typename U> 1442 bool operator<=(union_field_ref<T> a, const U& b) { 1443 return !(a > b); 1444 } 1445 1446 template <typename T, typename U> 1447 bool operator>=(union_field_ref<T> a, const U& b) { 1448 return !(a < b); 1449 } 1450 1451 template <typename T, typename U> 1452 bool operator<(const U& a, union_field_ref<T> b) { 1453 return b > a; 1454 } 1455 1456 template <typename T, typename U> 1457 bool operator<=(const U& a, union_field_ref<T> b) { 1458 return b >= a; 1459 } 1460 1461 template <typename T, typename U> 1462 bool operator>(const U& a, union_field_ref<T> b) { 1463 return b < a; 1464 } 1465 1466 template <typename T, typename U> 1467 bool operator>=(const U& a, union_field_ref<T> b) { 1468 return b <= a; 1469 } 1470 1471 } // namespace thrift 1472 } // namespace apache 1473