diff options
author | Marc Chevrier <marc.chevrier@gmail.com> | 2019-08-04 08:49:16 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-09-20 14:01:37 (GMT) |
commit | c688b401d3adaacc820ef4b589010e8aefa808b1 (patch) | |
tree | 83e46e3dc7c9847692e61d0e6629b1cf9b65d2a5 /Utilities/std/cm/optional | |
parent | 9c31d83aa2a3d3f5921f4a5a559e126e285b96c5 (diff) | |
download | CMake-c688b401d3adaacc820ef4b589010e8aefa808b1.zip CMake-c688b401d3adaacc820ef4b589010e8aefa808b1.tar.gz CMake-c688b401d3adaacc820ef4b589010e8aefa808b1.tar.bz2 |
cmstd: Modernize CMake system headers
Provide a standardized way to handle the C++ "standard" headers
customized to be used with current CMake C++ standard constraints.
Offer under directory `cm` headers which can be used as direct
replacements of the standard ones. For example:
#include <cm/string_view>
can be used safely for CMake development in place of the `<string_view>`
standard header.
Fixes: #19491
Diffstat (limited to 'Utilities/std/cm/optional')
-rw-r--r-- | Utilities/std/cm/optional | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional new file mode 100644 index 0000000..80b0951 --- /dev/null +++ b/Utilities/std/cm/optional @@ -0,0 +1,344 @@ +// -*-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 |