optional.h
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Modifications copyright 2017 Universite catholique de Louvain (UCL), Belgium
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==============================================================================*/
17 
18 #pragma once
19 
20 #include <platform/macros.h>
21 
22 #include <assert.h>
23 #include <functional>
24 #include <initializer_list>
25 #include <type_traits>
26 #include <utility>
27 
28 namespace momemta {
29 namespace gtl {
30 
31 // A value of type gtl::optional<T> holds either a value of T or an
32 // "empty" value. When it holds a value of T, it stores it as a direct
33 // subobject, so sizeof(optional<T>) is approximately sizeof(T)+1. The interface
34 // is based on the upcoming std::optional<T>, and gtl::optional<T> is
35 // designed to be cheaply drop-in replaceable by std::optional<T>, once it is
36 // rolled out.
37 //
38 // This implementation is based on the specification in the latest draft as of
39 // 2017-01-05, section 20.6.
40 //
41 // Differences between gtl::optional<T> and std::optional<T> include:
42 // - constexpr not used for nonconst member functions.
43 // (dependency on some differences between C++11 and C++14.)
44 // - nullopt and in_place are not constexpr. We need the inline variable
45 // support in C++17 for external linkage.
46 // - optional::swap() and swap() relies on std::is_(nothrow_)swappable
47 // which is introduced in C++17. So we assume is_swappable is always true
48 // and is_nothrow_swappable is same as std::is_trivial.
49 // - make_optional cannot be constexpr due to absence of guaranteed copy
50 // elision.
51 //
52 // Synopsis:
53 //
54 // #include "lib/optional.h"
55 //
56 // momemta::gtl::optional<string> f() {
57 // std::string result;
58 // if (...) {
59 // ...
60 // result = ...;
61 // return result;
62 // } else {
63 // ...
64 // return momemta::gtl::nullopt;
65 // }
66 // }
67 //
68 // int main() {
69 // momemta::gtl::optional<string> optstr = f();
70 // if (optstr) {
71 // // non-empty
72 // print(optstr.value());
73 // } else {
74 // // empty
75 // error();
76 // }
77 // }
78 
79 class bad_optional_access: public std::exception {
80 public:
81 virtual const char* what() const noexcept;
82 };
83 
84 template <typename T>
85 class optional;
86 
87 // The tag constant `in_place` is used as the first parameter of an optional<T>
88 // constructor to indicate that the remaining arguments should be forwarded
89 // to the underlying T constructor.
90 struct in_place_t {};
91 extern const in_place_t in_place;
92 
93 // The tag constant `nullopt` is used to indicate an empty optional<T> in
94 // certain functions, such as construction or assignment.
95 struct nullopt_t {
96  struct init_t {};
97  static init_t init;
98  // It must not be default-constructible to avoid ambiguity for opt = {}.
99  // Note the non-const reference, it is to eliminate ambiguity for code like:
100  // struct S { int value; };
101  //
102  // void Test() {
103  // optional<S> opt;
104  // opt = {{}};
105  // }
106  explicit constexpr nullopt_t(init_t& /*unused*/) {} // NOLINT
107 };
108 constexpr nullopt_t nullopt(nullopt_t::init);
109 
110 namespace internal_optional {
111 
112 // define forward locally because std::forward is not constexpr until C++14
113 template <typename T>
114 constexpr T&& forward(typename std::remove_reference<T>::type&
115  t) noexcept { // NOLINT(runtime/references)
116  return static_cast<T&&>(t);
117 }
118 
119 struct empty_struct {};
120 // This class stores the data in optional<T>.
121 // It is specialized based on whether T is trivially destructible.
122 // This is the specialization for non trivially destructible type.
123 template <typename T, bool = std::is_trivially_destructible<T>::value>
125  protected:
126  // Whether there is data or not.
127  bool engaged_;
128  // data storage
129  union {
130  empty_struct dummy_;
131  T data_;
132  };
133 
134  void destruct() noexcept {
135  if (engaged_) {
136  data_.~T();
137  engaged_ = false;
138  }
139  }
140 
141  // dummy_ must be initialized for constexpr constructor
142  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{} {}
143 
144  template <typename... Args>
145  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
146  : engaged_(true), data_(internal_optional::forward<Args>(args)...) {}
147 
148  ~optional_data_dtor_base() { destruct(); }
149 };
150 
151 // Specialization for trivially destructible type.
152 template <typename T>
153 class optional_data_dtor_base<T, true> {
154  protected:
155  // Whether there is data or not.
156  bool engaged_;
157  // data storage
158  union {
159  empty_struct dummy_;
160  T data_;
161  };
162  void destruct() noexcept { engaged_ = false; }
163 
164  // dummy_ must be initialized for constexpr constructor
165  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{} {}
166 
167  template <typename... Args>
168  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
169  : engaged_(true), data_(internal_optional::forward<Args>(args)...) {}
170 
171  ~optional_data_dtor_base() = default;
172 };
173 
174 template <typename T>
176  protected:
178  using base::base;
179 
180  T* pointer() { return &this->data_; }
181 
182  constexpr const T* pointer() const { return &this->data_; }
183 
184  template <typename... Args>
185  void construct(Args&&... args) {
186  new (pointer()) T(std::forward<Args>(args)...);
187  this->engaged_ = true;
188  }
189 
190  template <typename U>
191  void assign(U&& u) {
192  if (this->engaged_) {
193  this->data_ = std::forward<U>(u);
194  } else {
195  construct(std::forward<U>(u));
196  }
197  }
198 
199  optional_data() = default;
200 
201  optional_data(const optional_data& rhs): base() {
202  if (rhs.engaged_) {
203  construct(rhs.data_);
204  }
205  }
206 
207  optional_data(optional_data&& rhs) noexcept(
208  std::is_nothrow_move_constructible<T>::value) {
209  if (rhs.engaged_) {
210  construct(std::move(rhs.data_));
211  }
212  }
213 
214  optional_data& operator=(const optional_data& rhs) {
215  if (rhs.engaged_) {
216  assign(rhs.data_);
217  } else {
218  this->destruct();
219  }
220  return *this;
221  }
222 
223  optional_data& operator=(optional_data&& rhs) noexcept(
224  std::is_nothrow_move_assignable<T>::value&&
225  std::is_nothrow_move_constructible<T>::value) {
226  if (rhs.engaged_) {
227  assign(std::move(rhs.data_));
228  } else {
229  this->destruct();
230  }
231  return *this;
232  }
233 };
234 
235 // ordered by level of restriction, from low to high.
236 // copyable implies movable.
237 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
238 
239 // base class for enabling/disabling copy/move constructor.
240 template <copy_traits>
242 
243 template <>
244 class optional_ctor_base<copy_traits::copyable> {
245  public:
246  constexpr optional_ctor_base() = default;
247  optional_ctor_base(const optional_ctor_base&) = default;
249  optional_ctor_base& operator=(const optional_ctor_base&) = default;
250  optional_ctor_base& operator=(optional_ctor_base&&) = default;
251 };
252 
253 template <>
254 class optional_ctor_base<copy_traits::movable> {
255  public:
256  constexpr optional_ctor_base() = default;
257  optional_ctor_base(const optional_ctor_base&) = delete;
259  optional_ctor_base& operator=(const optional_ctor_base&) = default;
260  optional_ctor_base& operator=(optional_ctor_base&&) = default;
261 };
262 
263 template <>
264 class optional_ctor_base<copy_traits::non_movable> {
265  public:
266  constexpr optional_ctor_base() = default;
267  optional_ctor_base(const optional_ctor_base&) = delete;
269  optional_ctor_base& operator=(const optional_ctor_base&) = default;
270  optional_ctor_base& operator=(optional_ctor_base&&) = default;
271 };
272 
273 // base class for enabling/disabling copy/move assignment.
274 template <copy_traits>
276 
277 template <>
278 class optional_assign_base<copy_traits::copyable> {
279  public:
280  constexpr optional_assign_base() = default;
281  optional_assign_base(const optional_assign_base&) = default;
283  optional_assign_base& operator=(const optional_assign_base&) = default;
284  optional_assign_base& operator=(optional_assign_base&&) = default;
285 };
286 
287 template <>
288 class optional_assign_base<copy_traits::movable> {
289  public:
290  constexpr optional_assign_base() = default;
291  optional_assign_base(const optional_assign_base&) = default;
293  optional_assign_base& operator=(const optional_assign_base&) = delete;
294  optional_assign_base& operator=(optional_assign_base&&) = default;
295 };
296 
297 template <>
298 class optional_assign_base<copy_traits::non_movable> {
299  public:
300  constexpr optional_assign_base() = default;
301  optional_assign_base(const optional_assign_base&) = default;
303  optional_assign_base& operator=(const optional_assign_base&) = delete;
304  optional_assign_base& operator=(optional_assign_base&&) = delete;
305 };
306 
307 template <typename T>
308 constexpr copy_traits get_ctor_copy_traits() {
309  return std::is_copy_constructible<T>::value
310  ? copy_traits::copyable
311  : std::is_move_constructible<T>::value ? copy_traits::movable
312  : copy_traits::non_movable;
313 }
314 
315 template <typename T>
316 constexpr copy_traits get_assign_copy_traits() {
317  return std::is_copy_assignable<T>::value &&
318  std::is_copy_constructible<T>::value
319  ? copy_traits::copyable
320  : std::is_move_assignable<T>::value &&
321  std::is_move_constructible<T>::value
322  ? copy_traits::movable
323  : copy_traits::non_movable;
324 }
325 
326 // Whether T is constructible or convertible from optional<U>.
327 template <typename T, typename U>
329  : std::integral_constant<
330  bool, std::is_constructible<T, optional<U>&>::value ||
331  std::is_constructible<T, optional<U>&&>::value ||
332  std::is_constructible<T, const optional<U>&>::value ||
333  std::is_constructible<T, const optional<U>&&>::value ||
334  std::is_convertible<optional<U>&, T>::value ||
335  std::is_convertible<optional<U>&&, T>::value ||
336  std::is_convertible<const optional<U>&, T>::value ||
337  std::is_convertible<const optional<U>&&, T>::value> {};
338 
339 // Whether T is constructible or convertible or assignable from optional<U>.
340 template <typename T, typename U>
342  : std::integral_constant<
343  bool, is_constructible_convertible_from_optional<T, U>::value ||
344  std::is_assignable<T&, optional<U>&>::value ||
345  std::is_assignable<T&, optional<U>&&>::value ||
346  std::is_assignable<T&, const optional<U>&>::value ||
347  std::is_assignable<T&, const optional<U>&&>::value> {};
348 
349 } // namespace internal_optional
350 
351 template <typename T>
352 class optional : private internal_optional::optional_data<T>,
354  internal_optional::get_ctor_copy_traits<T>()>,
356  internal_optional::get_assign_copy_traits<T>()> {
357  using data_base = internal_optional::optional_data<T>;
358 
359  public:
360  typedef T value_type;
361 
362  // [optional.ctor], constructors
363 
364  // A default constructed optional holds the empty value, NOT a default
365  // constructed T.
366  constexpr optional() noexcept {}
367 
368  // An optional initialized with `nullopt` holds the empty value.
369  constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit)
370 
371  // Copy constructor, standard semantics.
372  optional(const optional& src) = default;
373 
374  // Move constructor, standard semantics.
375  optional(optional&& src) = default;
376 
377  // optional<T>(in_place, arg1, arg2, arg3) constructs a non-empty optional
378  // with an in-place constructed value of T(arg1,arg2,arg3).
379  // TODO(b/34201852): Add std::is_constructible<T, Args&&...> SFINAE.
380  template <typename... Args>
381  constexpr explicit optional(in_place_t, Args&&... args)
382  : data_base(in_place_t(), internal_optional::forward<Args>(args)...) {}
383 
384  // optional<T>(in_place, {arg1, arg2, arg3}) constructs a non-empty optional
385  // with an in-place list-initialized value of T({arg1, arg2, arg3}).
386  template <typename U, typename... Args,
387  typename = typename std::enable_if<std::is_constructible<
388  T, std::initializer_list<U>&, Args&&...>::value>::type>
389  constexpr explicit optional(in_place_t, std::initializer_list<U> il,
390  Args&&... args)
391  : data_base(in_place_t(), il, internal_optional::forward<Args>(args)...) {
392  }
393 
394  template <
395  typename U = T,
396  typename std::enable_if<
397  std::is_constructible<T, U&&>::value &&
398  !std::is_same<in_place_t, typename std::decay<U>::type>::value &&
399  !std::is_same<optional<T>, typename std::decay<U>::type>::value &&
400  std::is_convertible<U&&, T>::value,
401  bool>::type = false>
402  constexpr optional(U&& v) // NOLINT
403  : data_base(in_place_t(), internal_optional::forward<U>(v)) {}
404 
405  template <
406  typename U = T,
407  typename std::enable_if<
408  std::is_constructible<T, U&&>::value &&
409  !std::is_same<in_place_t, typename std::decay<U>::type>::value &&
410  !std::is_same<optional<T>, typename std::decay<U>::type>::value &&
411  !std::is_convertible<U&&, T>::value,
412  bool>::type = false>
413  explicit constexpr optional(U&& v)
414  : data_base(in_place_t(), internal_optional::forward<U>(v)) {}
415 
416  // Converting copy constructor (implicit)
417  template <
418  typename U,
419  typename std::enable_if<
420  std::is_constructible<T, const U&>::value &&
422  T, U>::value &&
423  std::is_convertible<const U&, T>::value,
424  bool>::type = false>
425  optional(const optional<U>& rhs) { // NOLINT
426  if (rhs) {
427  this->construct(*rhs);
428  }
429  }
430 
431  // Converting copy constructor (explicit)
432  template <
433  typename U,
434  typename std::enable_if<
435  std::is_constructible<T, const U&>::value &&
437  T, U>::value &&
438  !std::is_convertible<const U&, T>::value,
439  bool>::type = false>
440  explicit optional(const optional<U>& rhs) {
441  if (rhs) {
442  this->construct(*rhs);
443  }
444  }
445 
446  // Converting move constructor (implicit)
447  template <
448  typename U,
449  typename std::enable_if<
450  std::is_constructible<T, U&&>::value &&
452  T, U>::value &&
453  std::is_convertible<U&&, T>::value,
454  bool>::type = false>
455  optional(optional<U>&& rhs) { // NOLINT
456  if (rhs) {
457  this->construct(std::move(*rhs));
458  }
459  }
460 
461  // Converting move constructor (explicit)
462  template <
463  typename U,
464  typename std::enable_if<
465  std::is_constructible<T, U&&>::value &&
467  T, U>::value &&
468  !std::is_convertible<U&&, T>::value,
469  bool>::type = false>
470  explicit optional(optional<U>&& rhs) {
471  if (rhs) {
472  this->construct(std::move(*rhs));
473  }
474  }
475 
476  // [optional.dtor], destructor, trivial if T is trivially destructible.
477  ~optional() = default;
478 
479  // [optional.assign], assignment
480 
481  // Assignment from nullopt: opt = nullopt
482  optional& operator=(nullopt_t) noexcept {
483  this->destruct();
484  return *this;
485  }
486 
487  // Copy assigment, standard semantics.
488  optional& operator=(const optional& src) = default;
489 
490  // Move assignment, standard semantics.
491  optional& operator=(optional&& src) = default;
492 
493  // Value assignment
494  template <
495  typename U = T,
496  typename = typename std::enable_if<
497  !std::is_same<optional<T>, typename std::decay<U>::type>::value &&
498  (!std::is_scalar<T>::value ||
499  !std::is_same<T, typename std::decay<U>::type>::value) &&
500  std::is_constructible<T, U>::value &&
501  std::is_assignable<T&, U>::value>::type>
502  optional& operator=(U&& v) {
503  this->assign(std::forward<U>(v));
504  return *this;
505  }
506 
507  template <typename U,
508  typename = typename std::enable_if<
509  std::is_constructible<T, const U&>::value &&
510  std::is_assignable<T&, const U&>::value &&
511  !internal_optional::
512  is_constructible_convertible_assignable_from_optional<
513  T, U>::value>::type>
514  optional& operator=(const optional<U>& rhs) {
515  if (rhs) {
516  this->assign(*rhs);
517  } else {
518  this->destruct();
519  }
520  return *this;
521  }
522 
523  template <typename U,
524  typename = typename std::enable_if<
525  std::is_constructible<T, U>::value &&
526  std::is_assignable<T&, U>::value &&
527  !internal_optional::
528  is_constructible_convertible_assignable_from_optional<
529  T, U>::value>::type>
530  optional& operator=(optional<U>&& rhs) {
531  if (rhs) {
532  this->assign(std::move(*rhs));
533  } else {
534  this->destruct();
535  }
536  return *this;
537  }
538 
539  // [optional.mod], modifiers
540  // Destroys the inner T value if one is present.
541  void reset() noexcept { this->destruct(); }
542 
543  // Emplace reconstruction. (Re)constructs the underlying T in-place with the
544  // given arguments forwarded:
545  //
546  // optional<Foo> opt;
547  // opt.emplace(arg1,arg2,arg3); (Constructs Foo(arg1,arg2,arg3))
548  //
549  // If the optional is non-empty, and the `args` refer to subobjects of the
550  // current object, then behaviour is undefined. This is because the current
551  // object will be destructed before the new object is constructed with `args`.
552  //
553  template <typename... Args,
554  typename = typename std::enable_if<
555  std::is_constructible<T, Args&&...>::value>::type>
556  void emplace(Args&&... args) {
557  this->destruct();
558  this->construct(std::forward<Args>(args)...);
559  }
560 
561  // Emplace reconstruction with initializer-list. See immediately above.
562  template <class U, class... Args,
563  typename = typename std::enable_if<std::is_constructible<
564  T, std::initializer_list<U>&, Args&&...>::value>::type>
565  void emplace(std::initializer_list<U> il, Args&&... args) {
566  this->destruct();
567  this->construct(il, std::forward<Args>(args)...);
568  }
569 
570  // [optional.swap], swap
571  // Swap, standard semantics.
572  void swap(optional& rhs) noexcept(
573  std::is_nothrow_move_constructible<T>::value&&
574  std::is_trivial<T>::value) {
575  if (*this) {
576  if (rhs) {
577  using std::swap;
578  swap(**this, *rhs);
579  } else {
580  rhs.construct(std::move(**this));
581  this->destruct();
582  }
583  } else {
584  if (rhs) {
585  this->construct(std::move(*rhs));
586  rhs.destruct();
587  } else {
588  // no effect (swap(disengaged, disengaged))
589  }
590  }
591  }
592 
593  // [optional.observe], observers
594  // You may use `*opt`, and `opt->m`, to access the underlying T value and T's
595  // member `m`, respectively. If the optional is empty, behaviour is
596  // undefined.
597  constexpr const T* operator->() const { return this->pointer(); }
598  T* operator->() {
599  assert(this->engaged_);
600  return this->pointer();
601  }
602  constexpr const T& operator*() const & { return reference(); }
603  T& operator*() & {
604  assert(this->engaged_);
605  return reference();
606  }
607  constexpr const T&& operator*() const && { return std::move(reference()); }
608  T&& operator*() && {
609  assert(this->engaged_);
610  return std::move(reference());
611  }
612 
613  // In a bool context an optional<T> will return false if and only if it is
614  // empty.
615  //
616  // if (opt) {
617  // // do something with opt.value();
618  // } else {
619  // // opt is empty
620  // }
621  //
622  constexpr explicit operator bool() const noexcept { return this->engaged_; }
623 
624  // Returns false if and only if *this is empty.
625  constexpr bool has_value() const noexcept { return this->engaged_; }
626 
627  // Use `opt.value()` to get a reference to underlying value. The constness
628  // and lvalue/rvalue-ness of `opt` is preserved to the view of the T
629  // subobject.
630  const T& value() const & {
631  if (!*this)
632  throw bad_optional_access();
633  return reference();
634  }
635  T& value() & {
636  if (!*this)
637  throw bad_optional_access();
638  return reference();
639  }
640  T&& value() && { // NOLINT(build/c++11)
641  if (!*this)
642  throw bad_optional_access();
643  return std::move(reference());
644  }
645  const T&& value() const && { // NOLINT(build/c++11)
646  if (!*this)
647  throw bad_optional_access();
648  return std::move(reference());
649  }
650 
651  // Use `opt.value_or(val)` to get either the value of T or the given default
652  // `val` in the empty case.
653  template <class U>
654  constexpr T value_or(U&& v) const & {
655  return static_cast<bool>(*this) ? **this
656  : static_cast<T>(std::forward<U>(v));
657  }
658  template <class U>
659  T value_or(U&& v) && { // NOLINT(build/c++11)
660  return static_cast<bool>(*this) ? std::move(**this)
661  : static_cast<T>(std::forward<U>(v));
662  }
663 
664  private:
665  // Private accessors for internal storage viewed as reference to T.
666  constexpr const T& reference() const { return *this->pointer(); }
667  T& reference() { return *(this->pointer()); }
668 
669  // T constaint checks. You can't have an optional of nullopt_t, in_place_t or
670  // a reference.
671  static_assert(
672  !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
673  "optional<nullopt_t> is not allowed.");
674  static_assert(
675  !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
676  "optional<in_place_t> is not allowed.");
677  static_assert(!std::is_reference<T>::value,
678  "optional<reference> is not allowed.");
679 };
680 
681 // [optional.specalg]
682 // Swap, standard semantics.
683 // This function shall not participate in overload resolution unless
684 // is_move_constructible_v<T> is true and is_swappable_v<T> is true.
685 // NOTE: we assume is_swappable is always true. There will be a compiling error
686 // if T is actually not Swappable.
687 template <typename T,
688  typename std::enable_if<std::is_move_constructible<T>::value,
689  bool>::type = false>
690 void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
691  a.swap(b);
692 }
693 
694 // NOTE: make_optional cannot be constexpr in C++11 because the copy/move
695 // constructor is not constexpr and we don't have guaranteed copy elision
696 // util C++17. But they are still declared constexpr for consistency with
697 // the standard.
698 
699 // make_optional(v) creates a non-empty optional<T> where the type T is deduced
700 // from v. Can also be explicitly instantiated as make_optional<T>(v).
701 template <typename T>
702 constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
703  return optional<typename std::decay<T>::type>(std::forward<T>(v));
704 }
705 
706 template <typename T, typename... Args>
707 constexpr optional<T> make_optional(Args&&... args) {
708  return optional<T>(in_place_t(), internal_optional::forward<Args>(args)...);
709 }
710 
711 template <typename T, typename U, typename... Args>
712 constexpr optional<T> make_optional(std::initializer_list<U> il,
713  Args&&... args) {
714  return optional<T>(in_place_t(), il,
715  internal_optional::forward<Args>(args)...);
716 }
717 
718 // Relational operators. Empty optionals are considered equal to each
719 // other and less than non-empty optionals. Supports relations between
720 // optional<T> and optional<T>, between optional<T> and T, and between
721 // optional<T> and nullopt.
722 // Note: We're careful to support T having non-bool relationals.
723 
724 // Relational operators [optional.relops]
725 // The C++17 (N4606) "Returns:" statements are translated into code
726 // in an obvious way here, and the original text retained as function docs.
727 // Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
728 // otherwise *x == *y.
729 template <class T>
730 constexpr bool operator==(const optional<T>& x, const optional<T>& y) {
731  return static_cast<bool>(x) != static_cast<bool>(y)
732  ? false
733  : static_cast<bool>(x) == false ? true : *x == *y;
734 }
735 // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
736 // otherwise *x != *y.
737 template <class T>
738 constexpr bool operator!=(const optional<T>& x, const optional<T>& y) {
739  return static_cast<bool>(x) != static_cast<bool>(y)
740  ? true
741  : static_cast<bool>(x) == false ? false : *x != *y;
742 }
743 // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
744 template <class T>
745 constexpr bool operator<(const optional<T>& x, const optional<T>& y) {
746  return !y ? false : !x ? true : *x < *y;
747 }
748 // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
749 template <class T>
750 constexpr bool operator>(const optional<T>& x, const optional<T>& y) {
751  return !x ? false : !y ? true : *x > *y;
752 }
753 // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
754 template <class T>
755 constexpr bool operator<=(const optional<T>& x, const optional<T>& y) {
756  return !x ? true : !y ? false : *x <= *y;
757 }
758 // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
759 template <class T>
760 constexpr bool operator>=(const optional<T>& x, const optional<T>& y) {
761  return !y ? true : !x ? false : *x >= *y;
762 }
763 
764 // Comparison with nullopt [optional.nullops]
765 // The C++17 (N4606) "Returns:" statements are used directly here.
766 template <class T>
767 constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
768  return !x;
769 }
770 template <class T>
771 constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
772  return !x;
773 }
774 template <class T>
775 constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
776  return static_cast<bool>(x);
777 }
778 template <class T>
779 constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
780  return static_cast<bool>(x);
781 }
782 template <class T>
783 constexpr bool operator<(const optional<T>& x ATTRIBUTE_UNUSED, nullopt_t) noexcept {
784  return false;
785 }
786 template <class T>
787 constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
788  return static_cast<bool>(x);
789 }
790 template <class T>
791 constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
792  return !x;
793 }
794 template <class T>
795 constexpr bool operator<=(nullopt_t, const optional<T>& x ATTRIBUTE_UNUSED) noexcept {
796  return true;
797 }
798 template <class T>
799 constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
800  return static_cast<bool>(x);
801 }
802 template <class T>
803 constexpr bool operator>(nullopt_t, const optional<T>& x ATTRIBUTE_UNUSED) noexcept {
804  return false;
805 }
806 template <class T>
807 constexpr bool operator>=(const optional<T>& x ATTRIBUTE_UNUSED, nullopt_t) noexcept {
808  return true;
809 }
810 template <class T>
811 constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
812  return !x;
813 }
814 
815 // Comparison with T [optional.comp_with_t]
816 // The C++17 (N4606) "Equivalent to:" statements are used directly here.
817 template <class T>
818 constexpr bool operator==(const optional<T>& x, const T& v) {
819  return static_cast<bool>(x) ? *x == v : false;
820 }
821 template <class T>
822 constexpr bool operator==(const T& v, const optional<T>& x) {
823  return static_cast<bool>(x) ? v == *x : false;
824 }
825 template <class T>
826 constexpr bool operator!=(const optional<T>& x, const T& v) {
827  return static_cast<bool>(x) ? *x != v : true;
828 }
829 template <class T>
830 constexpr bool operator!=(const T& v, const optional<T>& x) {
831  return static_cast<bool>(x) ? v != *x : true;
832 }
833 template <class T>
834 constexpr bool operator<(const optional<T>& x, const T& v) {
835  return static_cast<bool>(x) ? *x < v : true;
836 }
837 template <class T>
838 constexpr bool operator<(const T& v, const optional<T>& x) {
839  return static_cast<bool>(x) ? v < *x : false;
840 }
841 template <class T>
842 constexpr bool operator<=(const optional<T>& x, const T& v) {
843  return static_cast<bool>(x) ? *x <= v : true;
844 }
845 template <class T>
846 constexpr bool operator<=(const T& v, const optional<T>& x) {
847  return static_cast<bool>(x) ? v <= *x : false;
848 }
849 template <class T>
850 constexpr bool operator>(const optional<T>& x, const T& v) {
851  return static_cast<bool>(x) ? *x > v : false;
852 }
853 template <class T>
854 constexpr bool operator>(const T& v, const optional<T>& x) {
855  return static_cast<bool>(x) ? v > *x : true;
856 }
857 template <class T>
858 constexpr bool operator>=(const optional<T>& x, const T& v) {
859  return static_cast<bool>(x) ? *x >= v : false;
860 }
861 template <class T>
862 constexpr bool operator>=(const T& v, const optional<T>& x) {
863  return static_cast<bool>(x) ? v >= *x : true;
864 }
865 
866 } // namespace gtl
867 } // namespace momemta
868 
869 namespace std {
870 
871 template <class T>
872 struct hash<::momemta::gtl::optional<T>> {
873  size_t operator()(const ::momemta::gtl::optional<T>& opt) const {
874  if (opt) {
875  return hash<T>()(*opt);
876  } else {
877  return static_cast<size_t>(0x297814aaad196e6dULL);
878  }
879  }
880 };
881 
882 } // namespace std
Definition: optional.h:869
Definition: Graph.h:21