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