// file : libbutl/optional.mxx -*- C++ -*- // copyright : Copyright (c) 2014-2018 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef __cpp_modules #pragma once #endif // C includes. #ifndef __cpp_lib_modules #include // move() #include // hash #include // is_trivially_destructible #endif // Other includes. #ifdef __cpp_modules export module butl.optional; #ifdef __cpp_lib_modules import std.core; #endif #endif #include LIBBUTL_MODEXPORT namespace butl { // Simple optional class template while waiting for std::optional. // struct nullopt_t {constexpr explicit nullopt_t (int) {}}; #if defined(__cpp_modules) && defined(__clang__) //@@ MOD Clang duplicate sym. inline #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 #if (!defined(_MSC_VER) || _MSC_VER > 1900) && \ (!defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)) constexpr optional_data (const optional_data& o): v_ (o.v_) {if (v_) new (&d_) T (o.d_);} constexpr optional_data (optional_data&& o): v_ (o.v_) {if (v_) new (&d_) T (std::move (o.d_));} #else optional_data (const optional_data& o): v_ (o.v_) {if (v_) new (&d_) T (o.d_);} optional_data (optional_data&& o): v_ (o.v_) {if (v_) new (&d_) T (std::move (o.d_));} #endif optional_data& operator= (nullopt_t); optional_data& operator= (const T&); optional_data& operator= (T&&); 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 #if (!defined(_MSC_VER) || _MSC_VER > 1900) && \ (!defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)) constexpr optional_data (const optional_data& o): v_ (o.v_) {if (v_) new (&d_) T (o.d_);} constexpr optional_data (optional_data&& o): v_ (o.v_) {if (v_) new (&d_) T (std::move (o.d_));} #else optional_data (const optional_data& o): v_ (o.v_) {if (v_) new (&d_) T (o.d_);} optional_data (optional_data&& o): v_ (o.v_) {if (v_) new (&d_) T (std::move (o.d_));} #endif optional_data& operator= (nullopt_t); optional_data& operator= (const T&); optional_data& operator= (T&&); optional_data& operator= (const optional_data&); optional_data& operator= (optional_data&&); }; } template class optional: private details::optional_data { using base = details::optional_data; public: 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 #if (!defined(_MSC_VER) || _MSC_VER > 1900) && \ (!defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)) constexpr optional (const optional&) = default; constexpr optional (optional&&) = default; #else optional (const optional&) = default; optional (optional&&) = default; #endif 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= (const optional&) = default; optional& operator= (optional&&) = default; T& value () {return this->d_;} const T& value () const {return this->d_;} 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_;} }; template inline auto operator== (const optional& x, const optional& y) { bool px (x), py (y); return px == py && (!px || *x == *y); } template inline auto operator!= (const optional& x, const optional& y) { return !(x == y); } template inline auto operator< (const optional& x, const optional& y) { bool px (x), py (y); return px < py || (px && py && *x < *y); } template inline auto operator> (const optional& x, const optional& y) { return y < x; } } namespace std { template struct hash>: hash { using argument_type = butl::optional; size_t operator() (const butl::optional& o) const noexcept (noexcept (hash {} (*o))) { return o ? hash::operator() (*o) : static_cast (-3333); } }; } #include