From 1213c8959a58e639d00ed59bb010e983730b71c7 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Tue, 1 Nov 2016 05:31:59 -0400 Subject: [PATCH] Ditch the dependency on the optional submodule, nobody's ever gonna care about it... --- .gitmodules | 5 +- sol/object.hpp | 2 +- sol/optional.hpp | 3 +- sol/optional_implementation.hpp | 1141 +++++++++++++++++++++++++++++++ 4 files changed, 1145 insertions(+), 6 deletions(-) create mode 100644 sol/optional_implementation.hpp diff --git a/.gitmodules b/.gitmodules index f6ae162a..570fde0f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "Catch"] path = Catch - url = https://github.com/philsquared/Catch.git -[submodule "Optional"] - path = Optional - url = https://github.com/ThePhD/Optional.git + url = https://github.com/philsquared/Catch.git \ No newline at end of file diff --git a/sol/object.hpp b/sol/object.hpp index 5a038a3a..fafa0b68 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -22,11 +22,11 @@ #ifndef SOL_OBJECT_HPP #define SOL_OBJECT_HPP -#include "optional.hpp" #include "reference.hpp" #include "stack.hpp" #include "userdata.hpp" #include "variadic_args.hpp" +#include "optional.hpp" namespace sol { diff --git a/sol/optional.hpp b/sol/optional.hpp index 823bdc3d..16f805e4 100644 --- a/sol/optional.hpp +++ b/sol/optional.hpp @@ -22,11 +22,12 @@ #ifndef SOL_OPTIONAL_HPP #define SOL_OPTIONAL_HPP +#include "compatibility.hpp" #include "in_place.hpp" #if defined(SOL_USE_BOOST) #include #else -#include "../Optional/optional.hpp" +#include "optional_implementation.hpp" #endif // Boost vs. Better optional namespace sol { diff --git a/sol/optional_implementation.hpp b/sol/optional_implementation.hpp new file mode 100644 index 00000000..b4d58a32 --- /dev/null +++ b/sol/optional_implementation.hpp @@ -0,0 +1,1141 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Copyright (C) 2011 - 2012 Andrzej Krzemienski. +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The idea and interface is based on Boost.Optional library +// authored by Fernando Luis Cacciola Carballal + +# ifndef ___SOL_OPTIONAL_HPP___ +# define ___SOL_OPTIONAL_HPP___ + +# include +# include +# include +# include +# include +# include +# include +#ifdef SOL_NO_EXCEPTIONS +#include +#endif // Exceptions + +# define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ >= 5) +# define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if (defined __cplusplus) && (__cplusplus == 201103L) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +namespace sol { + + // BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template + using is_trivially_destructible = ::std::has_trivial_destructor; +# endif + // END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + +// workaround for missing traits in GCC and CLANG + template + struct is_nothrow_move_constructible + { + constexpr static bool value = ::std::is_nothrow_constructible::value; + }; + + + template + struct is_assignable + { + template + constexpr static bool has_assign(...) { return false; } + + template () = ::std::declval(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign(true); + }; + + + template + struct is_nothrow_move_assignable + { + template + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template + struct has_nothrow_move_assign { + constexpr static bool value = noexcept(::std::declval() = ::std::declval()); + }; + + constexpr static bool value = has_nothrow_move_assign::value>::value; + }; + // end workaround + + +# endif + + + +// 20.5.4, optional for object types + template class optional; + + // 20.5.5, optional for lvalue reference types + template class optional; + + + // workaround: std utility functions aren't constexpr yet + template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type& t) noexcept + { + return static_cast(t); + } + + template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type&& t) noexcept + { + static_assert(!::std::is_lvalue_reference::value, "!!"); + return static_cast(t); + } + + template inline constexpr typename ::std::remove_reference::type&& constexpr_move(T&& t) noexcept + { + return static_cast::type&&>(t); + } + + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + + namespace detail_ + { + + // static_addressof: a constexpr version of addressof + template + struct has_overloaded_addressof + { + template + constexpr static bool has_overload(...) { return false; } + + template ().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload(true); + }; + + template )> + constexpr T* static_addressof(T& ref) + { + return &ref; + } + + template )> + T* static_addressof(T& ref) + { + return ::std::addressof(ref); + } + + + // the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A + template + constexpr U convert(U v) { return v; } + + } // namespace detail_ + + constexpr struct trivial_init_t {} trivial_init{}; + + // 20.5.7, Disengaged state indicator + struct nullopt_t + { + struct init {}; + constexpr explicit nullopt_t(init) {} + }; + constexpr nullopt_t nullopt{ nullopt_t::init() }; + + + // 20.5.8, class bad_optional_access + class bad_optional_access : public ::std::logic_error { + public: + explicit bad_optional_access(const ::std::string& what_arg) : ::std::logic_error{ what_arg } {} + explicit bad_optional_access(const char* what_arg) : ::std::logic_error{ what_arg } {} + }; + + + template + struct optional_base + { + bool init_; + char storage_[sizeof(T)]; + + constexpr optional_base() noexcept : init_(false), storage_() {}; + + explicit optional_base(const T& v) : init_(true), storage_() { + new (&storage())T(v); + } + + explicit optional_base(T&& v) : init_(true), storage_() { + new (&storage())T(constexpr_move(v)); + } + + template explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_() { + new (&storage())T(constexpr_forward(args)...); + } + + template >)> + explicit optional_base(in_place_t, ::std::initializer_list il, Args&&... args) + : init_(true), storage_() { + new (&storage())T(il, constexpr_forward(args)...); + } +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + T& storage() { + return *reinterpret_cast(&storage_[0]); + } + + constexpr const T& storage() const { + return *reinterpret_cast(&storage_[0]); + } +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + + ~optional_base() { if (init_) { storage().T::~T(); } } + }; + +#if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ + // Sorry, GCC 4.x; you're just a piece of shit + template + using constexpr_optional_base = optional_base; +#else + template + struct constexpr_optional_base + { + bool init_; + char storage_[sizeof(T)]; + constexpr constexpr_optional_base() noexcept : init_(false), storage_() {} + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_() { + new (&storage())T(v); + } + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_() { + new (&storage())T(constexpr_move(v)); + } + + template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_() { + new (&storage())T(constexpr_forward(args)...); + } + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list il, Args&&... args) + : init_(true), storage_() { + new (&storage())T(il, constexpr_forward(args)...); + } + +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + T& storage() { + return (*reinterpret_cast(&storage_[0])); + } + + constexpr const T& storage() const { + return (*reinterpret_cast(&storage_[0])); + } +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + + ~constexpr_optional_base() = default; + }; +#endif + + template + using OptionalBase = typename ::std::conditional< + ::std::is_trivially_destructible::value, + constexpr_optional_base::type>, + optional_base::type> + >::type; + + + + template + class optional : private OptionalBase + { + static_assert(!::std::is_same::type, nullopt_t>::value, "bad T"); + static_assert(!::std::is_same::type, in_place_t>::value, "bad T"); + + + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + typename ::std::remove_const::type* dataptr() { return ::std::addressof(OptionalBase::storage()); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage()); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage(); } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return ::std::move(OptionalBase::storage()); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage(); } +# else + T& contained_val() & { return OptionalBase::storage(); } + T&& contained_val() && { return ::std::move(OptionalBase::storage()); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase::storage(); } + T& contained_val() { return OptionalBase::storage(); } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(::std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(::std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(::std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, ::std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, ::std::forward(args)...); + OptionalBase::init_ = true; + } + + public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + + optional(const optional& rhs) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(const optional& rhs) : optional() + { + if (rhs) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + + optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible::value) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(::std::move(*rhs)); + OptionalBase::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase(v) {} + + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place, constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list il, Args&&... args) + : OptionalBase(in_place, il, constexpr_forward(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(::std::is_nothrow_move_assignable::value && ::std::is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(::std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = ::std::move(*rhs); + return *this; + } + + template + auto operator=(U&& v) + -> typename ::std::enable_if + < + ::std::is_same::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = ::std::forward(v); } + else { initialize(::std::forward(v)); } + return *this; + } + + + template + void emplace(Args&&... args) + { + clear(); + initialize(::std::forward(args)...); + } + + template + void emplace(::std::initializer_list il, Args&&... args) + { + clear(); + initialize(il, ::std::forward(args)...); + } + + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(::std::is_nothrow_move_constructible::value && noexcept(swap(::std::declval(), ::std::declval()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(::std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(::std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using ::std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert(initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert(initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + if (initialized()) { + return contained_val(); + } +#ifdef SOL_NO_EXCEPTIONS + // No abort in constexpr + //std::abort(); + T* noreach = (T*)nullptr; + return *noreach; +#else + throw bad_optional_access("bad optional access") +#endif + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + if (initialized()) { + return contained_val(); + } +#ifdef SOL_NO_EXCEPTIONS + // No abort in constexpr + //std::abort(); + T* noreach = (T*)nullptr; + return *noreach; +#else + throw bad_optional_access("bad optional access") +#endif + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + if (initialized()) { + return std::move(contained_val()); + } +#ifdef SOL_NO_EXCEPTIONS + // No abort in constexpr + //std::abort(); + T* noreach = (T*)nullptr; + return std::move(*noreach); +#else + throw bad_optional_access("bad optional access") +#endif + + } + +# else + + T* operator ->() { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert(initialized()); + return contained_val(); + } + + constexpr T const& value() const { + if (initialized()) { + return contained_val(); + } +#ifdef SOL_NO_EXCEPTIONS + // No abort in constexpr + //std::abort(); + T* noreach = (T*)nullptr; + return *noreach; +#else + throw bad_optional_access("bad optional access") +#endif + } + + T& value() { + if (initialized()) { + return contained_val(); + } +#ifdef SOL_NO_EXCEPTIONS + std::abort(); + T* noreach = (T*)nullptr; + return *noreach; +#else + throw bad_optional_access("bad optional access") +#endif + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# endif + +# else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# endif + + }; + + + template + class optional + { + static_assert(!::std::is_same::value, "bad T"); + static_assert(!::std::is_same::value, "bad T"); + T* ref; + + public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template + auto operator=(U&& rhs) noexcept + -> typename ::std::enable_if + < + ::std::is_same::type, optional>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept + -> typename ::std::enable_if + < + !::std::is_same::type, optional>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + + void swap(optional& rhs) noexcept + { + ::std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + if (ref) { + return *ref; + } +#ifdef SOL_NO_EXCEPTIONS + // Can't abort in constexpr. Lovely. + std::abort(); + T* noreach = (T*)nullptr; + return *noreach; +#else + throw bad_optional_access("bad optional access") +#endif + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + template + constexpr T& value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + }; + + + template + class optional + { + static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); + }; + + + // 20.5.8, Relational operators + template constexpr bool operator==(const optional& x, const optional& y) + { + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; + } + + template constexpr bool operator!=(const optional& x, const optional& y) + { + return !(x == y); + } + + template constexpr bool operator<(const optional& x, const optional& y) + { + return (!y) ? false : (!x) ? true : *x < *y; + } + + template constexpr bool operator>(const optional& x, const optional& y) + { + return (y < x); + } + + template constexpr bool operator<=(const optional& x, const optional& y) + { + return !(y < x); + } + + template constexpr bool operator>=(const optional& x, const optional& y) + { + return !(x < y); + } + + + // 20.5.9, Comparison with nullopt + template constexpr bool operator==(const optional& x, nullopt_t) noexcept + { + return (!x); + } + + template constexpr bool operator==(nullopt_t, const optional& x) noexcept + { + return (!x); + } + + template constexpr bool operator!=(const optional& x, nullopt_t) noexcept + { + return bool(x); + } + + template constexpr bool operator!=(nullopt_t, const optional& x) noexcept + { + return bool(x); + } + + template constexpr bool operator<(const optional&, nullopt_t) noexcept + { + return false; + } + + template constexpr bool operator<(nullopt_t, const optional& x) noexcept + { + return bool(x); + } + + template constexpr bool operator<=(const optional& x, nullopt_t) noexcept + { + return (!x); + } + + template constexpr bool operator<=(nullopt_t, const optional&) noexcept + { + return true; + } + + template constexpr bool operator>(const optional& x, nullopt_t) noexcept + { + return bool(x); + } + + template constexpr bool operator>(nullopt_t, const optional&) noexcept + { + return false; + } + + template constexpr bool operator>=(const optional&, nullopt_t) noexcept + { + return true; + } + + template constexpr bool operator>=(nullopt_t, const optional& x) noexcept + { + return (!x); + } + + + + // 20.5.10, Comparison with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + + // Comparison of optional with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + // Comparison of optional with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + + // 20.5.12, Specialized algorithms + template + void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) { + x.swap(y); + } + + + template + constexpr optional::type> make_optional(T&& v) { + return optional::type>(constexpr_forward(v)); + } + + template + constexpr optional make_optional(::std::reference_wrapper v) { + return optional(v.get()); + } + + +} // namespace + +namespace std +{ + template + struct hash> { + typedef typename hash::result_type result_type; + typedef sol::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? ::std::hash{}(*arg) : result_type{}; + } + }; + + template + struct hash> { + typedef typename hash::result_type result_type; + typedef sol::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? ::std::hash{}(*arg) : result_type{}; + } + }; +} + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif //___SOL_OPTIONAL_HPP___