aboutsummaryrefslogtreecommitdiff
path: root/libbutl/optional.mxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-06-27 14:55:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-06-27 14:55:27 +0200
commit524322f78775dc14c61d33cbdb719b8330c2ad5c (patch)
tree4a101a1359025b916ca01d33339197c78bbb1872 /libbutl/optional.mxx
parent0071c616f02de72f8a6ed82448a7b9e8a6c9a40c (diff)
Reimplement optional not to require default-constructible value types
Diffstat (limited to 'libbutl/optional.mxx')
-rw-r--r--libbutl/optional.mxx147
1 files changed, 120 insertions, 27 deletions
diff --git a/libbutl/optional.mxx b/libbutl/optional.mxx
index cddf59a..ae72399 100644
--- a/libbutl/optional.mxx
+++ b/libbutl/optional.mxx
@@ -9,8 +9,9 @@
// C includes.
#ifndef __cpp_lib_modules
-#include <utility> // move()
-#include <functional> // hash
+#include <utility> // move()
+#include <functional> // hash
+#include <type_traits> // is_trivially_destructible
#endif
// Other includes.
@@ -34,55 +35,145 @@ LIBBUTL_MODEXPORT namespace butl
#endif
constexpr nullopt_t nullopt (1);
+ namespace details
+ {
+ template <typename T, bool = std::is_trivially_destructible<T>::value>
+ struct optional_data;
+
+ template <typename T>
+ struct optional_data<T, false>
+ {
+ struct empty {};
+
+ union
+ {
+ empty e_;
+ T d_;
+ };
+ bool v_;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional_data (): e_ (), v_ (false) {}
+ constexpr optional_data (nullopt_t): e_ (), v_ (false) {}
+ constexpr optional_data (const T& v): d_ (v), v_ (true) {}
+ constexpr optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#else
+ optional_data (): e_ (), v_ (false) {}
+ optional_data (nullopt_t): e_ (), v_ (false) {}
+ optional_data (const T& v): d_ (v), v_ (true) {}
+ optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#endif
+
+ optional_data& operator= (nullopt_t);
+ optional_data& operator= (const T&);
+ optional_data& operator= (T&&);
+
+ optional_data (const optional_data&);
+ optional_data (optional_data&&);
+
+ optional_data& operator= (const optional_data&);
+ optional_data& operator= (optional_data&&);
+
+ ~optional_data ();
+ };
+
+ template <typename T>
+ struct optional_data<T, true>
+ {
+ struct empty {};
+
+ union
+ {
+ empty e_;
+ T d_;
+ };
+ bool v_;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional_data (): e_ (), v_ (false) {}
+ constexpr optional_data (nullopt_t): e_ (), v_ (false) {}
+ constexpr optional_data (const T& v): d_ (v), v_ (true) {}
+ constexpr optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#else
+ optional_data (): e_ (), v_ (false) {}
+ optional_data (nullopt_t): e_ (), v_ (false) {}
+ optional_data (const T& v): d_ (v), v_ (true) {}
+ optional_data (T&& v): d_ (std::move (v)), v_ (true) {}
+#endif
+
+ optional_data& operator= (nullopt_t);
+ optional_data& operator= (const T&);
+ optional_data& operator= (T&&);
+
+ optional_data (const optional_data&);
+ optional_data (optional_data&&);
+
+ optional_data& operator= (const optional_data&);
+ optional_data& operator= (optional_data&&);
+ };
+ }
+
template <typename T>
- class optional
+ class optional: private details::optional_data<T>
{
+ using base = details::optional_data<T>;
+
public:
- typedef T value_type;
+ using value_type = T;
+
+#if !defined(_MSC_VER) || _MSC_VER > 1900
+ constexpr optional () {}
+ constexpr optional (nullopt_t) {}
+ constexpr optional (const T& v): base (v) {}
+ constexpr optional (T&& v): base (std::move (v)) {}
+#else
+ optional () {}
+ optional (nullopt_t) {}
+ optional (const T& v): base (v) {}
+ optional (T&& v): base (std::move (v)) {}
+#endif
- constexpr optional (): value_ (), null_ (true) {} // VC14 needs value_().
- constexpr optional (nullopt_t): value_ (), null_ (true) {}
- constexpr optional (const T& v): value_ (v), null_ (false) {}
- constexpr optional (T&& v): value_ (std::move (v)), null_ (false) {}
+ optional& operator= (nullopt_t v) {static_cast<base&> (*this) = v; return *this;}
+ optional& operator= (const T& v) {static_cast<base&> (*this) = v; return *this;}
+ optional& operator= (T&& v) {static_cast<base&> (*this) = std::move (v); return *this;}
- optional& operator= (nullopt_t) {value_ = T (); null_ = true; return *this;}
- optional& operator= (const T& v) {value_ = v; null_ = false; return *this;}
- optional& operator= (T&& v) {value_ = std::move (v); null_ = false; return *this;}
+ T& value () {return this->d_;}
+ const T& value () const {return this->d_;}
- T& value () {return value_;}
- const T& value () const {return value_;}
+ T* operator-> () {return &value ();}
+ const T* operator-> () const {return &value ();}
- T* operator-> () {return &value_;}
- const T* operator-> () const {return &value_;}
+ T& operator* () {return value ();}
+ const T& operator* () const {return value ();}
- T& operator* () {return value_;}
- const T& operator* () const {return value_;}
+ bool has_value () const {return this->v_;}
+ explicit operator bool () const {return this->v_;}
- bool has_value () const {return !null_;}
- explicit operator bool () const {return !null_;}
+ optional (const optional&) = default;
+ optional (optional&&) = default;
- private:
- T value_;
- bool null_;
+ optional& operator= (const optional&) = default;
+ optional& operator= (optional&&) = default;
};
template <typename T>
inline auto
- operator== (const optional<T>& x, const optional<T>& y) -> decltype (*x == *y)
+ operator== (const optional<T>& x, const optional<T>& y)
{
- return static_cast<bool> (x) == static_cast<bool> (y) && (!x || *x == *y);
+ bool px (x), py (y);
+ return px == py && (!px || *x == *y);
}
template <typename T>
inline auto
- operator!= (const optional<T>& x, const optional<T>& y) -> decltype (x == y)
+ operator!= (const optional<T>& x, const optional<T>& y)
{
return !(x == y);
}
template <typename T>
inline auto
- operator< (const optional<T>& x, const optional<T>& y) -> decltype (*x < *y)
+ operator< (const optional<T>& x, const optional<T>& y)
{
bool px (x), py (y);
return px < py || (px && py && *x < *y);
@@ -90,7 +181,7 @@ LIBBUTL_MODEXPORT namespace butl
template <typename T>
inline auto
- operator> (const optional<T>& x, const optional<T>& y) -> decltype (*x > *y)
+ operator> (const optional<T>& x, const optional<T>& y)
{
return y < x;
}
@@ -111,3 +202,5 @@ namespace std
}
};
}
+
+#include <libbutl/optional.ixx>