From 524322f78775dc14c61d33cbdb719b8330c2ad5c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 27 Jun 2018 14:55:27 +0200 Subject: Reimplement optional not to require default-constructible value types --- libbutl/optional.mxx | 147 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 27 deletions(-) (limited to 'libbutl/optional.mxx') 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 // move() -#include // hash +#include // move() +#include // hash +#include // is_trivially_destructible #endif // Other includes. @@ -34,55 +35,145 @@ LIBBUTL_MODEXPORT namespace butl #endif constexpr nullopt_t nullopt (1); + namespace details + { + template ::value> + struct optional_data; + + template + struct optional_data + { + 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 + struct optional_data + { + 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 - class optional + class optional: private details::optional_data { + using base = details::optional_data; + 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 (*this) = v; return *this;} + optional& operator= (const T& v) {static_cast (*this) = v; return *this;} + optional& operator= (T&& v) {static_cast (*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 inline auto - operator== (const optional& x, const optional& y) -> decltype (*x == *y) + operator== (const optional& x, const optional& y) { - return static_cast (x) == static_cast (y) && (!x || *x == *y); + bool px (x), py (y); + return px == py && (!px || *x == *y); } template inline auto - operator!= (const optional& x, const optional& y) -> decltype (x == y) + operator!= (const optional& x, const optional& y) { return !(x == y); } template inline auto - operator< (const optional& x, const optional& y) -> decltype (*x < *y) + operator< (const optional& x, const optional& y) { bool px (x), py (y); return px < py || (px && py && *x < *y); @@ -90,7 +181,7 @@ LIBBUTL_MODEXPORT namespace butl template inline auto - operator> (const optional& x, const optional& y) -> decltype (*x > *y) + operator> (const optional& x, const optional& y) { return y < x; } @@ -111,3 +202,5 @@ namespace std } }; } + +#include -- cgit v1.1