// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // optional.h // ----------------------------------------------------------------------------- // // This header file defines the `absl::optional` type for holding a value which // may or may not be present. This type is useful for providing value semantics // for operations that may either wish to return or hold "something-or-nothing". // // Example: // // // A common way to signal operation failure is to provide an output // // parameter and a bool return type: // bool AcquireResource(const Input&, Resource * out); // // // Providing an absl::optional return type provides a cleaner API: // absl::optional AcquireResource(const Input&); // // `absl::optional` is a C++11 compatible version of the C++17 `std::optional` // abstraction and is designed to be a drop-in replacement for code compliant // with C++17. #ifndef ABSL_TYPES_OPTIONAL_H_ #define ABSL_TYPES_OPTIONAL_H_ #include "absl/base/config.h" // TODO(calabrese) IWYU removal? #include "absl/utility/utility.h" #ifdef ABSL_USES_STD_OPTIONAL #include // IWYU pragma: export namespace absl { ABSL_NAMESPACE_BEGIN using std::bad_optional_access; using std::optional; using std::make_optional; using std::nullopt_t; using std::nullopt; ABSL_NAMESPACE_END } // namespace absl #else // ABSL_USES_STD_OPTIONAL #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/base/internal/inline_variable.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_optional_access.h" #include "absl/types/internal/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN // nullopt_t // // Class type for `absl::nullopt` used to indicate an `absl::optional` type // that does not contain a value. struct nullopt_t { // It must not be default-constructible to avoid ambiguity for opt = {}. explicit constexpr nullopt_t(optional_internal::init_t) noexcept {} }; // nullopt // // A tag constant of type `absl::nullopt_t` used to indicate an empty // `absl::optional` in certain functions, such as construction or assignment. ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt, nullopt_t(optional_internal::init_t())); // ----------------------------------------------------------------------------- // absl::optional // ----------------------------------------------------------------------------- // // A value of type `absl::optional` holds either a value of `T` or an // "empty" value. When it holds a value of `T`, it stores it as a direct // sub-object, so `sizeof(optional)` is approximately // `sizeof(T) + sizeof(bool)`. // // This implementation is based on the specification in the latest draft of the // C++17 `std::optional` specification as of May 2017, section 20.6. // // Differences between `absl::optional` and `std::optional` include: // // * `constexpr` is not used for non-const member functions. // (dependency on some differences between C++11 and C++14.) // * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We // need the inline variable support in C++17 for external linkage. // * Throws `absl::bad_optional_access` instead of // `std::bad_optional_access`. // * `make_optional()` cannot be declared `constexpr` due to the absence of // guaranteed copy elision. // * The move constructor's `noexcept` specification is stronger, i.e. if the // default allocator is non-throwing (via setting // `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because // we assume // a) move constructors should only throw due to allocation failure and // b) if T's move constructor allocates, it uses the same allocation // function as the default allocator. // template class optional : private optional_internal::optional_data, private optional_internal::optional_ctor_base< optional_internal::ctor_copy_traits::traits>, private optional_internal::optional_assign_base< optional_internal::assign_copy_traits::traits> { using data_base = optional_internal::optional_data; public: typedef T value_type; // Constructors // Constructs an `optional` holding an empty value, NOT a default constructed // `T`. constexpr optional() noexcept = default; // Constructs an `optional` initialized with `nullopt` to hold an empty value. constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit) // Copy constructor, standard semantics optional(const optional&) = default; // Move constructor, standard semantics optional(optional&&) = default; // Constructs a non-empty `optional` direct-initialized value of type `T` from // the arguments `std::forward(args)...` within the `optional`. // (The `in_place_t` is a tag used to indicate that the contained object // should be constructed in-place.) template , std::is_constructible >::value>* = nullptr> constexpr explicit optional(InPlaceT, Args&&... args) : data_base(in_place_t(), std::forward(args)...) {} // Constructs a non-empty `optional` direct-initialized value of type `T` from // the arguments of an initializer_list and `std::forward(args)...`. // (The `in_place_t` is a tag used to indicate that the contained object // should be constructed in-place.) template &, Args&&...>::value>::type> constexpr explicit optional(in_place_t, std::initializer_list il, Args&&... args) : data_base(in_place_t(), il, std::forward(args)...) {} // Value constructor (implicit) template < typename U = T, typename std::enable_if< absl::conjunction::type> >, absl::negation, typename std::decay::type> >, std::is_convertible, std::is_constructible >::value, bool>::type = false> constexpr optional(U&& v) : data_base(in_place_t(), std::forward(v)) {} // Value constructor (explicit) template < typename U = T, typename std::enable_if< absl::conjunction::type> >, absl::negation, typename std::decay::type> >, absl::negation >, std::is_constructible >::value, bool>::type = false> explicit constexpr optional(U&& v) : data_base(in_place_t(), std::forward(v)) {} // Converting copy constructor (implicit) template >, std::is_constructible, absl::negation< optional_internal:: is_constructible_convertible_from_optional >, std::is_convertible >::value, bool>::type = false> optional(const optional& rhs) { if (rhs) { this->construct(*rhs); } } // Converting copy constructor (explicit) template >, std::is_constructible, absl::negation< optional_internal:: is_constructible_convertible_from_optional>, absl::negation>>::value, bool>::type = false> explicit optional(const optional& rhs) { if (rhs) { this->construct(*rhs); } } // Converting move constructor (implicit) template >, std::is_constructible, absl::negation< optional_internal:: is_constructible_convertible_from_optional >, std::is_convertible >::value, bool>::type = false> optional(optional&& rhs) { if (rhs) { this->construct(std::move(*rhs)); } } // Converting move constructor (explicit) template < typename U, typename std::enable_if< absl::conjunction< absl::negation>, std::is_constructible, absl::negation< optional_internal::is_constructible_convertible_from_optional< T, U>>, absl::negation>>::value, bool>::type = false> explicit optional(optional&& rhs) { if (rhs) { this->construct(std::move(*rhs)); } } // Destructor. Trivial if `T` is trivially destructible. ~optional() = default; // Assignment Operators // Assignment from `nullopt` // // Example: // // struct S { int value; }; // optional opt = absl::nullopt; // Could also use opt = { }; optional& operator=(nullopt_t) noexcept { this->destruct(); return *this; } // Copy assignment operator, standard semantics optional& operator=(const optional& src) = default; // Move assignment operator, standard semantics optional& operator=(optional&& src) = default; // Value assignment operators template , typename std::decay::type> >, absl::negation, std::is_same::type> > >, std::is_constructible, std::is_assignable >::value>::type> optional& operator=(U&& v) { this->assign(std::forward(v)); return *this; } template < typename U, int&..., // Workaround an internal compiler error in GCC 5 to 10. typename = typename std::enable_if >, std::is_constructible, std::is_assignable, absl::negation< optional_internal:: is_constructible_convertible_assignable_from_optional< T, U> > >::value>::type> optional& operator=(const optional& rhs) { if (rhs) { this->assign(*rhs); } else { this->destruct(); } return *this; } template >, std::is_constructible, std::is_assignable, absl::negation< optional_internal:: is_constructible_convertible_assignable_from_optional< T, U> > >::value>::type> optional& operator=(optional&& rhs) { if (rhs) { this->assign(std::move(*rhs)); } else { this->destruct(); } return *this; } // Modifiers // optional::reset() // // Destroys the inner `T` value of an `absl::optional` if one is present. ABSL_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); } // optional::emplace() // // (Re)constructs the underlying `T` in-place with the given forwarded // arguments. // // Example: // // optional opt; // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3) // // If the optional is non-empty, and the `args` refer to subobjects of the // current object, then behaviour is undefined, because the current object // will be destructed before the new object is constructed with `args`. template ::value>::type> T& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { this->destruct(); this->construct(std::forward(args)...); return reference(); } // Emplace reconstruction overload for an initializer list and the given // forwarded arguments. // // Example: // // struct Foo { // Foo(std::initializer_list); // }; // // optional opt; // opt.emplace({1,2,3}); // Constructs Foo({1,2,3}) template &, Args&&...>::value>::type> T& emplace(std::initializer_list il, Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { this->destruct(); this->construct(il, std::forward(args)...); return reference(); } // Swaps // Swap, standard semantics void swap(optional& rhs) noexcept( std::is_nothrow_move_constructible::value&& type_traits_internal::IsNothrowSwappable::value) { if (*this) { if (rhs) { type_traits_internal::Swap(**this, *rhs); } else { rhs.construct(std::move(**this)); this->destruct(); } } else { if (rhs) { this->construct(std::move(*rhs)); rhs.destruct(); } else { // No effect (swap(disengaged, disengaged)). } } } // Observers // optional::operator->() // // Accesses the underlying `T` value's member `m` of an `optional`. If the // `optional` is empty, behavior is undefined. // // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. absl::Nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return std::addressof(this->data_); } absl::Nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return std::addressof(this->data_); } // optional::operator*() // // Accesses the underlying `T` value of an `optional`. If the `optional` is // empty, behavior is undefined. constexpr const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND { return ABSL_HARDENING_ASSERT(this->engaged_), reference(); } T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return reference(); } constexpr const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND { return ABSL_HARDENING_ASSERT(this->engaged_), std::move(reference()); } T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND { ABSL_HARDENING_ASSERT(this->engaged_); return std::move(reference()); } // optional::operator bool() // // Returns false if and only if the `optional` is empty. // // if (opt) { // // do something with *opt or opt->; // } else { // // opt is empty. // } // constexpr explicit operator bool() const noexcept { return this->engaged_; } // optional::has_value() // // Determines whether the `optional` contains a value. Returns `false` if and // only if `*this` is empty. constexpr bool has_value() const noexcept { return this->engaged_; } // Suppress bogus warning on MSVC: MSVC complains call to reference() after // throw_bad_optional_access() is unreachable. #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4702) #endif // _MSC_VER // optional::value() // // Returns a reference to an `optional`s underlying value. The constness // and lvalue/rvalue-ness of the `optional` is preserved to the view of // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional` // is empty. constexpr const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND { return static_cast(*this) ? reference() : (optional_internal::throw_bad_optional_access(), reference()); } T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND { return static_cast(*this) ? reference() : (optional_internal::throw_bad_optional_access(), reference()); } T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11) return std::move( static_cast(*this) ? reference() : (optional_internal::throw_bad_optional_access(), reference())); } constexpr const T&& value() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11) return std::move( static_cast(*this) ? reference() : (optional_internal::throw_bad_optional_access(), reference())); } #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER // optional::value_or() // // Returns either the value of `T` or a passed default `v` if the `optional` // is empty. template constexpr T value_or(U&& v) const& { static_assert(std::is_copy_constructible::value, "optional::value_or: T must be copy constructible"); static_assert(std::is_convertible::value, "optional::value_or: U must be convertible to T"); return static_cast(*this) ? **this : static_cast(std::forward(v)); } template T value_or(U&& v) && { // NOLINT(build/c++11) static_assert(std::is_move_constructible::value, "optional::value_or: T must be move constructible"); static_assert(std::is_convertible::value, "optional::value_or: U must be convertible to T"); return static_cast(*this) ? std::move(**this) : static_cast(std::forward(v)); } private: // Private accessors for internal storage viewed as reference to T. constexpr const T& reference() const { return this->data_; } T& reference() { return this->data_; } // T constraint checks. You can't have an optional of nullopt_t, in_place_t // or a reference. static_assert( !std::is_same::type>::value, "optional is not allowed."); static_assert( !std::is_same::type>::value, "optional is not allowed."); static_assert(!std::is_reference::value, "optional is not allowed."); }; // Non-member functions // swap() // // Performs a swap between two `absl::optional` objects, using standard // semantics. template ::value && type_traits_internal::IsSwappable::value, bool>::type = false> void swap(optional& a, optional& b) noexcept(noexcept(a.swap(b))) { a.swap(b); } // make_optional() // // Creates a non-empty `optional` where the type of `T` is deduced. An // `absl::optional` can also be explicitly instantiated with // `make_optional(v)`. // // Note: `make_optional()` constructions may be declared `constexpr` for // trivially copyable types `T`. Non-trivial types require copy elision // support in C++17 for `make_optional` to support `constexpr` on such // non-trivial types. // // Example: // // constexpr absl::optional opt = absl::make_optional(1); // static_assert(opt.value() == 1, ""); template constexpr optional::type> make_optional(T&& v) { return optional::type>(std::forward(v)); } template constexpr optional make_optional(Args&&... args) { return optional(in_place_t(), std::forward(args)...); } template constexpr optional make_optional(std::initializer_list il, Args&&... args) { return optional(in_place_t(), il, std::forward(args)...); } // Relational operators [optional.relops] // Empty optionals are considered equal to each other and less than non-empty // optionals. Supports relations between optional and optional, between // optional and U, and between optional and nullopt. // // Note: We're careful to support T having non-bool relationals. // Requires: The expression, e.g. "*x == *y" shall be well-formed and its result // shall be convertible to bool. // The C++17 (N4606) "Returns:" statements are translated into // code in an obvious way here, and the original text retained as function docs. // Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true; // otherwise *x == *y. template constexpr auto operator==(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x == *y)) { return static_cast(x) != static_cast(y) ? false : static_cast(x) == false ? true : static_cast(*x == *y); } // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; // otherwise *x != *y. template constexpr auto operator!=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x != *y)) { return static_cast(x) != static_cast(y) ? true : static_cast(x) == false ? false : static_cast(*x != *y); } // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. template constexpr auto operator<(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x < *y)) { return !y ? false : !x ? true : static_cast(*x < *y); } // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. template constexpr auto operator>(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x > *y)) { return !x ? false : !y ? true : static_cast(*x > *y); } // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. template constexpr auto operator<=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x <= *y)) { return !x ? true : !y ? false : static_cast(*x <= *y); } // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. template constexpr auto operator>=(const optional& x, const optional& y) -> decltype(optional_internal::convertible_to_bool(*x >= *y)) { return !y ? true : !x ? false : static_cast(*x >= *y); } // Comparison with nullopt [optional.nullops] // The C++17 (N4606) "Returns:" statements are used directly here. 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 static_cast(x); } template constexpr bool operator!=(nullopt_t, const optional& x) noexcept { return static_cast(x); } template constexpr bool operator<(const optional&, nullopt_t) noexcept { return false; } template constexpr bool operator<(nullopt_t, const optional& x) noexcept { return static_cast(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 static_cast(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; } // Comparison with T [optional.comp_with_t] // Requires: The expression, e.g. "*x == v" shall be well-formed and its result // shall be convertible to bool. // The C++17 (N4606) "Equivalent to:" statements are used directly here. template constexpr auto operator==(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x == v)) { return static_cast(x) ? static_cast(*x == v) : false; } template constexpr auto operator==(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v == *x)) { return static_cast(x) ? static_cast(v == *x) : false; } template constexpr auto operator!=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x != v)) { return static_cast(x) ? static_cast(*x != v) : true; } template constexpr auto operator!=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v != *x)) { return static_cast(x) ? static_cast(v != *x) : true; } template constexpr auto operator<(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x < v)) { return static_cast(x) ? static_cast(*x < v) : true; } template constexpr auto operator<(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v < *x)) { return static_cast(x) ? static_cast(v < *x) : false; } template constexpr auto operator<=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x <= v)) { return static_cast(x) ? static_cast(*x <= v) : true; } template constexpr auto operator<=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v <= *x)) { return static_cast(x) ? static_cast(v <= *x) : false; } template constexpr auto operator>(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x > v)) { return static_cast(x) ? static_cast(*x > v) : false; } template constexpr auto operator>(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v > *x)) { return static_cast(x) ? static_cast(v > *x) : true; } template constexpr auto operator>=(const optional& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x >= v)) { return static_cast(x) ? static_cast(*x >= v) : false; } template constexpr auto operator>=(const U& v, const optional& x) -> decltype(optional_internal::convertible_to_bool(v >= *x)) { return static_cast(x) ? static_cast(v >= *x) : true; } ABSL_NAMESPACE_END } // namespace absl namespace std { // std::hash specialization for absl::optional. template struct hash > : absl::optional_internal::optional_hash_base {}; } // namespace std #undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS #endif // ABSL_USES_STD_OPTIONAL #endif // ABSL_TYPES_OPTIONAL_H_