| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- // -*-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. */
- #pragma once
- #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);
- template <typename U = T>
- typename std::enable_if<std::is_constructible<T, U&&>::value &&
- std::is_assignable<T&, U&&>::value,
- optional&>::type
- operator=(optional<U>&& other) noexcept;
- template <typename U = T>
- 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),
- optional&>::type
- 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
- : optional()
- {
- }
- template <typename T>
- optional<T>::optional(const optional& other)
- {
- if (other.has_value()) {
- this->emplace(*other);
- }
- }
- template <typename T>
- optional<T>::optional(optional&& other) noexcept
- {
- if (other.has_value()) {
- this->emplace(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>
- template <typename U>
- typename std::enable_if<std::is_constructible<T, U&&>::value &&
- std::is_assignable<T&, U&&>::value,
- optional<T>&>::type
- optional<T>::operator=(optional<U>&& 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 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),
- optional<T>&>::type
- optional<T>::operator=(U&& v)
- {
- if (this->has_value()) {
- this->value() = v;
- } else {
- this->emplace(std::forward<U>(v));
- }
- return *this;
- }
- template <typename T, typename U>
- bool operator==(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (lhs.has_value()) {
- return rhs.has_value() && *lhs == *rhs;
- }
- return !rhs.has_value();
- }
- template <typename T, typename U>
- bool operator!=(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (lhs.has_value()) {
- return !rhs.has_value() || *lhs != *rhs;
- }
- return rhs.has_value();
- }
- template <typename T, typename U>
- bool operator<(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (rhs.has_value()) {
- return !lhs.has_value() || *lhs < *rhs;
- }
- return false;
- }
- template <typename T, typename U>
- bool operator<=(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (!lhs.has_value()) {
- return true;
- }
- if (rhs.has_value()) {
- return *lhs <= *rhs;
- }
- return false;
- }
- template <typename T, typename U>
- bool operator>(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (lhs.has_value()) {
- return !rhs.has_value() || *lhs > *rhs;
- }
- return false;
- }
- template <typename T, typename U>
- bool operator>=(const optional<T>& lhs, const optional<U>& rhs)
- {
- if (!rhs.has_value()) {
- return true;
- }
- if (lhs.has_value()) {
- return *lhs >= *rhs;
- }
- return false;
- }
- template <typename T>
- bool operator==(const optional<T>& opt, nullopt_t) noexcept
- {
- return !opt.has_value();
- }
- template <typename T>
- bool operator!=(const optional<T>& opt, nullopt_t) noexcept
- {
- return opt.has_value();
- }
- template <typename T>
- bool operator<(const optional<T>& /*opt*/, nullopt_t) noexcept
- {
- return false;
- }
- template <typename T>
- bool operator<=(const optional<T>& opt, nullopt_t) noexcept
- {
- return !opt.has_value();
- }
- template <typename T>
- bool operator>(const optional<T>& opt, nullopt_t) noexcept
- {
- return opt.has_value();
- }
- template <typename T>
- bool operator>=(const optional<T>& /*opt*/, nullopt_t) noexcept
- {
- return true;
- }
- template <typename T>
- bool operator==(nullopt_t, const optional<T>& opt) noexcept
- {
- return !opt.has_value();
- }
- template <typename T>
- bool operator!=(nullopt_t, const optional<T>& opt) noexcept
- {
- return opt.has_value();
- }
- template <typename T>
- bool operator<(nullopt_t, const optional<T>& opt) noexcept
- {
- return opt.has_value();
- }
- template <typename T>
- bool operator<=(nullopt_t, const optional<T>& /*opt*/) noexcept
- {
- return true;
- }
- template <typename T>
- bool operator>(nullopt_t, const optional<T>& /*opt*/) noexcept
- {
- return false;
- }
- template <typename T>
- bool operator>=(nullopt_t, const optional<T>& opt) noexcept
- {
- return !opt.has_value();
- }
- template <typename T, typename U>
- bool operator==(const optional<T>& opt, const U& value)
- {
- return opt.has_value() && *opt == value;
- }
- template <typename T, typename U>
- bool operator!=(const optional<T>& opt, const U& value)
- {
- return !opt.has_value() || *opt != value;
- }
- template <typename T, typename U>
- bool operator<(const optional<T>& opt, const U& value)
- {
- return !opt.has_value() || *opt < value;
- }
- template <typename T, typename U>
- bool operator<=(const optional<T>& opt, const U& value)
- {
- return !opt.has_value() || *opt <= value;
- }
- template <typename T, typename U>
- bool operator>(const optional<T>& opt, const U& value)
- {
- return opt.has_value() && *opt > value;
- }
- template <typename T, typename U>
- bool operator>=(const optional<T>& opt, const U& value)
- {
- return opt.has_value() && *opt >= value;
- }
- template <typename T, typename U>
- bool operator==(const T& value, const optional<U>& opt)
- {
- return opt.has_value() && value == *opt;
- }
- template <typename T, typename U>
- bool operator!=(const T& value, const optional<U>& opt)
- {
- return !opt.has_value() || value != *opt;
- }
- template <typename T, typename U>
- bool operator<(const T& value, const optional<U>& opt)
- {
- return opt.has_value() && value < *opt;
- }
- template <typename T, typename U>
- bool operator<=(const T& value, const optional<U>& opt)
- {
- return opt.has_value() && value <= *opt;
- }
- template <typename T, typename U>
- bool operator>(const T& value, const optional<U>& opt)
- {
- return !opt.has_value() || value > *opt;
- }
- template <typename T, typename U>
- bool operator>=(const T& value, const optional<U>& opt)
- {
- return !opt.has_value() || value >= *opt;
- }
- 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
- }
|