// Copyright (C) 2011 - 2012 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // The idea and interface is based on Boost.Optional library // authored by Fernando Luis Cacciola Carballal // // From https://github.com/akrzemi1/Optional // // C10 // - Move file to `c10` namespace. // - Remove macro use in line 478 because the nvcc device compiler cannot handle // it it. // - Revise constructor logic so that it is 1) consistent with c++ 17 standard // documented here in (8): // https://en.cppreference.com/w/cpp/utility/optional/optional, and 2) able to // support initialization of optionals from convertible type U. // - Remove the constructors for `optional(const T&)` and `optional(T&&)`, as // they can be handled by the template case with the default template // argument. // - Move `constexpr struct in_place_t {} in_place{}` to `c10/util/in_place.h` // so that it can also be used in `c10/util/variant.h`. // - Remove special cases for pre-c++14 compilers to make code simpler. #ifndef C10_UTIL_OPTIONAL_H_ #define C10_UTIL_OPTIONAL_H_ #include #include #include #include #include #include #include #include #include #include #include C10_CLANG_DIAGNOSTIC_PUSH() #if C10_CLANG_HAS_WARNING("-Wstring-conversion") C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion") #endif #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32") C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32") #endif #if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion") C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion") #endif #if C10_CLANG_HAS_WARNING("-Wimplicit-int-conversion") C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-conversion") #endif #define TR2_OPTIONAL_REQUIRES(...) \ typename std::enable_if<__VA_ARGS__::value, bool>::type = false namespace c10 { // 20.5.4, optional for object types template class optional; // 20.5.5, optional for lvalue reference types template class optional; // workaround: std utility functions aren't constexpr yet template inline constexpr T&& constexpr_forward( typename std::remove_reference::type& t) noexcept { return static_cast(t); } template inline constexpr T&& constexpr_forward( typename std::remove_reference::type&& t) noexcept { static_assert(!std::is_lvalue_reference::value, "!!"); return static_cast(t); } template inline constexpr typename std::remove_reference::type&& constexpr_move( T&& t) noexcept { return static_cast::type&&>(t); } #if defined NDEBUG #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) #else #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) \ ((CHECK) ? (EXPR) : ([] { assert(!#CHECK); }(), (EXPR))) #endif #if defined(__CUDA_ARCH__) #define TR2_OPTIONAL_HOST_CONSTEXPR #else #define TR2_OPTIONAL_HOST_CONSTEXPR constexpr #endif // Sphinx chokes on static_addressof, so exclude it from Doxygen // generation. See https://github.com/sphinx-doc/sphinx/issues/7944 // \cond namespace detail_ { // VS doesn't handle constexpr well, so we need to skip these stuff. #if (defined _MSC_VER) template T* static_addressof(T& ref) { return std::addressof(ref); } #else // static_addressof: a constexpr version of addressof template struct has_overloaded_addressof { template constexpr static bool has_overload(...) { return false; } template ().operator&())> constexpr static bool has_overload(bool) { return true; } constexpr static bool value = has_overload(true); }; template )> constexpr T* static_addressof(T& ref) { return &ref; } template )> T* static_addressof(T& ref) { return std::addressof(ref); } #endif // the call to convert(b) has return type A and converts b to type A iff b // decltype(b) is implicitly convertible to A template constexpr U convert(U v) { return v; } } // namespace detail_ // \endcond constexpr struct trivial_init_t { } trivial_init{}; // 20.5.7, Disengaged state indicator struct nullopt_t { constexpr explicit nullopt_t(int) {} }; constexpr nullopt_t nullopt{0}; // 20.5.8, class bad_optional_access class bad_optional_access : public std::logic_error { public: explicit bad_optional_access(const std::string& what_arg) : logic_error{what_arg} {} explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} }; template union storage_t { unsigned char dummy_; T value_; constexpr storage_t(trivial_init_t) noexcept : dummy_(){}; template constexpr storage_t(Args&&... args) : value_(constexpr_forward(args)...) {} ~storage_t() {} }; template union constexpr_storage_t { unsigned char dummy_; T value_; constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_(){}; template constexpr constexpr_storage_t(Args&&... args) : value_(constexpr_forward(args)...) {} ~constexpr_storage_t() = default; }; template struct optional_base { bool init_; storage_t storage_; constexpr optional_base() noexcept : init_(false), storage_(trivial_init){}; explicit constexpr optional_base(const optional_base& v) : init_(v.init_), storage_(trivial_init) { if (init_) { ::new (dataptr()) T(v.storage_.value_); } } explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} explicit constexpr optional_base(optional_base&& v) noexcept( std::is_nothrow_move_constructible::value) : init_(v.init_), storage_(trivial_init) { if (init_) { ::new (dataptr()) T(std::move(v.storage_.value_)); } } explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} template explicit optional_base(in_place_t, Args&&... args) : init_(true), storage_(constexpr_forward(args)...) {} template < class U, class... Args, TR2_OPTIONAL_REQUIRES(std::is_constructible>)> explicit optional_base( in_place_t, std::initializer_list il, Args&&... args) : init_(true), storage_(il, std::forward(args)...) {} optional_base& operator=(const optional_base& rhs) { if (init_ && !rhs.init_) { clear(); } else if (!init_ && rhs.init_) { init_ = true; ::new (dataptr()) T(rhs.storage_.value_); } else if (init_ && rhs.init_) { storage_.value_ = rhs.storage_.value_; } return *this; } optional_base& operator=(optional_base&& rhs) noexcept( std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) { if (init_ && !rhs.init_) { clear(); } else if (!init_ && rhs.init_) { init_ = true; ::new (dataptr()) T(std::move(rhs.storage_.value_)); } else if (init_ && rhs.init_) { storage_.value_ = std::move(rhs.storage_.value_); } return *this; } ~optional_base() { if (init_) storage_.value_.T::~T(); } constexpr bool initialized() const noexcept { return init_; } void setInitialized(bool init) noexcept { init_ = init; } private: typename std::remove_const::type* dataptr() { return std::addressof(storage_.value_); } constexpr const T* dataptr() const { return detail_::static_addressof(storage_.value_); } void clear() noexcept { if (init_) { dataptr()->~T(); } init_ = false; } }; template struct constexpr_optional_base { bool init_; constexpr_storage_t storage_; constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init){}; explicit constexpr constexpr_optional_base( const constexpr_optional_base& v) : init_(v.init_), storage_(trivial_init) { if (init_) { ::new (dataptr()) T(v.storage_.value_); } } explicit constexpr constexpr_optional_base( constexpr_optional_base&& v) noexcept(std::is_nothrow_move_constructible::value) : init_(v.init_), storage_(trivial_init) { if (init_) { ::new (dataptr()) T(std::move(v.storage_.value_)); } } explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) : init_(true), storage_(constexpr_forward(args)...) {} template < class U, class... Args, TR2_OPTIONAL_REQUIRES(std::is_constructible>)> constexpr explicit constexpr_optional_base( in_place_t, std::initializer_list il, Args&&... args) : init_(true), storage_(il, std::forward(args)...) {} ~constexpr_optional_base() = default; constexpr_optional_base& operator=(const constexpr_optional_base& rhs) { if (init_ && !rhs.init_) { clear(); } else if (!init_ && rhs.init_) { init_ = true; ::new (dataptr()) T(rhs.storage_.value_); } else if (init_ && rhs.init_) { storage_.value_ = rhs.storage_.value_; } return *this; } constexpr_optional_base& operator=(constexpr_optional_base&& rhs) noexcept( std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) { if (init_ && !rhs.init_) { clear(); } else if (!init_ && rhs.init_) { init_ = true; ::new (dataptr()) T(std::move(rhs.storage_.value_)); } else if (init_ && rhs.init_) { storage_.value_ = std::move(rhs.storage_.value_); } return *this; } constexpr bool initialized() const noexcept { return init_; } void setInitialized(bool init) noexcept { init_ = init; } private: typename std::remove_const::type* dataptr() { return std::addressof(storage_.value_); } constexpr const T* dataptr() const { return detail_::static_addressof(storage_.value_); } void clear() noexcept { init_ = false; } }; // HACK: Optimization for trivially copyable types. The mainline // implementation fails to have trivial copy/move operations in these // cases, and we care about them, so just implement that directly. template struct trivially_copyable_optimization_optional_base { bool init_; constexpr_storage_t storage_; constexpr trivially_copyable_optimization_optional_base() noexcept : init_(false), storage_(trivial_init) {} explicit constexpr trivially_copyable_optimization_optional_base(const T& v) : init_(true), storage_(v) {} explicit constexpr trivially_copyable_optimization_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} template explicit constexpr trivially_copyable_optimization_optional_base( in_place_t, Args&&... args) : init_(true), storage_(constexpr_forward(args)...) {} template < class U, class... Args, TR2_OPTIONAL_REQUIRES(std::is_constructible>)> constexpr explicit trivially_copyable_optimization_optional_base( in_place_t, std::initializer_list il, Args&&... args) : init_(true), storage_(il, std::forward(args)...) {} ~trivially_copyable_optimization_optional_base() = default; constexpr bool initialized() const noexcept { return init_; } void setInitialized(bool init) noexcept { init_ = init; } }; // HACK: Optimization for ArrayRef. We take advantage of an unused // bit pattern in ArrayRef (inspired by Arthur O'Dwyer's // tombstone_traits -- see https://youtu.be/MWBfmmg8-Yo?t=2466) to // keep the size of c10::optional::ArrayRef down to 16 bytes, which // allows it to be passed to functions in registers instead of getting // passed in memory per item 5c of the classification algorithm in // section 3.2.3 of the System V ABI document // (https://www.uclibc.org/docs/psABI-x86_64.pdf). template class arrayref_optional_base { public: union storage { struct raw { // ArrayRef has the invariant that if Data is nullptr then // Length must be zero, so this is an unused bit pattern. const void* p = nullptr; size_t sz = 1; } uninitialized_{}; ArrayRefT value_; constexpr storage() noexcept : uninitialized_() { setUninitialized(); } constexpr void setUninitialized() noexcept { uninitialized_.p = nullptr; uninitialized_.sz = 1; } explicit constexpr storage(ArrayRefT& v) : value_(v) {} template explicit constexpr storage(const std::initializer_list& v) : value_(v) {} template explicit constexpr storage(Args&&... args) : value_(constexpr_forward(args)...) {} }; storage storage_; constexpr arrayref_optional_base() noexcept = default; explicit constexpr arrayref_optional_base(const ArrayRefT& v) : storage_(v) {} template explicit constexpr arrayref_optional_base(in_place_t, Args&&... args) : storage_(constexpr_forward(args)...) {} template explicit constexpr arrayref_optional_base( in_place_t, const std::initializer_list& v) : storage_(v) {} constexpr bool initialized() const noexcept { typename storage::raw repr; // Cast to void* to suppress GCC's -Wclass-memaccess. memcpy( static_cast(&repr), static_cast(&storage_), sizeof(storage_)); return repr.p != nullptr || repr.sz == 0; } void setInitialized(bool init) noexcept { if (!init) { storage_.setUninitialized(); } else { assert(initialized()); } } }; namespace detail_ { template struct is_arrayref : std::false_type {}; template struct is_arrayref> : std::true_type {}; } // namespace detail_ template using OptionalBase = std::conditional_t< detail_::is_arrayref::value, arrayref_optional_base, std::conditional_t< std::is_trivially_destructible::value && C10_IS_TRIVIALLY_COPYABLE(T) && // Avoid using is_trivially_copy_{constructible,assignable} // because old GCC versions don't support them. Also, // is_trivially_copyable seems not to do what I expect, so check // trivially_copyable_optimization_optional_base directly. std::is_copy_constructible< trivially_copyable_optimization_optional_base>::value && std::is_copy_assignable< trivially_copyable_optimization_optional_base>::value, trivially_copyable_optimization_optional_base, std::conditional_t< std::is_trivially_destructible::value, // if possible constexpr_optional_base>, // use base with // trivial // destructor optional_base>>>>; template class optional : private OptionalBase { template // re-declaration for nvcc on Windows. using OptionalBase = std::conditional_t< detail_::is_arrayref::value, arrayref_optional_base, std::conditional_t< std::is_trivially_destructible::value && C10_IS_TRIVIALLY_COPYABLE(U) && // Avoid using is_trivially_copy_{constructible,assignable} // because old GCC versions don't support them. Also, // is_trivially_copyable seems not to do what I expect, so // check trivially_copyable_optimization_optional_base // directly. std::is_copy_constructible< trivially_copyable_optimization_optional_base>::value && std::is_copy_assignable< trivially_copyable_optimization_optional_base>::value, trivially_copyable_optimization_optional_base, std::conditional_t< std::is_trivially_destructible::value, // if possible constexpr_optional_base>, // use base // with // trivial // destructor optional_base>>>>; static_assert( !std::is_same::type, nullopt_t>::value, "bad T"); static_assert( !std::is_same::type, in_place_t>::value, "bad T"); constexpr bool initialized() const noexcept { return OptionalBase::initialized(); } typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } constexpr T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } constexpr T& contained_val() & { return OptionalBase::storage_.value_; } void clear() noexcept { if (initialized()) dataptr()->~T(); OptionalBase::setInitialized(false); } template void initialize(Args&&... args) noexcept( noexcept(T(std::forward(args)...))) { assert(!initialized()); ::new (static_cast(dataptr())) T(std::forward(args)...); OptionalBase::setInitialized(true); } template void initialize(std::initializer_list il, Args&&... args) noexcept( noexcept(T(il, std::forward(args)...))) { assert(!initialized()); ::new (static_cast(dataptr())) T(il, std::forward(args)...); OptionalBase::setInitialized(true); } public: typedef T value_type; // 20.5.5.1, constructors constexpr optional() noexcept : OptionalBase(){}; constexpr optional(nullopt_t) noexcept : OptionalBase(){}; optional(const optional& rhs) = default; optional(optional&& rhs) = default; // see https://github.com/akrzemi1/Optional/issues/16 // and https://en.cppreference.com/w/cpp/utility/optional/optional, // in constructor 8, the std::optional spec can allow initialization // of optionals from convertible type U // // 8 - implicit move construct from value template < typename U = T, TR2_OPTIONAL_REQUIRES( std::is_constructible::value && !std::is_same::type, in_place_t>::value && !std::is_same::type, optional>::value && std::is_convertible)> constexpr optional(U&& u) : OptionalBase(std::forward(u)) {} // 8 - explicit move construct from value template < typename U = T, TR2_OPTIONAL_REQUIRES( std::is_constructible::value && !std::is_same::type, in_place_t>::value && !std::is_same::type, optional>::value && !std::is_convertible)> explicit constexpr optional(U&& u) : OptionalBase(std::forward(u)) {} template explicit constexpr optional(in_place_t, Args&&... args) : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} template < class U, class... Args, TR2_OPTIONAL_REQUIRES(std::is_constructible>)> constexpr explicit optional( in_place_t, std::initializer_list il, Args&&... args) : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} // 20.5.4.2, Destructor ~optional() = default; // 20.5.4.3, assignment optional& operator=(nullopt_t) noexcept { clear(); return *this; } optional& operator=(const optional& rhs) = default; optional& operator=(optional&& rhs) = default; template auto operator=(U&& v) -> typename std::enable_if< std::is_constructible::value && !std::is_same::type, optional>::value && (std::is_scalar::value || std::is_same::type, T>::value) && std::is_assignable::value, optional&>::type { if (initialized()) { contained_val() = std::forward(v); } else { initialize(std::forward(v)); } return *this; } template void emplace(Args&&... args) { clear(); initialize(std::forward(args)...); } template void emplace(std::initializer_list il, Args&&... args) { clear(); initialize(il, std::forward(args)...); } // 20.5.4.4, Swap void swap(optional& rhs) noexcept( std::is_nothrow_move_constructible::value&& noexcept( std::swap(std::declval(), std::declval()))) { if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } } // 20.5.4.5, Observers explicit constexpr operator bool() const noexcept { return initialized(); } constexpr bool has_value() const noexcept { return initialized(); } TR2_OPTIONAL_HOST_CONSTEXPR T const* operator->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); } TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() { assert(initialized()); return dataptr(); } TR2_OPTIONAL_HOST_CONSTEXPR T const& operator*() const& { return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); } TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() & { assert(initialized()); return contained_val(); } TR2_OPTIONAL_HOST_CONSTEXPR T&& operator*() && { assert(initialized()); return constexpr_move(contained_val()); } TR2_OPTIONAL_HOST_CONSTEXPR T const& value() const& { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } TR2_OPTIONAL_HOST_CONSTEXPR T& value() & { return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); } TR2_OPTIONAL_HOST_CONSTEXPR T&& value() && { if (!initialized()) throw bad_optional_access("bad optional access"); return std::move(contained_val()); } template constexpr T value_or(V&& v) const& { return *this ? **this : detail_::convert(constexpr_forward(v)); } template constexpr T value_or(V&& v) && { return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); } // 20.6.3.6, modifiers void reset() noexcept { clear(); } }; template constexpr T value_or_else(const optional& v, F&& func) { static_assert( std::is_convertible< typename guts::infer_function_traits_t::return_type, T>::value, "func parameters must be a callable that returns a type convertible to the value stored in the optional"); return v.has_value() ? *v : detail_::convert(std::forward(func)()); } template constexpr T value_or_else(optional&& v, F&& func) { static_assert( std::is_convertible< typename guts::infer_function_traits_t::return_type, T>::value, "func parameters must be a callable that returns a type convertible to the value stored in the optional"); return v.has_value() ? constexpr_move(std::move(v).contained_val()) : detail_::convert(std::forward(func)()); } // XXX: please refrain from using optional, since it is being against with // the optional standard in c++ 17, see the debate and the details here: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3406#rationale.refs // if you need it, consider using optional> or * // pointer // // we leave the implementation here in case we want to reconsider using it in // the future if it becomes a definitely necessary case. template class optional { // add this assert to prevent user from using optional reference as indicated // above static_assert( sizeof(T) == 0, "optional references is ill-formed, \ consider use optional of a std::reference_wrapper of type T to \ hold a reference if you really need to"); static_assert(!std::is_same::value, "bad T"); static_assert(!std::is_same::value, "bad T"); T* ref; public: // 20.5.5.1, construction/destruction constexpr optional() noexcept : ref(nullptr) {} constexpr optional(nullopt_t) noexcept : ref(nullptr) {} template constexpr optional(U& u) noexcept : ref(detail_::static_addressof(u)) {} template optional(U&&) = delete; constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} explicit optional(in_place_t, T&&) = delete; ~optional() = default; // 20.5.5.2, mutation optional& operator=(nullopt_t) noexcept { ref = nullptr; return *this; } // optional& operator=(const optional& rhs) noexcept { // ref = rhs.ref; // return *this; // } // optional& operator=(optional&& rhs) noexcept { // ref = rhs.ref; // return *this; // } template auto operator=(U&& rhs) noexcept -> typename std::enable_if< std::is_same::type, optional>::value, optional&>::type { ref = rhs.ref; return *this; } template auto operator=(U&& rhs) noexcept -> typename std::enable_if< !std::is_same::type, optional>::value, optional&>::type = delete; void emplace(T& v) noexcept { ref = detail_::static_addressof(v); } void emplace(T&&) = delete; void swap(optional& rhs) noexcept { std::swap(ref, rhs.ref); } // 20.5.5.3, observers TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); } TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() const { return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); } constexpr T& value() const { return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); } explicit constexpr operator bool() const noexcept { return ref != nullptr; } constexpr bool has_value() const noexcept { return ref != nullptr; } template constexpr typename std::decay::type value_or(V&& v) const { return *this ? **this : detail_::convert::type>( constexpr_forward(v)); } // x.x.x.x, modifiers void reset() noexcept { ref = nullptr; } }; template class optional { static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); }; // 20.5.8, Relational operators template constexpr bool operator==(const optional& x, const optional& y) { return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; } template constexpr bool operator!=(const optional& x, const optional& y) { return !(x == y); } template constexpr bool operator<(const optional& x, const optional& y) { return (!y) ? false : (!x) ? true : *x < *y; } template constexpr bool operator>(const optional& x, const optional& y) { return (y < x); } template constexpr bool operator<=(const optional& x, const optional& y) { return !(y < x); } template constexpr bool operator>=(const optional& x, const optional& y) { return !(x < y); } // 20.5.9, Comparison with nullopt template constexpr bool operator==(const optional& x, nullopt_t) noexcept { return (!x); } template constexpr bool operator==(nullopt_t, const optional& x) noexcept { return (!x); } template constexpr bool operator!=(const optional& x, nullopt_t) noexcept { return bool(x); } template constexpr bool operator!=(nullopt_t, const optional& x) noexcept { return bool(x); } template constexpr bool operator<(const optional&, nullopt_t) noexcept { return false; } template constexpr bool operator<(nullopt_t, const optional& x) noexcept { return bool(x); } template constexpr bool operator<=(const optional& x, nullopt_t) noexcept { return (!x); } template constexpr bool operator<=(nullopt_t, const optional&) noexcept { return true; } template constexpr bool operator>(const optional& x, nullopt_t) noexcept { return bool(x); } template constexpr bool operator>(nullopt_t, const optional&) noexcept { return false; } template constexpr bool operator>=(const optional&, nullopt_t) noexcept { return true; } template constexpr bool operator>=(nullopt_t, const optional& x) noexcept { return (!x); } // 20.5.10, Comparison with T template constexpr bool operator==(const optional& x, const U& v) { return bool(x) ? *x == v : false; } template constexpr bool operator==(const U& v, const optional& x) { return bool(x) ? v == *x : false; } template constexpr bool operator!=(const optional& x, const U& v) { return bool(x) ? *x != v : true; } template constexpr bool operator!=(const U& v, const optional& x) { return bool(x) ? v != *x : true; } template constexpr bool operator<(const optional& x, const U& v) { return bool(x) ? *x < v : true; } template constexpr bool operator>(const U& v, const optional& x) { return bool(x) ? v > *x : true; } template constexpr bool operator>(const optional& x, const U& v) { return bool(x) ? *x > v : false; } template constexpr bool operator<(const U& v, const optional& x) { return bool(x) ? v < *x : false; } template constexpr bool operator>=(const optional& x, const U& v) { return bool(x) ? *x >= v : false; } template constexpr bool operator<=(const U& v, const optional& x) { return bool(x) ? v <= *x : false; } template constexpr bool operator<=(const optional& x, const U& v) { return bool(x) ? *x <= v : true; } template constexpr bool operator>=(const U& v, const optional& x) { return bool(x) ? v >= *x : true; } // Comparison of optional with T template constexpr bool operator==(const optional& x, const T& v) { return bool(x) ? *x == v : false; } template constexpr bool operator==(const T& v, const optional& x) { return bool(x) ? v == *x : false; } template constexpr bool operator!=(const optional& x, const T& v) { return bool(x) ? *x != v : true; } template constexpr bool operator!=(const T& v, const optional& x) { return bool(x) ? v != *x : true; } template constexpr bool operator<(const optional& x, const T& v) { return bool(x) ? *x < v : true; } template constexpr bool operator>(const T& v, const optional& x) { return bool(x) ? v > *x : true; } template constexpr bool operator>(const optional& x, const T& v) { return bool(x) ? *x > v : false; } template constexpr bool operator<(const T& v, const optional& x) { return bool(x) ? v < *x : false; } template constexpr bool operator>=(const optional& x, const T& v) { return bool(x) ? *x >= v : false; } template constexpr bool operator<=(const T& v, const optional& x) { return bool(x) ? v <= *x : false; } template constexpr bool operator<=(const optional& x, const T& v) { return bool(x) ? *x <= v : true; } template constexpr bool operator>=(const T& v, const optional& x) { return bool(x) ? v >= *x : true; } // Comparison of optional with T template constexpr bool operator==(const optional& x, const T& v) { return bool(x) ? *x == v : false; } template constexpr bool operator==(const T& v, const optional& x) { return bool(x) ? v == *x : false; } template constexpr bool operator!=(const optional& x, const T& v) { return bool(x) ? *x != v : true; } template constexpr bool operator!=(const T& v, const optional& x) { return bool(x) ? v != *x : true; } template constexpr bool operator<(const optional& x, const T& v) { return bool(x) ? *x < v : true; } template constexpr bool operator>(const T& v, const optional& x) { return bool(x) ? v > *x : true; } template constexpr bool operator>(const optional& x, const T& v) { return bool(x) ? *x > v : false; } template constexpr bool operator<(const T& v, const optional& x) { return bool(x) ? v < *x : false; } template constexpr bool operator>=(const optional& x, const T& v) { return bool(x) ? *x >= v : false; } template constexpr bool operator<=(const T& v, const optional& x) { return bool(x) ? v <= *x : false; } template constexpr bool operator<=(const optional& x, const T& v) { return bool(x) ? *x <= v : true; } template constexpr bool operator>=(const T& v, const optional& x) { return bool(x) ? v >= *x : true; } // 20.5.12, Specialized algorithms template void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) { x.swap(y); } template constexpr optional::type> make_optional(T&& v) { return optional::type>(constexpr_forward(v)); } template constexpr optional make_optional(std::reference_wrapper v) { return optional(v.get()); } } // namespace c10 namespace std { template struct hash> { typedef typename hash::result_type result_type; typedef c10::optional argument_type; constexpr result_type operator()(argument_type const& arg) const { return arg ? std::hash{}(*arg) : result_type{}; } }; template struct hash> { typedef typename hash::result_type result_type; typedef c10::optional argument_type; constexpr result_type operator()(argument_type const& arg) const { return arg ? std::hash{}(*arg) : result_type{}; } }; } // namespace std #undef TR2_OPTIONAL_REQUIRES #undef TR2_OPTIONAL_ASSERTED_EXPRESSION #undef TR2_OPTIONAL_HOST_CONSTEXPR C10_CLANG_DIAGNOSTIC_POP() #endif // C10_UTIL_OPTIONAL_H_