// The MIT License (MIT) // Copyright (c) 2013-2021 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 <sol/version.hpp> #include <sol/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> #include <cstdlib> #include <optional> #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 destroyion 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 base_t = optional_operations_base<T>; using base_t::base_t; optional_copy_base() = default; optional_copy_base(const optional_copy_base& rhs) : base_t() { 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 using nullopt_t = std::nullopt_t; /// \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 /// ``` using std::nullopt; /// @brief An exception for when an optional is accessed through specific methods while it is not engaged. class bad_optional_access : public std::exception { public: /// @brief Default-constructs an optional exception. bad_optional_access() = default; /// @brief Returns a pointer to a null-terminated string containing the reason for the exception. const char* what() const noexcept override { 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n auto 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> \n auto 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> \n auto 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> \n auto 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> \n constexpr 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 // sol2 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> \n T& 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; #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } /// \group value /// \synopsis constexpr const T &value() const; SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& { if (has_value()) return this->m_value; #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } /// \exclude SOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && { if (has_value()) return std::move(this->m_value); #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } #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); #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } #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> \n void 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n constexpr 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> \n auto 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> \n auto 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> \n auto 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> \n auto 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; #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } /// \group value /// \synopsis constexpr const T &value() const; SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const { if (has_value()) return *m_value; #if SOL_IS_OFF(SOL_EXCEPTIONS_I_) std::abort(); #else throw bad_optional_access(); #endif // No exceptions allowed } /// \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