| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- // -*-c++-*-
- // vim: set ft=cpp:
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #ifndef cm_optional
- #define cm_optional
- #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
- # define CMake_HAVE_CXX_OPTIONAL
- #endif
- #if defined(CMake_HAVE_CXX_OPTIONAL)
- # include <optional> // IWYU pragma: export
- #else
- # include <memory>
- # include <cm/utility>
- #endif
- namespace cm {
- #if defined(CMake_HAVE_CXX_OPTIONAL)
- using std::nullopt_t;
- using std::nullopt;
- using std::optional;
- using std::bad_optional_access;
- using std::make_optional;
- #else
- class bad_optional_access : public std::exception
- {
- using std::exception::exception;
- };
- struct nullopt_t
- {
- explicit constexpr nullopt_t(int) {}
- };
- constexpr nullopt_t nullopt{ 0 };
- template <typename T>
- class optional
- {
- public:
- using value_type = T;
- optional() noexcept = default;
- optional(nullopt_t) noexcept;
- optional(const optional& other);
- optional(optional&& other) noexcept;
- template <typename... Args>
- explicit optional(cm::in_place_t, Args&&... args);
- template <
- typename U = T,
- typename = typename std::enable_if<
- std::is_constructible<T, U&&>::value &&
- !std::is_same<typename std::decay<U>::type, cm::in_place_t>::value &&
- !std::is_same<typename std::decay<U>::type,
- cm::optional<T>>::value>::type>
- optional(U&& v);
- ~optional();
- optional& operator=(nullopt_t) noexcept;
- optional& operator=(const optional& other);
- optional& operator=(optional&& other) noexcept;
- template <
- typename U = T,
- typename = typename std::enable_if<
- !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
- std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value &&
- (!std::is_scalar<T>::value ||
- !std::is_same<typename std::decay<U>::type, T>::value)>::type>
- optional& operator=(U&& v);
- const T* operator->() const;
- T* operator->();
- const T& operator*() const&;
- T& operator*() &;
- const T&& operator*() const&&;
- T&& operator*() &&;
- explicit operator bool() const noexcept;
- bool has_value() const noexcept;
- T& value() &;
- const T& value() const&;
- T&& value() &&;
- const T&& value() const&&;
- template <typename U>
- T value_or(U&& default_value) const&;
- template <typename U>
- T value_or(U&& default_value) &&;
- void swap(optional& other) noexcept;
- void reset() noexcept;
- template <typename... Args>
- T& emplace(Args&&... args);
- private:
- bool _has_value = false;
- std::allocator<T> _allocator;
- union _mem_union
- {
- T value;
- // Explicit constructor and destructor is required to make this work
- _mem_union() noexcept {}
- ~_mem_union() noexcept {}
- } _mem;
- };
- template <typename T>
- optional<typename std::decay<T>::type> make_optional(T&& value)
- {
- return optional<typename std::decay<T>::type>(std::forward<T>(value));
- }
- template <typename T, class... Args>
- optional<T> make_optional(Args&&... args)
- {
- return optional<T>(in_place, std::forward<Args>(args)...);
- }
- template <typename T>
- optional<T>::optional(nullopt_t) noexcept
- {
- }
- template <typename T>
- optional<T>::optional(const optional& other)
- {
- *this = other;
- }
- template <typename T>
- optional<T>::optional(optional&& other) noexcept
- {
- *this = std::move(other);
- }
- template <typename T>
- template <typename... Args>
- optional<T>::optional(cm::in_place_t, Args&&... args)
- {
- this->emplace(std::forward<Args>(args)...);
- }
- template <typename T>
- template <typename U, typename>
- optional<T>::optional(U&& v)
- {
- this->emplace(std::forward<U>(v));
- }
- template <typename T>
- optional<T>::~optional()
- {
- this->reset();
- }
- template <typename T>
- optional<T>& optional<T>::operator=(nullopt_t) noexcept
- {
- this->reset();
- return *this;
- }
- template <typename T>
- optional<T>& optional<T>::operator=(const optional& other)
- {
- if (other.has_value()) {
- if (this->has_value()) {
- this->value() = *other;
- } else {
- this->emplace(*other);
- }
- } else {
- this->reset();
- }
- return *this;
- }
- template <typename T>
- optional<T>& optional<T>::operator=(optional&& other) noexcept
- {
- if (other.has_value()) {
- if (this->has_value()) {
- this->value() = std::move(*other);
- } else {
- this->emplace(std::move(*other));
- }
- } else {
- this->reset();
- }
- return *this;
- }
- template <typename T>
- template <typename U, typename>
- optional<T>& optional<T>::operator=(U&& v)
- {
- if (this->has_value()) {
- this->value() = v;
- } else {
- this->emplace(std::forward<U>(v));
- }
- return *this;
- }
- template <typename T>
- const T* optional<T>::operator->() const
- {
- return &**this;
- }
- template <typename T>
- T* optional<T>::operator->()
- {
- return &**this;
- }
- template <typename T>
- const T& optional<T>::operator*() const&
- {
- return this->_mem.value;
- }
- template <typename T>
- T& optional<T>::operator*() &
- {
- return this->_mem.value;
- }
- template <typename T>
- const T&& optional<T>::operator*() const&&
- {
- return std::move(**this);
- }
- template <typename T>
- T&& optional<T>::operator*() &&
- {
- return std::move(**this);
- }
- template <typename T>
- bool optional<T>::has_value() const noexcept
- {
- return this->_has_value;
- }
- template <typename T>
- optional<T>::operator bool() const noexcept
- {
- return this->has_value();
- }
- template <typename T>
- T& optional<T>::value() &
- {
- if (!this->has_value()) {
- throw cm::bad_optional_access{};
- }
- return **this;
- }
- template <typename T>
- const T& optional<T>::value() const&
- {
- if (!this->has_value()) {
- throw cm::bad_optional_access{};
- }
- return **this;
- }
- template <typename T>
- template <typename U>
- T optional<T>::value_or(U&& default_value) const&
- {
- return bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value));
- }
- template <typename T>
- template <typename U>
- T optional<T>::value_or(U&& default_value) &&
- {
- return bool(*this) ? std::move(**this)
- : static_cast<T>(std::forward<U>(default_value));
- }
- template <typename T>
- void optional<T>::swap(optional& other) noexcept
- {
- if (this->has_value()) {
- if (other.has_value()) {
- using std::swap;
- swap(**this, *other);
- } else {
- other.emplace(std::move(**this));
- this->reset();
- }
- } else if (other.has_value()) {
- this->emplace(std::move(*other));
- other.reset();
- }
- }
- template <typename T>
- void optional<T>::reset() noexcept
- {
- if (this->has_value()) {
- this->_has_value = false;
- std::allocator_traits<std::allocator<T>>::destroy(this->_allocator,
- &**this);
- }
- }
- template <typename T>
- template <typename... Args>
- T& optional<T>::emplace(Args&&... args)
- {
- this->reset();
- std::allocator_traits<std::allocator<T>>::construct(
- this->_allocator, &**this, std::forward<Args>(args)...);
- this->_has_value = true;
- return this->value();
- }
- #endif
- }
- #endif
|