diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2018-06-27 14:55:27 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2018-06-27 14:55:27 +0200 |
commit | 524322f78775dc14c61d33cbdb719b8330c2ad5c (patch) | |
tree | 4a101a1359025b916ca01d33339197c78bbb1872 /libbutl/optional.mxx | |
parent | 0071c616f02de72f8a6ed82448a7b9e8a6c9a40c (diff) |
Reimplement optional not to require default-constructible value types
Diffstat (limited to 'libbutl/optional.mxx')
-rw-r--r-- | libbutl/optional.mxx | 147 |
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> |