// file : libbutl/optional.mxx -*- C++ -*- // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef __cpp_modules_ts #pragma once #endif // C includes. // Note: the Clang check must come before GCC since also defines __GNUC__. // #if defined(ODB_COMPILER) // // Make sure we use butl::optional during ODB compilation (has to be this // way until we completely switch to std::optional since we use the same // generated code for all compiler). // #elif defined(_MSC_VER) // // Available from 19.10 (15.0). Except it (or the compiler) doesn't seem to // be constexpr-correct. Things appear to be fixed in 19.20 (16.0) but // optional is now only available in the C++17 mode or later. // # if _MSC_VER >= 1920 # if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L // See /Zc:__cplusplus # define LIBBUTL_STD_OPTIONAL # endif # endif #elif defined(__clang__) // // Clang's libc++ has it since 4 but we might also be using libstdc++. For // the latter we will check for the presence of the header which // only appeared in GCC 7. Also assume both are only available in C++17. // // Note that on Mac OS it can still be . // # if __cplusplus >= 201703L # if __has_include(<__config>) # include <__config> // _LIBCPP_VERSION # if _LIBCPP_VERSION >= 4000 && __has_include() # define LIBBUTL_STD_OPTIONAL # endif # elif __has_include() # define LIBBUTL_STD_OPTIONAL # endif # endif #elif defined(__GNUC__) // // Available from 7 but only in the C++17 mode. Note also that from 8 // defines __cpp_lib_optional. // # if __GNUC__ >= 7 && __cplusplus >= 201703L # define LIBBUTL_STD_OPTIONAL # endif #endif #ifndef __cpp_lib_modules_ts #ifdef LIBBUTL_STD_OPTIONAL # include #else # include // move() # include // hash # include // is_trivially_destructible #endif #endif // Other includes. #ifdef __cpp_modules_ts export module butl.optional; #ifdef __cpp_lib_modules_ts import std.core; #endif #endif #include #ifdef LIBBUTL_STD_OPTIONAL LIBBUTL_MODEXPORT namespace butl { template using optional = std::optional; using std::nullopt_t; using std::nullopt; } #else 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_ts) && 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 &this->d_;} const T* operator-> () const {return &this->d_;} T& operator* () {return this->d_;} const T& operator* () const {return this->d_;} 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 #endif // !LIBBUTL_STD_OPTIONAL