#pragma once #ifdef USE_BOOST #include #include #define GIT_USE_BOOST_OPTIONAL #elif defined(__has_include) && __has_include() #include #define GIT_USE_STD_OPTIONAL #elif defined(__has_include) && __has_include() #include #define GIT_USE_STD_EXPERIMENTAL_OPTIONAL #else #include #include #endif namespace git { namespace internal { #if defined(GIT_USE_BOOST_OPTIONAL) #undef GIT_USE_BOOST_OPTIONAL using boost::optional; using boost::none_t; using boost::none; template optional & emplace(optional & opt, Args&&... args) { opt = boost::in_place(std::forward(args)...); return opt; } template bool has_value(optional const & opt) { return opt.is_initialized(); } #elif defined(GIT_USE_STD_OPTIONAL) #undef GIT_USE_STD_OPTIONAL using std::optional; using none_t = std::nullopt_t; const none_t none = std::nullopt; template optional & emplace(optional & opt, Args&&... args) { opt.emplace(std::forward(args)...); return opt; } template bool has_value(optional const & opt) { return opt.has_value(); } #elif defined(GIT_USE_STD_EXPERIMENTAL_OPTIONAL) #undef GIT_USE_STD_EXPERIMENTAL_OPTIONAL using std::experimental::optional; using none_t = std::experimental::nullopt_t; const none_t none = std::experimental::nullopt; template optional & emplace(optional & opt, Args&&... args) { opt.emplace(std::forward(args)...); return opt; } template bool has_value(optional const & opt) { return static_cast(opt); } #else typedef std::nullptr_t none_t; const none_t none = nullptr; //Simple (and incomplete) optional implementations template class optional { private: //type alias typedef typename std::aligned_storage::type StorageT; public: //type traits enum non_movable_t{}; enum non_copyable_t{}; static const bool movable = std::is_move_constructible::value && std::is_move_assignable::value; static const bool copyable = std::is_copy_constructible::value && std::is_copy_assignable::value; typedef typename std::conditional::type MovableT; typedef typename std::conditional::type CopyableT; public: //initializing and attribution constexpr optional(none_t t = none) : initialized(false) {} optional(T const & v) { assign(v);} optional(T && v) { assign(std::move(v));} optional(optional const & other) { assign(other);} optional(optional && other) { assign(std::move(other));} optional & operator=(none_t none) { reset(); return *this;} optional & operator=(T && v) { return assign(std::move(v));} optional & operator=(const T & v) { return assign(v);} optional & operator=(optional const & other){ return assign(other);} optional & operator=(optional && other){ return assign(std::move(other));} ~optional() { reset(); } public: //getting value T const & value() const { return reinterpret_cast(storage); } T & value() { return reinterpret_cast(storage); } T const & operator* () const { return value(); } T & operator * () { return value(); } T const * operator -> () const { return &value(); } T * operator -> () { return &value(); } public: //querying state explicit operator bool() const { return initialized; } public: //change state void reset() { if (initialized) { value().~T(); initialized = false; } } template void emplace(Args&&... args){ if (initialized) reset(); init(std::forward(args)...); } private: //assign optional & assign(MovableT && value) { return set_from_value(std::move(value)); } optional & assign(CopyableT const & value) { return set_from_value(value); } optional & assign(optional const & other) { return set_or_reset(other.value(), other.initialized); } optional & assign(optional && other) { return set_or_reset(std::move(other.value()), other.initialized); } protected: template optional & set_or_reset(U&& u, bool isValid) { if (isValid) set_from_value(std::forward(u)); else reset(); return *this; } template optional & set_from_value(U&& u) { if (initialized) reinterpret_cast(storage) = std::forward(u); else init(std::forward(u)); return *this; } template void init(Args&& ... args){ new (&storage) T(std::forward(args)...); initialized = true; } protected: StorageT storage; bool initialized; }; template optional & emplace(optional & opt, Args&&... args){ opt.emplace(std::forward(args)...); return opt; } template bool has_value(optional const & opt) { return static_cast(opt); } #endif }}//namespace git