summaryrefslogtreecommitdiffstats
path: root/Source/cm_optional.hxx
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2019-08-02 20:52:19 (GMT)
committerBrad King <brad.king@kitware.com>2019-08-23 12:43:35 (GMT)
commit197c5e12adea2b7d72cf8bfa17e961b9428f5d57 (patch)
tree327b5c4d8a376a2712c9a5e11d7b5fc1c06ef63a /Source/cm_optional.hxx
parent170fcd715f586cfd6b9f741c0572d472e0abe8ed (diff)
downloadCMake-197c5e12adea2b7d72cf8bfa17e961b9428f5d57.zip
CMake-197c5e12adea2b7d72cf8bfa17e961b9428f5d57.tar.gz
CMake-197c5e12adea2b7d72cf8bfa17e961b9428f5d57.tar.bz2
Source: Add cm::optional
Diffstat (limited to 'Source/cm_optional.hxx')
-rw-r--r--Source/cm_optional.hxx343
1 files changed, 343 insertions, 0 deletions
diff --git a/Source/cm_optional.hxx b/Source/cm_optional.hxx
new file mode 100644
index 0000000..295571d
--- /dev/null
+++ b/Source/cm_optional.hxx
@@ -0,0 +1,343 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_optional_hxx
+#define cm_optional_hxx
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+# define CMake_HAVE_CXX_OPTIONAL
+#endif
+
+#if defined(CMake_HAVE_CXX_OPTIONAL)
+# include <optional>
+#else
+# include "cm_utility.hxx"
+# include <memory>
+# include <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