diff options
Diffstat (limited to 'deps/sol2/include/sol/optional_implementation.hpp')
-rw-r--r-- | deps/sol2/include/sol/optional_implementation.hpp | 2272 |
1 files changed, 2272 insertions, 0 deletions
diff --git a/deps/sol2/include/sol/optional_implementation.hpp b/deps/sol2/include/sol/optional_implementation.hpp new file mode 100644 index 0000000..0d9abc0 --- /dev/null +++ b/deps/sol2/include/sol/optional_implementation.hpp @@ -0,0 +1,2272 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2019 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. + +// Taken from: TartanLlama/optional on Github, because +// holy shit am I done dealing with C++11 constexpr + +/// +// optional - An implementation of std::optional with extensions +// Written in 2017 by Simon Brand (@TartanLlama) +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// <http://creativecommons.org/publicdomain/zero/1.0/>. +/// + +#ifndef SOL_TL_OPTIONAL_HPP +#define SOL_TL_OPTIONAL_HPP + +#include "in_place.hpp" + +#define SOL_TL_OPTIONAL_VERSION_MAJOR 0 +#define SOL_TL_OPTIONAL_VERSION_MINOR 5 + +#include <exception> +#include <functional> +#include <new> +#include <type_traits> +#include <utility> + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define SOL_TL_OPTIONAL_MSVC2015 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__)) +#define SOL_TL_OPTIONAL_GCC55 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions +#define SOL_TL_OPTIONAL_NO_CONSTRR + +// GCC < 5 doesn't support some standard C++11 type traits +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value + +// This one will be different for GCC 5.7 if it's ever supported +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector +// for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace sol { namespace detail { + template <class T> + struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {}; +#ifdef _GLIBCXX_VECTOR + template <class T, class A> + struct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> {}; +#endif +}} // namespace sol::detail +#endif + +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) sol::detail::is_trivially_copy_constructible<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value +#else +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value +#endif + +#if __cplusplus > 201103L +#define SOL_TL_OPTIONAL_CXX14 +#endif + +// constexpr implies const in C++11, not C++14 +#if (__cplusplus == 201103L || defined(SOL_TL_OPTIONAL_MSVC2015) || defined(SOL_TL_OPTIONAL_GCC49)) +/// \exclude +#define SOL_TL_OPTIONAL_11_CONSTEXPR +#else +/// \exclude +#define SOL_TL_OPTIONAL_11_CONSTEXPR constexpr +#endif + +namespace sol { +#ifndef SOL_TL_MONOSTATE_INPLACE_MUTEX +#define SOL_TL_MONOSTATE_INPLACE_MUTEX + /// \brief Used to represent an optional with no data; essentially a bool + class monostate {}; +#endif + + template <class T> + class optional; + + /// \exclude + namespace detail { +#ifndef SOL_TL_TRAITS_MUTEX +#define SOL_TL_TRAITS_MUTEX + // C++14-style aliases for brevity + template <class T> + using remove_const_t = typename std::remove_const<T>::type; + template <class T> + using remove_reference_t = typename std::remove_reference<T>::type; + template <class T> + using decay_t = typename std::decay<T>::type; + template <bool E, class T = void> + using enable_if_t = typename std::enable_if<E, T>::type; + template <bool B, class T, class F> + using conditional_t = typename std::conditional<B, T, F>::type; + + // std::conjunction from C++17 + template <class...> + struct conjunction : std::true_type {}; + template <class B> + struct conjunction<B> : B {}; + template <class B, class... Bs> + struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND + template <class T> + struct is_pointer_to_non_const_member_func : std::false_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type {}; + template <class T, class Ret, class... Args> + struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type {}; + + template <class T> + struct is_const_or_const_ref : std::false_type {}; + template <class T> + struct is_const_or_const_ref<T const&> : std::true_type {}; + template <class T> + struct is_const_or_const_ref<T const> : std::true_type {}; +#endif + + // std::invoke from C++17 + // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround + template <typename Fn, typename... Args, +#ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && is_const_or_const_ref<Args...>::value)>, +#endif + typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0> + constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) + -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { + return std::mem_fn(f)(std::forward<Args>(args)...); + } + + template <typename Fn, typename... Args, typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>> + constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) + -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { + return std::forward<Fn>(f)(std::forward<Args>(args)...); + } + + // std::invoke_result from C++17 + template <class F, class, class... Us> + struct invoke_result_impl; + + template <class F, class... Us> + struct invoke_result_impl<F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), Us...> { + using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...)); + }; + + template <class F, class... Us> + using invoke_result = invoke_result_impl<F, void, Us...>; + + template <class F, class... Us> + using invoke_result_t = typename invoke_result<F, Us...>::type; +#endif + + // std::void_t from C++17 + template <class...> + struct voider { + using type = void; + }; + template <class... Ts> + using void_t = typename voider<Ts...>::type; + + // Trait for checking if a type is a sol::optional + template <class T> + struct is_optional_impl : std::false_type {}; + template <class T> + struct is_optional_impl<optional<T>> : std::true_type {}; + template <class T> + using is_optional = is_optional_impl<decay_t<T>>; + + // Change void to sol::monostate + template <class U> + using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>; + + template <class F, class U, class = invoke_result_t<F, U>> + using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>; + + // Check if invoking F for some Us returns void + template <class F, class = void, class... U> + struct returns_void_impl; + template <class F, class... U> + struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> {}; + template <class F, class... U> + using returns_void = returns_void_impl<F, void, U...>; + + template <class T, class... U> + using enable_if_ret_void = enable_if_t<returns_void<T&&, U...>::value>; + + template <class T, class... U> + using disable_if_ret_void = enable_if_t<!returns_void<T&&, U...>::value>; + + template <class T, class U> + using enable_forward_value = detail::enable_if_t<std::is_constructible<T, U&&>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value + && !std::is_same<optional<T>, detail::decay_t<U>>::value>; + + template <class T, class U, class Other> + using enable_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && !std::is_constructible<T, optional<U>&>::value + && !std::is_constructible<T, optional<U>&&>::value && !std::is_constructible<T, const optional<U>&>::value + && !std::is_constructible<T, const optional<U>&&>::value && !std::is_convertible<optional<U>&, T>::value + && !std::is_convertible<optional<U>&&, T>::value && !std::is_convertible<const optional<U>&, T>::value + && !std::is_convertible<const optional<U>&&, T>::value>; + + template <class T, class U> + using enable_assign_forward = detail::enable_if_t<!std::is_same<optional<T>, detail::decay_t<U>>::value + && !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value && std::is_constructible<T, U>::value + && std::is_assignable<T&, U>::value>; + + template <class T, class U, class Other> + using enable_assign_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && std::is_assignable<T&, Other>::value + && !std::is_constructible<T, optional<U>&>::value && !std::is_constructible<T, optional<U>&&>::value + && !std::is_constructible<T, const optional<U>&>::value && !std::is_constructible<T, const optional<U>&&>::value + && !std::is_convertible<optional<U>&, T>::value && !std::is_convertible<optional<U>&&, T>::value + && !std::is_convertible<const optional<U>&, T>::value && !std::is_convertible<const optional<U>&&, T>::value + && !std::is_assignable<T&, optional<U>&>::value && !std::is_assignable<T&, optional<U>&&>::value + && !std::is_assignable<T&, const optional<U>&>::value && !std::is_assignable<T&, const optional<U>&&>::value>; + +#ifdef _MSC_VER + // TODO make a version which works with MSVC + template <class T, class U = T> + struct is_swappable : std::true_type {}; + + template <class T, class U = T> + struct is_nothrow_swappable : std::true_type {}; +#else + // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept + namespace swap_adl_tests { + // if swap ADL finds this then it would call std::swap otherwise (same + // signature) + struct tag {}; + + template <class T> + tag swap(T&, T&); + template <class T, std::size_t N> + tag swap(T (&a)[N], T (&b)[N]); + + // helper functions to test if an unqualified swap is possible, and if it + // becomes std::swap + template <class, class> + std::false_type can_swap(...) noexcept(false); + template <class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))> + std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(), std::declval<U&>()))); + + template <class, class> + std::false_type uses_std(...); + template <class T, class U> + std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int); + + template <class T> + struct is_std_swap_noexcept + : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> {}; + + template <class T, std::size_t N> + struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {}; + + template <class T, class U> + struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {}; + } // namespace swap_adl_tests + + template <class T, class U = T> + struct is_swappable : std::integral_constant<bool, + decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value + && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value + || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> {}; + + template <class T, std::size_t N> + struct is_swappable<T[N], T[N]> : std::integral_constant<bool, + decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value + && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> {}; + + template <class T, class U = T> + struct is_nothrow_swappable + : std::integral_constant<bool, + is_swappable<T, U>::value + && ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value) + || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> {}; +#endif + + // The storage base manages the actual storage, and correctly propagates + // trivial destruction from T. This case is for when T is not trivially + // destructible. + template <class T, bool = ::std::is_trivially_destructible<T>::value> + struct optional_storage_base { + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) { + } + + template <class... U> + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) { + } + + ~optional_storage_base() { + if (m_has_value) { + m_value.~T(); + m_has_value = false; + } + } + + struct dummy {}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value; + }; + + // This case is for when T is trivially destructible. + template <class T> + struct optional_storage_base<T, true> { + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) { + } + + template <class... U> + SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) { + } + + // No destructor, so this class is trivially destructible + + struct dummy {}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value = false; + }; + + // This base class provides some handy member functions which can be used in + // further derived classes + template <class T> + struct optional_operations_base : optional_storage_base<T> { + using optional_storage_base<T>::optional_storage_base; + + void hard_reset() noexcept { + get().~T(); + this->m_has_value = false; + } + + template <class... Args> + void construct(Args&&... args) noexcept { + new (std::addressof(this->m_value)) T(std::forward<Args>(args)...); + this->m_has_value = true; + } + + template <class Opt> + void assign(Opt&& rhs) { + if (this->has_value()) { + if (rhs.has_value()) { + this->m_value = std::forward<Opt>(rhs).get(); + } + else { + this->m_value.~T(); + this->m_has_value = false; + } + } + + else if (rhs.has_value()) { + construct(std::forward<Opt>(rhs).get()); + } + } + + bool has_value() const { + return this->m_has_value; + } + + SOL_TL_OPTIONAL_11_CONSTEXPR T& get() & { + return this->m_value; + } + SOL_TL_OPTIONAL_11_CONSTEXPR const T& get() const& { + return this->m_value; + } + SOL_TL_OPTIONAL_11_CONSTEXPR T&& get() && { + return std::move(this->m_value); + } +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + constexpr const T&& get() const&& { + return std::move(this->m_value); + } +#endif + }; + + // This class manages conditionally having a trivial copy constructor + // This specialization is for when T is trivially copy constructible + template <class T, bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)> + struct optional_copy_base : optional_operations_base<T> { + using optional_operations_base<T>::optional_operations_base; + }; + + // This specialization is for when T is not trivially copy constructible + template <class T> + struct optional_copy_base<T, false> : optional_operations_base<T> { + using optional_operations_base<T>::optional_operations_base; + + optional_copy_base() = default; + optional_copy_base(const optional_copy_base& rhs) { + if (rhs.has_value()) { + this->construct(rhs.get()); + } + else { + this->m_has_value = false; + } + } + + optional_copy_base(optional_copy_base&& rhs) = default; + optional_copy_base& operator=(const optional_copy_base& rhs) = default; + optional_copy_base& operator=(optional_copy_base&& rhs) = default; + }; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef SOL_TL_OPTIONAL_GCC49 + template <class T, bool = std::is_trivially_move_constructible<T>::value> + struct optional_move_base : optional_copy_base<T> { + using optional_copy_base<T>::optional_copy_base; + }; +#else + template <class T, bool = false> + struct optional_move_base; +#endif + template <class T> + struct optional_move_base<T, false> : optional_copy_base<T> { + using optional_copy_base<T>::optional_copy_base; + + optional_move_base() = default; + optional_move_base(const optional_move_base& rhs) = default; + + optional_move_base(optional_move_base&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) { + if (rhs.has_value()) { + this->construct(std::move(rhs.get())); + } + else { + this->m_has_value = false; + } + } + optional_move_base& operator=(const optional_move_base& rhs) = default; + optional_move_base& operator=(optional_move_base&& rhs) = default; + }; + + // This class manages conditionally having a trivial copy assignment operator + template <class T, + bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) && SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) && SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)> + struct optional_copy_assign_base : optional_move_base<T> { + using optional_move_base<T>::optional_move_base; + }; + + template <class T> + struct optional_copy_assign_base<T, false> : optional_move_base<T> { + using optional_move_base<T>::optional_move_base; + + optional_copy_assign_base() = default; + optional_copy_assign_base(const optional_copy_assign_base& rhs) = default; + + optional_copy_assign_base(optional_copy_assign_base&& rhs) = default; + optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) { + this->assign(rhs); + return *this; + } + optional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default; + }; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef SOL_TL_OPTIONAL_GCC49 + template <class T, + bool = std::is_trivially_destructible<T>::value&& std::is_trivially_move_constructible<T>::value&& std::is_trivially_move_assignable<T>::value> + struct optional_move_assign_base : optional_copy_assign_base<T> { + using optional_copy_assign_base<T>::optional_copy_assign_base; + }; +#else + template <class T, bool = false> + struct optional_move_assign_base; +#endif + + template <class T> + struct optional_move_assign_base<T, false> : optional_copy_assign_base<T> { + using optional_copy_assign_base<T>::optional_copy_assign_base; + + optional_move_assign_base() = default; + optional_move_assign_base(const optional_move_assign_base& rhs) = default; + + optional_move_assign_base(optional_move_assign_base&& rhs) = default; + + optional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default; + + optional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept( + std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_assignable<T>::value) { + this->assign(std::move(rhs)); + return *this; + } + }; + + // optional_delete_ctor_base will conditionally delete copy and move + // constructors depending on whether T is copy/move constructible + template <class T, bool EnableCopy = std::is_copy_constructible<T>::value, bool EnableMove = std::is_move_constructible<T>::value> + struct optional_delete_ctor_base { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, true, false> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, false, true> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_ctor_base<T, false, false> { + optional_delete_ctor_base() = default; + optional_delete_ctor_base(const optional_delete_ctor_base&) = delete; + optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete; + optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default; + optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default; + }; + + // optional_delete_assign_base will conditionally delete copy and move + // constructors depending on whether T is copy/move constructible + assignable + template <class T, bool EnableCopy = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value), + bool EnableMove = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)> + struct optional_delete_assign_base { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_assign_base<T, true, false> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete; + }; + + template <class T> + struct optional_delete_assign_base<T, false, true> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default; + }; + + template <class T> + struct optional_delete_assign_base<T, false, false> { + optional_delete_assign_base() = default; + optional_delete_assign_base(const optional_delete_assign_base&) = default; + optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default; + optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete; + optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete; + }; + + } // namespace detail + + /// \brief A tag type to represent an empty optional + struct nullopt_t { + struct do_not_use {}; + constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept { + } + }; + /// \brief Represents an empty optional + /// \synopsis static constexpr nullopt_t nullopt; + /// + /// *Examples*: + /// ``` + /// sol::optional<int> a = sol::nullopt; + /// void foo (sol::optional<int>); + /// foo(sol::nullopt); //pass an empty optional + /// ``` + static constexpr nullopt_t nullopt{ nullopt_t::do_not_use{}, nullopt_t::do_not_use{} }; + + class bad_optional_access : public std::exception { + public: + bad_optional_access() = default; + const char* what() const noexcept { + return "Optional has no value"; + } + }; + + /// An optional object is an object that contains the storage for another + /// object and manages the lifetime of this contained object, if any. The + /// contained object may be initialized after the optional object has been + /// initialized, and may be destroyed before the optional object has been + /// destroyed. The initialization state of the contained object is tracked by + /// the optional object. + template <class T> + class optional : private detail::optional_move_assign_base<T>, + private detail::optional_delete_ctor_base<T>, + private detail::optional_delete_assign_base<T> { + using base = detail::optional_move_assign_base<T>; + + static_assert(!std::is_same<T, in_place_t>::value, "instantiation of optional with in_place_t is ill-formed"); + static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value, "instantiation of optional with nullopt_t is ill-formed"); + + public: +// The different versions for C++14 and 11 are needed because deduced return +// types are not SFINAE-safe. This provides better support for things like +// generic lambdas. C.f. +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + template <class F> + constexpr auto and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + template <class F> + constexpr auto and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } +#endif +#else + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise the return value of + /// `std::invoke(std::forward<F>(f), value())` is returned. + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&&> and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + template <class F> + constexpr detail::invoke_result_t<F, const T&&> and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt); + } +#endif +#endif + +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&; + template <class F> + constexpr auto map(F&& f) const& { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&&; + template <class F> + constexpr auto map(F&& f) const&& { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & { + return optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&; + template <class F> + constexpr decltype(optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& { + return optional_map_impl(*this, std::forward<F>(f)); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&&; + template <class F> + constexpr decltype(optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& { + return optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t<F>` must be void or convertible to + /// `optional<T>`. + /// \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. + /// + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + return has_value() ? *this : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &&; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) && { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) const &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const& { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { + return has_value() ? *this : std::forward<F>(f)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward<U>(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// const &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// const &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template <class U> + constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const { + using result = optional<detail::decay_t<U>>; + return has_value() ? result{ u } : result{ nullopt }; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const& { + return has_value() ? *this : rhs; + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const&& { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const& { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const&& { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const& { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const&& { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept = default; + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept { + } + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; + + /// Constructs the stored value in-place using the given arguments. + /// \group in_place + /// \synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args); + template <class... Args> + constexpr explicit optional(detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, Args&&... args) + : base(in_place, std::forward<Args>(args)...) { + } + + /// \group in_place + /// \synopsis template <class U, class... Args>\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args); + template <class U, class... Args> + SOL_TL_OPTIONAL_11_CONSTEXPR explicit optional(detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>, + std::initializer_list<U> il, Args&&... args) { + this->construct(il, std::forward<Args>(args)...); + } + +#if 0 // SOL_MODIFICATION + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + template <class U = T, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr> + constexpr optional(U&& u) : base(in_place, std::forward<U>(u)) { + } + + /// \exclude + template <class U = T, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr> + constexpr explicit optional(U&& u) : base(in_place, std::forward<U>(u)) { + } +#else + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + constexpr optional(T&& u) : base(in_place, std::move(u)) { + } + + /// \exclude + constexpr optional(const T& u) : base(in_place, u) { + } +#endif // sol3 modification + + /// Converting copy constructor. + /// \synopsis template <class U> optional(const optional<U> &rhs); + template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr> + optional(const optional<U>& rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + /// \exclude + template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr> + explicit optional(const optional<U>& rhs) { + if (rhs.has_value()) { + this->construct(*rhs); + } + } + + /// Converting move constructor. + /// \synopsis template <class U> optional(optional<U> &&rhs); + template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr> + optional(optional<U>&& rhs) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + } + + /// \exclude + template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr> + explicit optional(optional<U>&& rhs) { + this->construct(std::move(*rhs)); + } + + /// Destroys the stored value if there is one. + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional& operator=(nullopt_t) noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + + return *this; + } + + /// Copy assignment. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional& operator=(const optional& rhs) = default; + + /// Move assignment. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + optional& operator=(optional&& rhs) = default; + + /// Assigns the stored value from `u`, destroying the old value if there was + /// one. + /// \synopsis optional &operator=(U &&u); + template <class U = T, detail::enable_assign_forward<T, U>* = nullptr> + optional& operator=(U&& u) { + if (has_value()) { + this->m_value = std::forward<U>(u); + } + else { + this->construct(std::forward<U>(u)); + } + + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(const optional<U> & rhs); + template <class U, detail::enable_assign_from_other<T, U, const U&>* = nullptr> + optional& operator=(const optional<U>& rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = *rhs; + } + else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(*rhs); + } + + return *this; + } + + // TODO check exception guarantee + /// Converting move assignment operator. + /// + /// Moves the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + /// \synopsis optional &operator=(optional<U> && rhs); + template <class U, detail::enable_assign_from_other<T, U, U>* = nullptr> + optional& operator=(optional<U>&& rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(*rhs); + } + else { + this->hard_reset(); + } + } + + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } + + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + /// \group emplace + template <class... Args> + T& emplace(Args&&... args) { + static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward<Args>(args)...); + return value(); + } + + /// \group emplace + /// \synopsis template <class U, class... Args>\nT& emplace(std::initializer_list<U> il, Args &&... args); + template <class U, class... Args> + detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> emplace(std::initializer_list<U> il, Args&&... args) { + *this = nullopt; + this->construct(il, std::forward<Args>(args)...); + return value(); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&& detail::is_nothrow_swappable<T>::value) { + if (has_value()) { + if (rhs.has_value()) { + using std::swap; + swap(**this, *rhs); + } + else { + new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); + this->m_value.T::~T(); + } + } + else if (rhs.has_value()) { + new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); + rhs.m_value.T::~T(); + } + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T* operator->() const { + return std::addressof(this->m_value); + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() { + return std::addressof(this->m_value); + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() & { + return this->m_value; + } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T& operator*() const& { + return this->m_value; + } + + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR T&& operator*() && { + return std::move(this->m_value); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + constexpr const T&& operator*() const&& { + return std::move(this->m_value); + } +#endif + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { + return this->m_has_value; + } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return this->m_has_value; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// \synopsis constexpr T &value(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& value() & { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + /// \group value + /// \synopsis constexpr const T &value() const; + SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && { + if (has_value()) + return std::move(this->m_value); + throw bad_optional_access(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + SOL_TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& { + if (has_value()) + return std::move(this->m_value); + throw bad_optional_access(); + } +#endif + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template <class U> + constexpr T value_or(U&& u) const& { + static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast<T>(std::forward<U>(u)); + } + + /// \group value_or + template <class U> + SOL_TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && { + static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast<T>(std::forward<U>(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + } + }; // namespace sol + + /// \group relop + /// \brief Compares two optional objects + /// \details If both optionals contain a value, they are compared with `T`s + /// relational operators. Otherwise `lhs` and `rhs` are equal only if they are + /// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` + /// is not. + template <class T, class U> + inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); + } + /// \group relop + template <class T, class U> + inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + } + + /// \group relop_nullopt + /// \brief Compares an optional to a `nullopt` + /// \details Equivalent to comparing the optional to an empty optional + template <class T> + inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept { + return !rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept { + return rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { + return false; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept { + return rhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { + return true; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { + return false; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { + return true; + } + /// \group relop_nullopt + template <class T> + inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept { + return !rhs.has_value(); + } + + /// \group relop_t + /// \brief Compares the optional with a value. + /// \details If the optional has a value, it is compared with the other value + /// using `T`s relational operators. Otherwise, the optional is considered + /// less than the value. + template <class T, class U> + inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs == rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs == *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs != rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs != *rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs < rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs < *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs <= rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs <= *rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs > rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs > *rhs : true; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() ? *lhs >= rhs : false; + } + /// \group relop_t + template <class T, class U> + inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) { + return rhs.has_value() ? lhs >= *rhs : true; + } + + /// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T> &rhs); + template <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr> + void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); + } + + namespace detail { + struct i_am_secret {}; + } // namespace detail + + template <class T = detail::i_am_secret, class U, class Ret = detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, detail::decay_t<U>, T>> + inline constexpr optional<Ret> make_optional(U&& v) { + return optional<Ret>(std::forward<U>(v)); + } + + template <class T, class... Args> + inline constexpr optional<T> make_optional(Args&&... args) { + return optional<T>(in_place, std::forward<Args>(args)...); + } + template <class T, class U, class... Args> + inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) { + return optional<T>(in_place, il, std::forward<Args>(args)...); + } + +#if __cplusplus >= 201703L + template <class T> + optional(T)->optional<T>; +#endif + + /// \exclude + namespace detail { +#ifdef SOL_TL_OPTIONAL_CXX14 + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr> + constexpr auto optional_map_impl(Opt&& opt, F&& f) { + return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt); + } + + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<std::is_void<Ret>::value>* = nullptr> + auto optional_map_impl(Opt&& opt, F&& f) { + if (opt.has_value()) { + detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); + return make_optional(monostate{}); + } + + return optional<monostate>(nullopt); + } +#else + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr> + + constexpr auto optional_map_impl(Opt&& opt, F&& f) -> optional<Ret> { + return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt); + } + + template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())), + detail::enable_if_t<std::is_void<Ret>::value>* = nullptr> + + auto optional_map_impl(Opt&& opt, F&& f) -> optional<monostate> { + if (opt.has_value()) { + detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)); + return monostate{}; + } + + return nullopt; + } +#endif + } // namespace detail + + /// Specialization for when `T` is a reference. `optional<T&>` acts similarly + /// to a `T*`, but provides more operations and shows intent more clearly. + /// + /// *Examples*: + /// + /// ``` + /// int i = 42; + /// sol::optional<int&> o = i; + /// *o == 42; //true + /// i = 12; + /// *o = 12; //true + /// &*o == &i; //true + /// ``` + /// + /// Assignment has rebind semantics rather than assign-through semantics: + /// + /// ``` + /// int j = 8; + /// o = j; + /// + /// &*o == &j; //true + /// ``` + template <class T> + class optional<T&> { + public: +// The different versions for C++14 and 11 are needed because deduced return +// types are not SFINAE-safe. This provides better support for things like +// generic lambdas. C.f. +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + template <class F> + constexpr auto and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + template <class F> + constexpr auto and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } +#endif +#else + /// \group and_then + /// Carries out some operation which returns an optional on the stored + /// object if there is one. \requires `std::invoke(std::forward<F>(f), + /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be + /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a + /// `std::optional<U>`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` + /// is returned. + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) && { + using result = detail::invoke_result_t<F, T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; + template <class F> + constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const&& { + using result = detail::invoke_result_t<F, const T&>; + static_assert(detail::is_optional<result>::value, "F must return an optional"); + + return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt); + } +#endif +#endif + +#if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55) + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&; + template <class F> + constexpr auto map(F&& f) const& { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> constexpr auto map(F &&f) const&&; + template <class F> + constexpr auto map(F&& f) const&& { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#else + /// \brief Carries out some operation on the stored object if there is one. + /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), + /// value())`. Returns a `std::optional<U>`. The return value is empty if + /// `*this` is empty, otherwise an `optional<U>` is constructed from the + /// return value of `std::invoke(std::forward<F>(f), value())` and is + /// returned. + /// + /// \group map + /// \synopsis template <class F> auto map(F &&f) &; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) &&; + template <class F> + SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } + + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&; + template <class F> + constexpr decltype(detail::optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& { + return detail::optional_map_impl(*this, std::forward<F>(f)); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map + /// \synopsis template <class F> auto map(F &&f) const&&; + template <class F> + constexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& { + return detail::optional_map_impl(std::move(*this), std::forward<F>(f)); + } +#endif +#endif + + /// \brief Calls `f` if the optional is empty + /// \requires `std::invoke_result_t<F>` must be void or convertible to + /// `optional<T>`. \effects If `*this` has a value, returns `*this`. + /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns + /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`. + /// + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & { + return has_value() ? *this : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) &&; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) && { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } + + /// \group or_else + /// \synopsis template <class F> optional<T> or_else (F &&f) const &; + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const& { + if (has_value()) + return *this; + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& { + return has_value() ? *this : std::forward<F>(f)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \exclude + template <class F, detail::enable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + if (has_value()) + return std::move(*this); + + std::forward<F>(f)(); + return nullopt; + } + + /// \exclude + template <class F, detail::disable_if_ret_void<F>* = nullptr> + optional<T> or_else(F&& f) const&& { + return has_value() ? std::move(*this) : std::forward<F>(f)(); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise returns + /// `u`. + /// + /// \details If there is a value stored, then `f` is called with `**this` + /// and the value is returned. Otherwise `u` is returned. + /// + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } + + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or + template <class F, class U> + U map_or(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u); + } +#endif + + /// \brief Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + /// + /// \details If there is a value stored, then `f` is + /// called with `**this` and the value is returned. Otherwise + /// `std::forward<U>(u)()` is returned. + /// + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } + + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// const &; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& { + return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)(); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group map_or_else + /// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) + /// const &&; + template <class F, class U> + detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& { + return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)(); + } +#endif + + /// \returns `u` if `*this` has a value, otherwise an empty optional. + template <class U> + constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const { + using result = optional<detail::decay_t<U>>; + return has_value() ? result{ u } : result{ nullopt }; + } + + /// \returns `rhs` if `*this` is empty, otherwise the current value. + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & { + return has_value() ? *this : rhs; + } + + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const& { + return has_value() ? *this : rhs; + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && { + return has_value() ? std::move(*this) : rhs; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(const optional& rhs) const&& { + return has_value() ? std::move(*this) : rhs; + } +#endif + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const& { + return has_value() ? *this : std::move(rhs); + } + + /// \group disjunction + SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && { + return has_value() ? std::move(*this) : std::move(rhs); + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group disjunction + constexpr optional disjunction(optional&& rhs) const&& { + return has_value() ? std::move(*this) : std::move(rhs); + } +#endif + + /// Takes the value out of the optional, leaving it empty + /// \group take + optional take() & { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() const& { + optional ret = *this; + reset(); + return ret; + } + + /// \group take + optional take() && { + optional ret = std::move(*this); + reset(); + return ret; + } + +#ifndef SOL_TL_OPTIONAL_NO_CONSTRR + /// \group take + optional take() const&& { + optional ret = std::move(*this); + reset(); + return ret; + } +#endif + + using value_type = T&; + + /// Constructs an optional that does not contain a value. + /// \group ctor_empty + constexpr optional() noexcept : m_value(nullptr) { + } + + /// \group ctor_empty + constexpr optional(nullopt_t) noexcept : m_value(nullptr) { + } + + /// Copy constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default; + + /// Move constructor + /// + /// If `rhs` contains a value, the stored value is direct-initialized with + /// it. Otherwise, the constructed optional is empty. + SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default; + + /// Constructs the stored value with `u`. + /// \synopsis template <class U=T> constexpr optional(U &&u); + template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr> + constexpr optional(U&& u) : m_value(std::addressof(u)) { + static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); + } + + /// \exclude + template <class U> + constexpr explicit optional(const optional<U>& rhs) : optional(*rhs) { + } + + /// No-op + ~optional() = default; + + /// Assignment to empty. + /// + /// Destroys the current value if there is one. + optional& operator=(nullopt_t) noexcept { + m_value = nullptr; + return *this; + } + + /// Copy assignment. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + optional& operator=(const optional& rhs) = default; + + /// Rebinds this optional to `u`. + /// + /// \requires `U` must be an lvalue reference. + /// \synopsis optional &operator=(U &&u); + template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr> + optional& operator=(U&& u) { + static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue"); + m_value = std::addressof(u); + return *this; + } + + /// Converting copy assignment operator. + /// + /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise + /// resets the stored value in `*this`. + template <class U> + optional& operator=(const optional<U>& rhs) { + m_value = std::addressof(rhs.value()); + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + /// + /// \group emplace + template <class... Args> + T& emplace(Args&&... args) noexcept { + static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args"); + + *this = nullopt; + this->construct(std::forward<Args>(args)...); + } + + /// Swaps this optional with the other. + /// + /// If neither optionals have a value, nothing happens. + /// If both have a value, the values are swapped. + /// If one has a value, it is moved to the other and the movee is left + /// valueless. + void swap(optional& rhs) noexcept { + std::swap(m_value, rhs.m_value); + } + + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer + /// \synopsis constexpr const T *operator->() const; + constexpr const T* operator->() const { + return m_value; + } + + /// \group pointer + /// \synopsis constexpr T *operator->(); + SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() { + return m_value; + } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref + /// \synopsis constexpr T &operator*(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() { + return *m_value; + } + + /// \group deref + /// \synopsis constexpr const T &operator*() const; + constexpr const T& operator*() const { + return *m_value; + } + + /// \returns whether or not the optional has a value + /// \group has_value + constexpr bool has_value() const noexcept { + return m_value != nullptr; + } + + /// \group has_value + constexpr explicit operator bool() const noexcept { + return m_value != nullptr; + } + + /// \returns the contained value if there is one, otherwise throws + /// [bad_optional_access] + /// \group value + /// synopsis constexpr T &value(); + SOL_TL_OPTIONAL_11_CONSTEXPR T& value() { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + /// \group value + /// \synopsis constexpr const T &value() const; + SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or + template <class U> + constexpr T& value_or(U&& u) const { + static_assert(std::is_convertible<U&&, T&>::value, "T must be convertible from U"); + return has_value() ? const_cast<T&>(**this) : static_cast<T&>(std::forward<U>(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept { + m_value = nullptr; + } + + private: + T* m_value; + }; + +} // namespace sol + +namespace std { + // TODO SFINAE + template <class T> + struct hash< ::sol::optional<T> > { + ::std::size_t operator()(const ::sol::optional<T>& o) const { + if (!o.has_value()) + return 0; + + return ::std::hash< ::sol::detail::remove_const_t<T>>()(*o); + } + }; +} // namespace std + +#endif // SOL_TL_OPTIONAL_HPP |