From df1ef68cd8e8582724ce1192bfc202e0b9aeaf0c Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 28 Sep 2021 19:24:31 +0300 Subject: Get rid of C++ modules related code and rename *.mxx files to *.hxx --- libbutl/optional.hxx | 343 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 libbutl/optional.hxx (limited to 'libbutl/optional.hxx') diff --git a/libbutl/optional.hxx b/libbutl/optional.hxx new file mode 100644 index 0000000..28aa95a --- /dev/null +++ b/libbutl/optional.hxx @@ -0,0 +1,343 @@ +// file : libbutl/optional.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#pragma once + +// Note: the Clang check must come before GCC since it 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 compilers). + // +#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 + +#ifdef LIBBUTL_STD_OPTIONAL +# include +#else +# include // move() +# include // hash +# include // is_* +#endif + +#include + +#ifdef LIBBUTL_STD_OPTIONAL +namespace butl +{ + template + using optional = std::optional; + + using std::nullopt_t; + using std::nullopt; +} +#else + +namespace butl +{ + // Simple optional class template while waiting for std::optional. + // + struct nullopt_t {constexpr explicit nullopt_t (int) {}}; + 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 ::value, + bool = std::is_move_constructible::value> + struct optional_ctors: optional_data + { + using optional_data::optional_data; + }; + + template + struct optional_ctors: optional_ctors + { + using optional_ctors::optional_ctors; + +#if !defined(_MSC_VER) || _MSC_VER > 1900 + constexpr optional_ctors () = default; +#else + optional_ctors () = default; +#endif + + optional_ctors (const optional_ctors&) = delete; + +#if (!defined(_MSC_VER) || _MSC_VER > 1900) && \ + (!defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)) + constexpr optional_ctors (optional_ctors&&) = default; +#else + optional_ctors (optional_ctors&&) = default; +#endif + + optional_ctors& operator= (const optional_ctors&) = default; + optional_ctors& operator= (optional_ctors&&) = default; + }; + + template + struct optional_ctors: optional_ctors + { + using optional_ctors::optional_ctors; + +#if !defined(_MSC_VER) || _MSC_VER > 1900 + constexpr optional_ctors () = default; +#else + optional_ctors () = default; +#endif + +#if (!defined(_MSC_VER) || _MSC_VER > 1900) && \ + (!defined(__GNUC__) || __GNUC__ > 4 || defined(__clang__)) + constexpr optional_ctors (const optional_ctors&) = default; +#else + optional_ctors (const optional_ctors&) = default; +#endif + + optional_ctors (optional_ctors&&) = delete; + + optional_ctors& operator= (const optional_ctors&) = default; + optional_ctors& operator= (optional_ctors&&) = default; + }; + + template + struct optional_ctors: optional_ctors + { + using optional_ctors::optional_ctors; + +#if !defined(_MSC_VER) || _MSC_VER > 1900 + constexpr optional_ctors () = default; +#else + optional_ctors () = default; +#endif + + optional_ctors (const optional_ctors&) = delete; + optional_ctors (optional_ctors&&) = delete; + + optional_ctors& operator= (const optional_ctors&) = default; + optional_ctors& operator= (optional_ctors&&) = default; + }; + } + + template + class optional: private details::optional_ctors + { + using base = details::optional_ctors; + + 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 -- cgit v1.1