Agora Java API Reference for Android
AgoraOptional.h
1 // Copyright (c) 2019 Agora.io. All rights reserved
2 
3 // This program is confidential and proprietary to Agora.io.
4 // And may not be copied, reproduced, modified, disclosed to others, published
5 // or used, in whole or in part, without the express prior written permission
6 // of Agora.io.
7 #pragma once
8 
9 #include <type_traits>
10 #include <utility>
11 
12 #ifndef CONSTEXPR
13 #if __cplusplus <= 199711L
14 #define CONSTEXPR
15 #else
16 #define CONSTEXPR constexpr
17 #endif // __cplusplus <= 199711L
18 #endif // !CONSTEXPR
19 
20 namespace agora {
21 
22 // Specification:
23 // http://en.cppreference.com/w/cpp/utility/optional/in_place_t
24 struct in_place_t {};
25 
26 // Specification:
27 // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
28 struct nullopt_t {
29  CONSTEXPR explicit nullopt_t(int) {}
30 };
31 
32 // Specification:
33 // http://en.cppreference.com/w/cpp/utility/optional/in_place
34 /*CONSTEXPR*/ const in_place_t in_place = {};
35 
36 // Specification:
37 // http://en.cppreference.com/w/cpp/utility/optional/nullopt
38 /*CONSTEXPR*/ const nullopt_t nullopt(0);
39 
40 // Forward declaration, which is refered by following helpers.
41 template <typename T>
42 class Optional;
43 
44 namespace internal {
45 
46 template <typename T>
48  // Initializing |empty_| here instead of using default member initializing
49  // to avoid errors in g++ 4.8.
50  CONSTEXPR OptionalStorageBase() : is_populated_(false), empty_('\0') {}
51 
52  template <class... Args>
53  CONSTEXPR explicit OptionalStorageBase(in_place_t, Args&&... args)
54  : is_populated_(true), value_(std::forward<Args>(args)...) {}
55 
56  // When T is not trivially destructible we must call its
57  // destructor before deallocating its memory.
58  // Note that this hides the (implicitly declared) move constructor, which
59  // would be used for constexpr move constructor in OptionalStorage<T>.
60  // It is needed iff T is trivially move constructible. However, the current
61  // is_trivially_{copy,move}_constructible implementation requires
62  // is_trivially_destructible (which looks a bug, cf:
63  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
64  // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
65  // necessary for this case at the moment. Please see also the destructor
66  // comment in "is_trivially_destructible = true" specialization below.
68  if (is_populated_)
69  value_.~T();
70  }
71 
72  template <class... Args>
73  void Init(Args&&... args) {
74  ::new (&value_) T(std::forward<Args>(args)...);
75  is_populated_ = true;
76  }
77 
78  bool is_populated_;
79 
80  union {
81  // |empty_| exists so that the union will always be initialized, even when
82  // it doesn't contain a value. Union members must be initialized for the
83  // constructor to be 'constexpr'.
84  char empty_;
85  T value_;
86  };
87 };
88 
89 // Implement conditional constexpr copy and move constructors. These are
90 // constexpr if is_trivially_{copy,move}_constructible<T>::value is true
91 // respectively. If each is true, the corresponding constructor is defined as
92 // "= default;", which generates a constexpr constructor (In this case,
93 // the condition of constexpr-ness is satisfied because the base class also has
94 // compiler generated constexpr {copy,move} constructors). Note that
95 // placement-new is prohibited in constexpr.
96 template <typename T>
98  // This is no trivially {copy,move} constructible case. Other cases are
99  // defined below as specializations.
100 
101  // Accessing the members of template base class requires explicit
102  // declaration.
106 
107  // Inherit constructors (specifically, the in_place constructor).
108  //using OptionalStorageBase<T>::OptionalStorageBase;
109 
110  template <class... Args>
111  CONSTEXPR explicit OptionalStorage(in_place_t in_place, Args&&... args)
112  : OptionalStorageBase<T>(in_place, std::forward<Args>(args)...) {}
113 
114  // User defined constructor deletes the default constructor.
115  // Define it explicitly.
116  OptionalStorage() {}
117 
118  OptionalStorage(const OptionalStorage& other) {
119  if (other.is_populated_)
120  Init(other.value_);
121  }
122 
123  OptionalStorage(OptionalStorage&& other) noexcept(
124  std::is_nothrow_move_constructible<T>::value) {
125  if (other.is_populated_)
126  Init(std::move(other.value_));
127  }
128 };
129 
130 // Base class to support conditionally usable copy-/move- constructors
131 // and assign operators.
132 template <typename T>
134  // This class provides implementation rather than public API, so everything
135  // should be hidden. Often we use composition, but we cannot in this case
136  // because of C++ language restriction.
137  protected:
138  CONSTEXPR OptionalBase() {}
139  CONSTEXPR OptionalBase(const OptionalBase& other) : storage_(other.storage_) {}
140  CONSTEXPR OptionalBase(OptionalBase&& other) : storage_(std::move(other.storage_)) {}
141 
142  template <class... Args>
143  CONSTEXPR explicit OptionalBase(in_place_t, Args&&... args)
144  : storage_(in_place, std::forward<Args>(args)...) {}
145 
146  // Implementation of converting constructors.
147  template <typename U>
148  explicit OptionalBase(const OptionalBase<U>& other) {
149  if (other.storage_.is_populated_)
150  storage_.Init(other.storage_.value_);
151  }
152 
153  template <typename U>
154  explicit OptionalBase(OptionalBase<U>&& other) {
155  if (other.storage_.is_populated_)
156  storage_.Init(std::move(other.storage_.value_));
157  }
158 
159  ~OptionalBase() {}
160 
161  OptionalBase& operator=(const OptionalBase& other) {
162  CopyAssign(other);
163  return *this;
164  }
165 
166  OptionalBase& operator=(OptionalBase&& other) noexcept(
167  std::is_nothrow_move_assignable<T>::value&&
168  std::is_nothrow_move_constructible<T>::value) {
169  MoveAssign(std::move(other));
170  return *this;
171  }
172 
173  template <typename U>
174  void CopyAssign(const OptionalBase<U>& other) {
175  if (other.storage_.is_populated_)
176  InitOrAssign(other.storage_.value_);
177  else
178  FreeIfNeeded();
179  }
180 
181  template <typename U>
182  void MoveAssign(OptionalBase<U>&& other) {
183  if (other.storage_.is_populated_)
184  InitOrAssign(std::move(other.storage_.value_));
185  else
186  FreeIfNeeded();
187  }
188 
189  template <typename U>
190  void InitOrAssign(U&& value) {
191  if (storage_.is_populated_)
192  storage_.value_ = std::forward<U>(value);
193  else
194  storage_.Init(std::forward<U>(value));
195  }
196 
197  void FreeIfNeeded() {
198  if (!storage_.is_populated_)
199  return;
200  storage_.value_.~T();
201  storage_.is_populated_ = false;
202  }
203 
204  // For implementing conversion, allow access to other typed OptionalBase
205  // class.
206  template <typename U>
207  friend class OptionalBase;
208 
209  OptionalStorage<T> storage_;
210 };
211 
212 // The following {Copy,Move}{Constructible,Assignable} structs are helpers to
213 // implement constructor/assign-operator overloading. Specifically, if T is
214 // is not movable but copyable, Optional<T>'s move constructor should not
215 // participate in overload resolution. This inheritance trick implements that.
216 template <bool is_copy_constructible>
218 
219 template <>
220 struct CopyConstructible<false> {
221  CONSTEXPR CopyConstructible() {}
222  CONSTEXPR CopyConstructible(CopyConstructible&&) {}
223  CopyConstructible& operator=(const CopyConstructible&) { return *this; }
224  CopyConstructible& operator=(CopyConstructible&&) { return *this; }
225 
226  private:
227  CONSTEXPR CopyConstructible(const CopyConstructible&);
228 };
229 
230 template <bool is_move_constructible>
232 
233 template <>
234 struct MoveConstructible<false> {
235  CONSTEXPR MoveConstructible() {}
236  CONSTEXPR MoveConstructible(const MoveConstructible&) {}
237  MoveConstructible& operator=(const MoveConstructible&) { return *this; }
238  MoveConstructible& operator=(MoveConstructible&&) { return *this; }
239 
240  private:
242 };
243 
244 template <bool is_copy_assignable>
245 struct CopyAssignable {};
246 
247 template <>
248 struct CopyAssignable<false> {
249  CONSTEXPR CopyAssignable() {}
250  CONSTEXPR CopyAssignable(const CopyAssignable&) {}
251  CONSTEXPR CopyAssignable(CopyAssignable&&) {}
252  CopyAssignable& operator=(CopyAssignable&&) { return *this; }
253 
254  private:
255  CopyAssignable& operator=(const CopyAssignable&);
256 };
257 
258 template <bool is_move_assignable>
259 struct MoveAssignable {};
260 
261 template <>
262 struct MoveAssignable<false> {
263  CONSTEXPR MoveAssignable() {}
264  CONSTEXPR MoveAssignable(const MoveAssignable&) {}
265  CONSTEXPR MoveAssignable(MoveAssignable&&) {}
266  MoveAssignable& operator=(const MoveAssignable&) { return *this; }
267 
268  private:
269  MoveAssignable& operator=(MoveAssignable&&);
270 };
271 
272 // Helper to conditionally enable converting constructors and assign operators.
273 template <typename T, typename U>
275  : std::integral_constant<
276  bool,
277  std::is_constructible<T, Optional<U>&>::value ||
278  std::is_constructible<T, const Optional<U>&>::value ||
279  std::is_constructible<T, Optional<U>&&>::value ||
280  std::is_constructible<T, const Optional<U>&&>::value ||
281  std::is_convertible<Optional<U>&, T>::value ||
282  std::is_convertible<const Optional<U>&, T>::value ||
283  std::is_convertible<Optional<U>&&, T>::value ||
284  std::is_convertible<const Optional<U>&&, T>::value> {};
285 
286 template <typename T, typename U>
288  : std::integral_constant<
289  bool,
290  IsConvertibleFromOptional<T, U>::value ||
291  std::is_assignable<T&, Optional<U>&>::value ||
292  std::is_assignable<T&, const Optional<U>&>::value ||
293  std::is_assignable<T&, Optional<U>&&>::value ||
294  std::is_assignable<T&, const Optional<U>&&>::value> {};
295 
296 // Forward compatibility for C++17.
297 // Introduce one more deeper nested namespace to avoid leaking using std::swap.
298 namespace swappable_impl {
299 using std::swap;
300 
302  // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
303  // is available for T. Otherwise, Check's overload resolution falls back
304  // to Check(...) declared below thanks to SFINAE, so returns false_type.
305  template <typename T>
306  static auto Check(int)
307  -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
308 
309  template <typename T>
310  static std::false_type Check(...);
311 };
312 } // namespace swappable_impl
313 
314 template <typename T>
315 struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
316 
317 } // namespace internal
318 
319 // On Windows, by default, empty-base class optimization does not work,
320 // which means even if the base class is empty struct, it still consumes one
321 // byte for its body. __declspec(empty_bases) enables the optimization.
322 // cf)
323 // https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
324 #ifdef _WIN32
325 #define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
326 #else
327 #define OPTIONAL_DECLSPEC_EMPTY_BASES
328 #endif
329 
330 // Optional is a Chromium version of the C++17 optional class:
331 // std::optional documentation:
332 // http://en.cppreference.com/w/cpp/utility/optional
333 // Chromium documentation:
334 // https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
335 //
336 // These are the differences between the specification and the implementation:
337 // - Constructors do not use 'constexpr' as it is a C++14 extension.
338 // - 'constexpr' might be missing in some places for reasons specified locally.
339 // - No exceptions are thrown, because they are banned from Chromium.
340 // Marked noexcept for only move constructor and move assign operators.
341 // - All the non-members are in the 'base' namespace instead of 'std'.
342 //
343 // Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
344 // T's constructor (specifically via IsConvertibleFromOptional), and in the
345 // check whether T can be constructible from Optional<T>, which is recursive
346 // so it does not work. As of Feb 2018, std::optional C++17 implementation in
347 // both clang and gcc has same limitation. MSVC SFINAE looks to have different
348 // behavior, but anyway it reports an error, too.
349 template <typename T>
350 class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
351  : public internal::OptionalBase<T>,
352  public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
353  public internal::MoveConstructible<std::is_move_constructible<T>::value>,
354  public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
355  std::is_copy_assignable<T>::value>,
356  public internal::MoveAssignable<std::is_move_constructible<T>::value &&
357  std::is_move_assignable<T>::value> {
358  public:
359 #undef OPTIONAL_DECLSPEC_EMPTY_BASES
360 
361  typedef T value_type;
362 
363  // Defer default/copy/move constructor implementation to OptionalBase.
364  CONSTEXPR Optional() {}
365  CONSTEXPR Optional(const Optional& other) : internal::OptionalBase<T>(other) {}
366 
367  CONSTEXPR Optional(nullopt_t) {} // NOLINT(runtime/explicit)
368 
369  // Converting copy constructor. "explicit" only if
370  // std::is_convertible<const U&, T>::value is false. It is implemented by
371  // declaring two almost same constructors, but that condition in enable_if_t
372  // is different, so that either one is chosen, thanks to SFINAE.
373  template <typename U>
374  Optional(const Optional<U>& other) : internal::OptionalBase<T>(other) {}
375 
376  // Converting move constructor. Similar to converting copy constructor,
377  // declaring two (explicit and non-explicit) constructors.
378  template <typename U>
379  Optional(Optional<U>&& other) : internal::OptionalBase<T>(std::move(other)) {}
380 
381  template <class... Args>
382  CONSTEXPR explicit Optional(in_place_t, Args&&... args)
383  : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
384 
385  template <class U, class... Args>
386  CONSTEXPR explicit Optional(in_place_t,
387  std::initializer_list<U> il,
388  Args&&... args)
389  : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
390 
391  // Forward value constructor. Similar to converting constructors,
392  // conditionally explicit.
393  template <typename U = value_type>
394  CONSTEXPR Optional(U&& value)
395  : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
396 
397  ~Optional() {}
398 
399  // Defer copy-/move- assign operator implementation to OptionalBase.
400  Optional& operator=(const Optional& other) {
401  if (&other == this) {
402  return *this;
403  }
404 
405  internal::OptionalBase<T>::operator=(other);
406  return *this;
407  }
408 
409  Optional& operator=(nullopt_t) {
410  FreeIfNeeded();
411  return *this;
412  }
413 
414  // Perfect-forwarded assignment.
415  template <typename U>
416  Optional& operator=(U&& value) {
417  InitOrAssign(std::forward<U>(value));
418  return *this;
419  }
420 
421  // Copy assign the state of other.
422  template <typename U>
423  Optional& operator=(const Optional<U>& other) {
424  CopyAssign(other);
425  return *this;
426  }
427 
428  // Move assign the state of other.
429  template <typename U>
430  Optional& operator=(Optional<U>&& other) {
431  MoveAssign(std::move(other));
432  return *this;
433  }
434 
435  const T* operator->() const {
436  return &storage_.value_;
437  }
438 
439  const T& operator*() const {
440  return storage_.value_;
441  }
442 
443  T& operator*() {
444  return storage_.value_;
445  }
446 
447  CONSTEXPR explicit operator bool() const { return storage_.is_populated_; }
448 
449  CONSTEXPR bool has_value() const { return storage_.is_populated_; }
450 
451 #if 1
452  const T& value() const {
453  return storage_.value_;
454  }
455 
456  template <class U>
457  CONSTEXPR T value_or(U&& default_value) const {
458  // TODO(mlamouri): add the following assert when possible:
459  // static_assert(std::is_copy_constructible<T>::value,
460  // "T must be copy constructible");
461  static_assert(std::is_convertible<U, T>::value,
462  "U must be convertible to T");
463  return storage_.is_populated_
464  ? value()
465  : static_cast<T>(std::forward<U>(default_value));
466  }
467 #else
468  const T& value() const & {
469  return storage_.value_;
470  }
471 
472  const T&& value() const && {
473  return std::move(storage_.value_);
474  }
475 
476  template <class U>
477  CONSTEXPR T value_or(U&& default_value) const & {
478  // TODO(mlamouri): add the following assert when possible:
479  // static_assert(std::is_copy_constructible<T>::value,
480  // "T must be copy constructible");
481  static_assert(std::is_convertible<U, T>::value,
482  "U must be convertible to T");
483  return storage_.is_populated_
484  ? value()
485  : static_cast<T>(std::forward<U>(default_value));
486  }
487 
488  template <class U>
489  CONSTEXPR T value_or(U&& default_value) const && {
490  // TODO(mlamouri): add the following assert when possible:
491  // static_assert(std::is_move_constructible<T>::value,
492  // "T must be move constructible");
493  static_assert(std::is_convertible<U, T>::value,
494  "U must be convertible to T");
495  return storage_.is_populated_
496  ? std::move(value())
497  : static_cast<T>(std::forward<U>(default_value));
498  }
499 #endif // 1
500 
501  void swap(Optional& other) {
502  if (!storage_.is_populated_ && !other.storage_.is_populated_)
503  return;
504 
505  if (storage_.is_populated_ != other.storage_.is_populated_) {
506  if (storage_.is_populated_) {
507  other.storage_.Init(std::move(storage_.value_));
508  FreeIfNeeded();
509  } else {
510  storage_.Init(std::move(other.storage_.value_));
511  other.FreeIfNeeded();
512  }
513  return;
514  }
515  using std::swap;
516  swap(**this, *other);
517  }
518 
519  void reset() { FreeIfNeeded(); }
520 
521  template <class... Args>
522  T& emplace(Args&&... args) {
523  FreeIfNeeded();
524  storage_.Init(std::forward<Args>(args)...);
525  return storage_.value_;
526  }
527 
528  template <class U, class... Args>
529  T& emplace(std::initializer_list<U> il, Args&&... args) {
530  FreeIfNeeded();
531  storage_.Init(il, std::forward<Args>(args)...);
532  return storage_.value_;
533  }
534 
535  private:
536  // Accessing template base class's protected member needs explicit
537  // declaration to do so.
538  using internal::OptionalBase<T>::CopyAssign;
539  using internal::OptionalBase<T>::FreeIfNeeded;
540  using internal::OptionalBase<T>::InitOrAssign;
541  using internal::OptionalBase<T>::MoveAssign;
542  using internal::OptionalBase<T>::storage_;
543 };
544 
545 // Here after defines comparation operators. The definition follows
546 // http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
547 // while bool() casting is replaced by has_value() to meet the chromium
548 // style guide.
549 template <class T, class U>
550 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
551  if (lhs.has_value() != rhs.has_value())
552  return false;
553  if (!lhs.has_value())
554  return true;
555  return *lhs == *rhs;
556 }
557 
558 template <class T, class U>
559 bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
560  if (lhs.has_value() != rhs.has_value())
561  return true;
562  if (!lhs.has_value())
563  return false;
564  return *lhs != *rhs;
565 }
566 
567 template <class T, class U>
568 bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
569  if (!rhs.has_value())
570  return false;
571  if (!lhs.has_value())
572  return true;
573  return *lhs < *rhs;
574 }
575 
576 template <class T, class U>
577 bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
578  if (!lhs.has_value())
579  return true;
580  if (!rhs.has_value())
581  return false;
582  return *lhs <= *rhs;
583 }
584 
585 template <class T, class U>
586 bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
587  if (!lhs.has_value())
588  return false;
589  if (!rhs.has_value())
590  return true;
591  return *lhs > *rhs;
592 }
593 
594 template <class T, class U>
595 bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
596  if (!rhs.has_value())
597  return true;
598  if (!lhs.has_value())
599  return false;
600  return *lhs >= *rhs;
601 }
602 
603 template <class T>
604 CONSTEXPR bool operator==(const Optional<T>& opt, nullopt_t) {
605  return !opt;
606 }
607 
608 template <class T>
609 CONSTEXPR bool operator==(nullopt_t, const Optional<T>& opt) {
610  return !opt;
611 }
612 
613 template <class T>
614 CONSTEXPR bool operator!=(const Optional<T>& opt, nullopt_t) {
615  return opt.has_value();
616 }
617 
618 template <class T>
619 CONSTEXPR bool operator!=(nullopt_t, const Optional<T>& opt) {
620  return opt.has_value();
621 }
622 
623 template <class T>
624 CONSTEXPR bool operator<(const Optional<T>& opt, nullopt_t) {
625  return false;
626 }
627 
628 template <class T>
629 CONSTEXPR bool operator<(nullopt_t, const Optional<T>& opt) {
630  return opt.has_value();
631 }
632 
633 template <class T>
634 CONSTEXPR bool operator<=(const Optional<T>& opt, nullopt_t) {
635  return !opt;
636 }
637 
638 template <class T>
639 CONSTEXPR bool operator<=(nullopt_t, const Optional<T>& opt) {
640  return true;
641 }
642 
643 template <class T>
644 CONSTEXPR bool operator>(const Optional<T>& opt, nullopt_t) {
645  return opt.has_value();
646 }
647 
648 template <class T>
649 CONSTEXPR bool operator>(nullopt_t, const Optional<T>& opt) {
650  return false;
651 }
652 
653 template <class T>
654 CONSTEXPR bool operator>=(const Optional<T>& opt, nullopt_t) {
655  return true;
656 }
657 
658 template <class T>
659 CONSTEXPR bool operator>=(nullopt_t, const Optional<T>& opt) {
660  return !opt;
661 }
662 
663 template <class T, class U>
664 CONSTEXPR bool operator==(const Optional<T>& opt, const U& value) {
665  return opt.has_value() ? *opt == value : false;
666 }
667 
668 template <class T, class U>
669 CONSTEXPR bool operator==(const U& value, const Optional<T>& opt) {
670  return opt.has_value() ? value == *opt : false;
671 }
672 
673 template <class T, class U>
674 CONSTEXPR bool operator!=(const Optional<T>& opt, const U& value) {
675  return opt.has_value() ? *opt != value : true;
676 }
677 
678 template <class T, class U>
679 CONSTEXPR bool operator!=(const U& value, const Optional<T>& opt) {
680  return opt.has_value() ? value != *opt : true;
681 }
682 
683 template <class T, class U>
684 CONSTEXPR bool operator<(const Optional<T>& opt, const U& value) {
685  return opt.has_value() ? *opt < value : true;
686 }
687 
688 template <class T, class U>
689 CONSTEXPR bool operator<(const U& value, const Optional<T>& opt) {
690  return opt.has_value() ? value < *opt : false;
691 }
692 
693 template <class T, class U>
694 CONSTEXPR bool operator<=(const Optional<T>& opt, const U& value) {
695  return opt.has_value() ? *opt <= value : true;
696 }
697 
698 template <class T, class U>
699 CONSTEXPR bool operator<=(const U& value, const Optional<T>& opt) {
700  return opt.has_value() ? value <= *opt : false;
701 }
702 
703 template <class T, class U>
704 CONSTEXPR bool operator>(const Optional<T>& opt, const U& value) {
705  return opt.has_value() ? *opt > value : false;
706 }
707 
708 template <class T, class U>
709 CONSTEXPR bool operator>(const U& value, const Optional<T>& opt) {
710  return opt.has_value() ? value > *opt : true;
711 }
712 
713 template <class T, class U>
714 CONSTEXPR bool operator>=(const Optional<T>& opt, const U& value) {
715  return opt.has_value() ? *opt >= value : false;
716 }
717 
718 template <class T, class U>
719 CONSTEXPR bool operator>=(const U& value, const Optional<T>& opt) {
720  return opt.has_value() ? value >= *opt : true;
721 }
722 
723 template <class T, class... Args>
724 CONSTEXPR Optional<T> make_optional(Args&&... args) {
725  return Optional<T>(in_place, std::forward<Args>(args)...);
726 }
727 
728 template <class T, class U, class... Args>
729 CONSTEXPR Optional<T> make_optional(std::initializer_list<U> il,
730  Args&&... args) {
731  return Optional<T>(in_place, il, std::forward<Args>(args)...);
732 }
733 
734 // Partial specialization for a function template is not allowed. Also, it is
735 // not allowed to add overload function to std namespace, while it is allowed
736 // to specialize the template in std. Thus, swap() (kind of) overloading is
737 // defined in base namespace, instead.
738 template <class T>
739 void swap(Optional<T>& lhs, Optional<T>& rhs) {
740  lhs.swap(rhs);
741 }
742 
743 } // namespace agora
744 
745 namespace std {
746 
747 template <class T>
748 struct hash<agora::Optional<T>> {
749  size_t operator()(const agora::Optional<T>& opt) const {
750  return opt == agora::nullopt ? 0 : std::hash<T>()(*opt);
751  }
752 };
753 
754 } // namespace std
755 
756 #undef CONSTEXPR
agora::internal::IsConvertibleFromOptional
Definition: AgoraOptional.h:284
agora::internal::swappable_impl::IsSwappableImpl
Definition: AgoraOptional.h:301
agora::internal::CopyConstructible
Definition: AgoraOptional.h:217
agora::internal::CopyAssignable
Definition: AgoraOptional.h:245
agora::internal::MoveConstructible
Definition: AgoraOptional.h:231
agora::in_place_t
Definition: AgoraOptional.h:24
agora::internal::MoveAssignable
Definition: AgoraOptional.h:259
agora::internal::OptionalStorage
Definition: AgoraOptional.h:97
agora::internal::OptionalBase
Definition: AgoraOptional.h:133
agora::nullopt_t
Definition: AgoraOptional.h:28
agora::internal::OptionalStorageBase
Definition: AgoraOptional.h:47
agora::Optional
Definition: AgoraOptional.h:42
agora::internal::IsAssignableFromOptional
Definition: AgoraOptional.h:294
agora::internal::IsSwappable
Definition: AgoraOptional.h:315