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