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