From 6239971ea7421ccbd7a632de180a3046374425d3 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Sun, 21 Jan 2024 00:51:08 +0000 Subject: [PATCH] [+] TartanLlama/optional based optionals because i cant be arsed to finish the minimalistic std replacements --- Include/auROXTL/ThirdParty/LICENSING.txt | 1 + .../ThirdParty/tartanllamaOptional.hpp | 3166 +++++++++++++++++ Include/auROXTL/auOptional.hpp | 17 +- Include/auROXTL/auOptionalEx.hpp | 18 +- 4 files changed, 3199 insertions(+), 3 deletions(-) create mode 100644 Include/auROXTL/ThirdParty/LICENSING.txt create mode 100644 Include/auROXTL/ThirdParty/tartanllamaOptional.hpp diff --git a/Include/auROXTL/ThirdParty/LICENSING.txt b/Include/auROXTL/ThirdParty/LICENSING.txt new file mode 100644 index 0000000..02c5d3f --- /dev/null +++ b/Include/auROXTL/ThirdParty/LICENSING.txt @@ -0,0 +1 @@ +All software here must be CC0, Unlicense, or similar public domain license. \ No newline at end of file diff --git a/Include/auROXTL/ThirdParty/tartanllamaOptional.hpp b/Include/auROXTL/ThirdParty/tartanllamaOptional.hpp new file mode 100644 index 0000000..ef6a386 --- /dev/null +++ b/Include/auROXTL/ThirdParty/tartanllamaOptional.hpp @@ -0,0 +1,3166 @@ + +/// +// optional - An implementation of std::optional with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at https://tl.tartanllama.xyz/ +// +// 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 +// . +/// + +#ifndef TL_OPTIONAL_HPP +#define TL_OPTIONAL_HPP + +#define TL_OPTIONAL_VERSION_MAJOR 1 +#define TL_OPTIONAL_VERSION_MINOR 1 +#define TL_OPTIONAL_VERSION_PATCH 0 + +#include +#include +#include +#include +#include + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_OPTIONAL_MSVC2015 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_OPTIONAL_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_OPTIONAL_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define 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 TL_OPTIONAL_NO_CONSTRR + +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::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 TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { + namespace detail { + template + struct is_trivially_copy_constructible : std::is_trivially_copy_constructible + { }; + #ifdef _GLIBCXX_VECTOR + template + struct is_trivially_copy_constructible> + : std::is_trivially_copy_constructible + { }; + #endif + } +} +#endif + +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable::value +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value +#else +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible::value +#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable::value +#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value +#endif + +#if __cplusplus > 201103L +#define TL_OPTIONAL_CXX14 +#endif + +// constexpr implies const in C++11, not C++14 +#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ + defined(TL_OPTIONAL_GCC49)) +#define TL_OPTIONAL_11_CONSTEXPR +#else +#define TL_OPTIONAL_11_CONSTEXPR constexpr +#endif + +namespace tl { +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +/// Used to represent an optional with no data; essentially a bool + class monostate + { }; + +/// A tag type to tell optional to construct its value in-place + struct in_place_t + { + explicit in_place_t() = default; + }; + /// A tag to tell optional to construct its value in-place + static constexpr in_place_t in_place{}; +#endif + + template class optional; + + namespace detail { + #ifndef TL_TRAITS_MUTEX + #define TL_TRAITS_MUTEX + // C++14-style aliases for brevity + template using remove_const_t = typename std::remove_const::type; + template + using remove_reference_t = typename std::remove_reference::type; + template using decay_t = typename std::decay::type; + template + using enable_if_t = typename AuEnableIf::type; + template + using conditional_t = typename AuConditional::type; + + // std::conjunction from C++17 + template struct conjunction : AuTrueType + { }; + template struct conjunction : B + { }; + template + struct conjunction + : AuConditional, B>::type + { }; + + #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L + #define TL_TRAITS_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 TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + template struct is_pointer_to_non_const_member_func : AuFalseType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + template + struct is_pointer_to_non_const_member_func : AuTrueType + { }; + + template struct is_const_or_const_ref : AuFalseType + { }; + template struct is_const_or_const_ref : AuTrueType + { }; + template struct is_const_or_const_ref : AuTrueType + { }; + #endif + + // std::invoke from C++17 + // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround + template ::value + &&is_const_or_const_ref::value)>, + #endif + typename = enable_if_t>::value>, + int = 0> + constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::mem_fn(f)(AuForward(args)...))) + -> decltype(std::mem_fn(f)(AuForward(args)...)) + { + return std::mem_fn(f)(AuForward(args)...); + } + + template >::value>> + constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(AuForward(f)(AuForward(args)...))) + -> decltype(AuForward(f)(AuForward(args)...)) + { + return AuForward(f)(AuForward(args)...); + } + + // std::invoke_result from C++17 + template struct invoke_result_impl; + + template + struct invoke_result_impl< + F, decltype(detail::invoke(AuDecalVal(), AuDecalVal()...), void()), + Us...> + { + using type = decltype(detail::invoke(AuDecalVal(), AuDecalVal()...)); + }; + + template + using invoke_result = invoke_result_impl; + + template + using invoke_result_t = typename invoke_result::type; + + #if defined(_MSC_VER) && _MSC_VER <= 1900 + // TODO make a version which works with MSVC 2015 + template struct is_swappable : AuTrueType + { }; + + template struct is_nothrow_swappable : AuTrueType + { }; + #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 tag swap(T &, T &); + template 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 AuFalseType can_swap(...) noexcept(false); + template (), AuDecalVal()))> + AuTrueType can_swap(int) noexcept(noexcept(swap(AuDecalVal(), + AuDecalVal()))); + + template AuFalseType uses_std(...); + template + std::is_same(), AuDecalVal())), tag> + uses_std(int); + + template + struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> + { }; + + template + struct is_std_swap_noexcept : is_std_swap_noexcept + { }; + + template + struct is_adl_swap_noexcept + : std::integral_constant(0))> + { }; + } // namespace swap_adl_tests + + template + struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> + { }; + + template + struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype( + detail::swap_adl_tests::uses_std(0))::value || + is_swappable::value)> + { }; + + template + struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value + &&detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> + { }; + #endif + #endif + + // std::void_t from C++17 + template struct voider + { + using type = void; + }; + template using void_t = typename voider::type; + + // Trait for checking if a type is a tl::optional + template struct is_optional_impl : AuFalseType + { }; + template struct is_optional_impl> : AuTrueType + { }; + template using is_optional = is_optional_impl>; + + // Change void to tl::monostate + template + using fixup_void = conditional_t::value, monostate, U>; + + template > + using get_map_return = optional>>; + + // Check if invoking F for some Us returns void + template struct returns_void_impl; + template + struct returns_void_impl>, U...> + : std::is_void> + { }; + template + using returns_void = returns_void_impl; + + template + using enable_if_ret_void = enable_if_t::value>; + + template + using disable_if_ret_void = enable_if_t::value>; + + template + using enable_forward_value = + detail::enable_if_t::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value>; + + template + using enable_from_other = detail::enable_if_t< + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + + template + using enable_assign_forward = detail::enable_if_t< + !std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value &&std::is_assignable::value>; + + template + using enable_assign_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_assignable::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value && + !std::is_assignable &>::value && + !std::is_assignable &&>::value>; + + // 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 ::value> + struct optional_storage_base + { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), m_has_value(false) + { } + + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(AuForward(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 struct optional_storage_base + { + TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept + : m_dummy(), m_has_value(false) + { } + + template + TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) + : m_value(AuForward(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 struct optional_operations_base : optional_storage_base + { + using optional_storage_base::optional_storage_base; + + void hard_reset() noexcept + { + get().~T(); + this->m_has_value = false; + } + + template void construct(Args &&... args) + { + new (std::addressof(this->m_value)) T(AuForward(args)...); + this->m_has_value = true; + } + + template void assign(Opt &&rhs) + { + if (this->has_value()) + { + if (rhs.has_value()) + { + this->m_value = AuForward(rhs).get(); + } + else + { + this->m_value.~T(); + this->m_has_value = false; + } + } + + else if (rhs.has_value()) + { + construct(AuForward(rhs).get()); + } + } + + bool has_value() const + { + return this->m_has_value; + } + + TL_OPTIONAL_11_CONSTEXPR T &get() & + { + return this->m_value; + } + TL_OPTIONAL_11_CONSTEXPR const T &get() const & + { + return this->m_value; + } + TL_OPTIONAL_11_CONSTEXPR T &&get() && + { + return AuMove(this->m_value); + } + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr const T &&get() const && + { + return AuMove(this->m_value); + } + #endif + }; + + // This class manages conditionally having a trivial copy constructor + // This specialization is for when T is trivially copy constructible + template + struct optional_copy_base : optional_operations_base + { + using optional_operations_base::optional_operations_base; + }; + + // This specialization is for when T is not trivially copy constructible + template + struct optional_copy_base : optional_operations_base + { + using optional_operations_base::optional_operations_base; + + optional_copy_base() = default; + optional_copy_base(const optional_copy_base &rhs) + : optional_operations_base() + { + 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 TL_OPTIONAL_GCC49 + template ::value> + struct optional_move_base : optional_copy_base + { + using optional_copy_base::optional_copy_base; + }; + #else + template struct optional_move_base; + #endif + template struct optional_move_base : optional_copy_base + { + using optional_copy_base::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::value) + { + if (rhs.has_value()) + { + this->construct(AuMove(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 + struct optional_copy_assign_base : optional_move_base + { + using optional_move_base::optional_move_base; + }; + + template + struct optional_copy_assign_base : optional_move_base + { + using optional_move_base::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 TL_OPTIONAL_GCC49 + template ::value + &&std::is_trivially_move_constructible::value + &&std::is_trivially_move_assignable::value> + struct optional_move_assign_base : optional_copy_assign_base + { + using optional_copy_assign_base::optional_copy_assign_base; + }; + #else + template struct optional_move_assign_base; + #endif + + template + struct optional_move_assign_base : optional_copy_assign_base + { + using optional_copy_assign_base::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::value + &&std::is_nothrow_move_assignable::value) + { + this->assign(AuMove(rhs)); + return *this; + } + }; + + // optional_delete_ctor_base will conditionally delete copy and move + // constructors depending on whether T is copy/move constructible + template ::value, + bool EnableMove = std::is_move_constructible::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 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 = delete; + optional_delete_ctor_base & + operator=(const optional_delete_ctor_base &) = default; + optional_delete_ctor_base & + operator=(optional_delete_ctor_base &&) noexcept = default; + }; + + template struct optional_delete_ctor_base + { + 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 struct optional_delete_ctor_base + { + 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 ::value && + std::is_copy_assignable::value), + bool EnableMove = (std::is_move_constructible::value && + std::is_move_assignable::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 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 = delete; + }; + + template 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 &) = delete; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = default; + }; + + template 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 &) = delete; + optional_delete_assign_base & + operator=(optional_delete_assign_base &&) noexcept = delete; + }; + + } // namespace detail + + /// 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 + { } + }; + /// Represents 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 optional : private detail::optional_move_assign_base, + private detail::optional_delete_ctor_base, + private detail::optional_delete_assign_base + { + using base = detail::optional_move_assign_base; + + static_assert(!std::is_same::value, + "instantiation of optional with in_place_t is ill-formed"); + static_assert(!std::is_same, 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(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + + template constexpr auto and_then(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template constexpr auto and_then(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + #endif + + template TL_OPTIONAL_11_CONSTEXPR auto AndThen(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template TL_OPTIONAL_11_CONSTEXPR auto AndThen(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + + template constexpr auto AndThen(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template constexpr auto AndThen(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + #endif + #else + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + + template + constexpr detail::invoke_result_t and_then(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr detail::invoke_result_t and_then(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + #endif + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t AndThen(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t AndThen(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + + template + constexpr detail::invoke_result_t AndThen(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr detail::invoke_result_t AndThen(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + #endif + #endif + + #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto map(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto map(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto Map(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto Map(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto Map(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto Map(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Map(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Map(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Map(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Map(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + #endif + + #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto transform(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto transform(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + template TL_OPTIONAL_11_CONSTEXPR auto Transform(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto Transform(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto Transform(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto Transform(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) & + { + return optional_map_impl(*this, AuForward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) const & + { + return optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) const && + { + return optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + #endif + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & + { + return has_value() ? *this : AuForward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) const & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & + { + return has_value() ? *this : AuForward(f)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional or_else(F &&f) const && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional or_else(F &&f) const && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + #endif + + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) & + { + return has_value() ? *this : AuForward(f)(); + } + + template * = nullptr> + optional OrElse(F &&f) && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + + template * = nullptr> + optional OrElse(F &&f) const & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) const & + { + return has_value() ? *this : AuForward(f)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional OrElse(F &&f) const && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional OrElse(F &&f) const && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + #endif + + /// Maps the stored value with `f` if there is one, otherwise returns `u`. + template U map_or(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + template U map_or(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + + template U map_or(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template U map_or(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + #endif + + template U MapOr(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + template U MapOr(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + + template U MapOr(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template U MapOr(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + #endif + + /// Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + #endif + + /// Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + #endif + + + /// Returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const + { + using result = optional>; + return has_value() ? result{u} : result { nullopt }; + } + + template + constexpr optional::type> Conjunction(U &&u) const + { + using result = optional>; + return has_value() ? result{u} : result { nullopt }; + } + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & + { + return has_value() ? *this : rhs; + } + + constexpr optional disjunction(const optional &rhs) const & + { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && + { + return has_value() ? AuMove(*this) : rhs; + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(const optional &rhs) const && + { + return has_value() ? AuMove(*this) : rhs; + } + #endif + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & + { + return has_value() ? *this : AuMove(rhs); + } + + constexpr optional disjunction(optional &&rhs) const & + { + return has_value() ? *this : AuMove(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(optional &&rhs) const && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + #endif + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(const optional &rhs) & + { + return has_value() ? *this : rhs; + } + + constexpr optional Disjunction(const optional &rhs) const & + { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(const optional &rhs) && + { + return has_value() ? AuMove(*this) : rhs; + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional Disjunction(const optional &rhs) const && + { + return has_value() ? AuMove(*this) : rhs; + } + #endif + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(optional &&rhs) & + { + return has_value() ? *this : AuMove(rhs); + } + + constexpr optional Disjunction(optional &&rhs) const & + { + return has_value() ? *this : AuMove(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(optional &&rhs) && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional Disjunction(optional &&rhs) const && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + #endif + + /// Takes the value out of the optional, leaving it empty + optional take() + { + optional ret = AuMove(*this); + reset(); + return ret; + } + + /// Takes the value out of the optional, leaving it empty + optional Take() + { + optional ret = AuMove(*this); + reset(); + return ret; + } + + using value_type = T; + + /// Constructs an optional that does not contain a value. + constexpr optional() noexcept = default; + + 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. + 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. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value in-place using the given arguments. + template + constexpr explicit optional( + detail::enable_if_t::value, in_place_t>, + Args &&... args) + : base(in_place, AuForward(args)...) + { } + + template + TL_OPTIONAL_11_CONSTEXPR explicit optional( + detail::enable_if_t &, + Args &&...>::value, + in_place_t>, + std::initializer_list il, Args &&... args) + { + this->construct(il, AuForward(args)...); + } + + /// Constructs the stored value with `u`. + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr optional(U &&u) : base(in_place, AuForward(u)) + { } + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> + constexpr explicit optional(U &&u) : base(in_place, AuForward(u)) + { } + + /// Converting copy constructor. + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + optional(const optional &rhs) + { + if (rhs.has_value()) + { + this->construct(*rhs); + } + } + + template * = nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit optional(const optional &rhs) + { + if (rhs.has_value()) + { + this->construct(*rhs); + } + } + + /// Converting move constructor. + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + optional(optional &&rhs) + { + if (rhs.has_value()) + { + this->construct(AuMove(*rhs)); + } + } + + template < + class U, detail::enable_from_other * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit optional(optional &&rhs) + { + if (rhs.has_value()) + { + this->construct(AuMove(*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. + template * = nullptr> + optional &operator=(U &&u) + { + if (has_value()) + { + this->m_value = AuForward(u); + } + else + { + this->construct(AuForward(u)); + } + + return *this; + } + + /// Converting copy assignment operator. + /// + /// Copies the value from `rhs` if there is one. Otherwise resets the stored + /// value in `*this`. + template * = nullptr> + optional &operator=(const optional &rhs) + { + if (has_value()) + { + if (rhs.has_value()) + { + this->m_value = *rhs; + } + else + { + this->hard_reset(); + } + } + + else 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`. + template * = nullptr> + optional &operator=(optional &&rhs) + { + if (has_value()) + { + if (rhs.has_value()) + { + this->m_value = AuMove(*rhs); + } + else + { + this->hard_reset(); + } + } + + else if (rhs.has_value()) + { + this->construct(AuMove(*rhs)); + } + + return *this; + } + + /// Constructs the value in-place, destroying the current one if there is + /// one. + template T &emplace(Args &&... args) + { + static_assert(std::is_constructible::value, + "T must be constructible with Args"); + + *this = nullopt; + this->construct(AuForward(args)...); + return value(); + } + + template + detail::enable_if_t< + std::is_constructible &, Args &&...>::value, + T &> + emplace(std::initializer_list il, Args &&... args) + { + *this = nullopt; + this->construct(il, AuForward(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::value + &&detail::is_nothrow_swappable::value) + { + using std::swap; + if (has_value()) + { + if (rhs.has_value()) + { + swap(**this, *rhs); + } + else + { + new (std::addressof(rhs.m_value)) T(AuMove(this->m_value)); + this->m_value.T::~T(); + } + } + else if (rhs.has_value()) + { + new (std::addressof(this->m_value)) T(AuMove(rhs.m_value)); + rhs.m_value.T::~T(); + } + swap(this->m_has_value, rhs.m_has_value); + } + + void Swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value) + { + using std::swap; + if (has_value()) + { + if (rhs.has_value()) + { + swap(**this, *rhs); + } + else + { + new (std::addressof(rhs.m_value)) T(AuMove(this->m_value)); + this->m_value.T::~T(); + } + } + else if (rhs.has_value()) + { + new (std::addressof(this->m_value)) T(AuMove(rhs.m_value)); + rhs.m_value.T::~T(); + } + swap(this->m_has_value, rhs.m_has_value); + } + + /// Returns a pointer to the stored value + constexpr const T *operator->() const + { + return std::addressof(this->m_value); + } + + TL_OPTIONAL_11_CONSTEXPR T *operator->() + { + return std::addressof(this->m_value); + } + + /// Returns the stored value + TL_OPTIONAL_11_CONSTEXPR T &operator*() & + { + return this->m_value; + } + + constexpr const T &operator*() const & + { + return this->m_value; + } + + TL_OPTIONAL_11_CONSTEXPR T &&operator*() && + { + return AuMove(this->m_value); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr const T &&operator*() const && + { + return AuMove(this->m_value); + } + #endif + + /// Returns whether or not the optional has a value + constexpr bool has_value() const noexcept + { + return this->m_has_value; + } + + constexpr bool HasValue() const noexcept + { + return this->m_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 + TL_OPTIONAL_11_CONSTEXPR T &value() & + { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR const T &value() const & + { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR T &&value() && + { + if (has_value()) + return AuMove(this->m_value); + throw bad_optional_access(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + TL_OPTIONAL_11_CONSTEXPR const T &&value() const && + { + if (has_value()) + return AuMove(this->m_value); + throw bad_optional_access(); + } + #endif + + TL_OPTIONAL_11_CONSTEXPR T &Value() & + { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR const T &Value() const & + { + if (has_value()) + return this->m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR T &&Value() && + { + if (has_value()) + return AuMove(this->m_value); + throw bad_optional_access(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + TL_OPTIONAL_11_CONSTEXPR const T &&Value() const && + { + if (has_value()) + return AuMove(this->m_value); + throw bad_optional_access(); + } + #endif + + /// Returns the stored value if there is one, otherwise returns `u` + template constexpr T value_or(U &&u) const & + { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && + { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? AuMove(**this) : static_cast(AuForward(u)); + } + + /// Returns the stored value if there is one, otherwise returns `u` + template constexpr T ValueOr(U &&u) const & + { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + template TL_OPTIONAL_11_CONSTEXPR T ValueOr(U &&u) && + { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? AuMove(**this) : static_cast(AuForward(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; + } + } + + void Reset() + { + this->reset(); + } + + AuUInt HashCode() const + { + if (!has_value()) + { + return 0; + } + + return AuHashCode(this->m_value); + } + }; // namespace tl + + /// Compares two optional objects + template + inline constexpr bool operator==(const optional &lhs, + const optional &rhs) + { + return lhs.has_value() == rhs.has_value() && + (!lhs.has_value() || *lhs == *rhs); + } + template + inline constexpr bool operator!=(const optional &lhs, + const optional &rhs) + { + return lhs.has_value() != rhs.has_value() || + (lhs.has_value() && *lhs != *rhs); + } + template + inline constexpr bool operator<(const optional &lhs, + const optional &rhs) + { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); + } + template + inline constexpr bool operator>(const optional &lhs, + const optional &rhs) + { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); + } + template + inline constexpr bool operator<=(const optional &lhs, + const optional &rhs) + { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); + } + template + inline constexpr bool operator>=(const optional &lhs, + const optional &rhs) + { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + } + + /// Compares an optional to a `nullopt` + template + inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept + { + return !lhs.has_value(); + } + template + inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept + { + return !rhs.has_value(); + } + template + inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept + { + return lhs.has_value(); + } + template + inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept + { + return rhs.has_value(); + } + template + inline constexpr bool operator<(const optional &, nullopt_t) noexcept + { + return false; + } + template + inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept + { + return rhs.has_value(); + } + template + inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept + { + return !lhs.has_value(); + } + template + inline constexpr bool operator<=(nullopt_t, const optional &) noexcept + { + return true; + } + template + inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept + { + return lhs.has_value(); + } + template + inline constexpr bool operator>(nullopt_t, const optional &) noexcept + { + return false; + } + template + inline constexpr bool operator>=(const optional &, nullopt_t) noexcept + { + return true; + } + template + inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept + { + return !rhs.has_value(); + } + + /// Compares the optional with a value. + template + inline constexpr bool operator==(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs == rhs : false; + } + template + inline constexpr bool operator==(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs == *rhs : false; + } + template + inline constexpr bool operator!=(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs != rhs : true; + } + template + inline constexpr bool operator!=(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs != *rhs : true; + } + template + inline constexpr bool operator<(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs < rhs : true; + } + template + inline constexpr bool operator<(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs < *rhs : false; + } + template + inline constexpr bool operator<=(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs <= rhs : true; + } + template + inline constexpr bool operator<=(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs <= *rhs : false; + } + template + inline constexpr bool operator>(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs > rhs : false; + } + template + inline constexpr bool operator>(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs > *rhs : true; + } + template + inline constexpr bool operator>=(const optional &lhs, const U &rhs) + { + return lhs.has_value() ? *lhs >= rhs : false; + } + template + inline constexpr bool operator>=(const U &lhs, const optional &rhs) + { + return rhs.has_value() ? lhs >= *rhs : true; + } + + template ::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + void swap(optional &lhs, + optional &rhs) noexcept(noexcept(lhs.swap(rhs))) + { + return lhs.swap(rhs); + } + + namespace detail { + struct i_am_secret + { }; + } // namespace detail + + template ::value, + detail::decay_t, T>> + inline constexpr optional make_optional(U &&v) + { + return optional(AuForward(v)); + } + + template + inline constexpr optional make_optional(Args &&... args) + { + return optional(in_place, AuForward(args)...); + } + template + inline constexpr optional make_optional(std::initializer_list il, + Args &&... args) + { + return optional(in_place, il, AuForward(args)...); + } + +#if __cplusplus >= 201703L + template optional(T) -> optional; +#endif + +/// \exclude + namespace detail { + #ifdef TL_OPTIONAL_CXX14 + template (), + *AuDecalVal())), + detail::enable_if_t::value> * = nullptr> + constexpr auto optional_map_impl(Opt &&opt, F &&f) + { + return opt.has_value() + ? detail::invoke(AuForward(f), *AuForward(opt)) + : optional(nullopt); + } + + template (), + *AuDecalVal())), + detail::enable_if_t::value> * = nullptr> + auto optional_map_impl(Opt &&opt, F &&f) + { + if (opt.has_value()) + { + detail::invoke(AuForward(f), *AuForward(opt)); + return make_optional(monostate {}); + } + + return optional(nullopt); + } + #else + template (), + *AuDecalVal())), + detail::enable_if_t::value> * = nullptr> + + constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional + { + return opt.has_value() + ? detail::invoke(AuForward(f), *AuForward(opt)) + : optional(nullopt); + } + + template (), + *AuDecalVal())), + detail::enable_if_t::value> * = nullptr> + + auto optional_map_impl(Opt &&opt, F &&f) -> optional + { + if (opt.has_value()) + { + detail::invoke(AuForward(f), *AuForward(opt)); + return monostate {}; + } + + return nullopt; + } + #endif + } // namespace detail + + /// Specialization for when `T` is a reference. `optional` acts similarly + /// to a `T*`, but provides more operations and shows intent more clearly. + template class optional + { + 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(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template constexpr auto and_then(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template constexpr auto and_then(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + #endif + #else + /// Carries out some operation which returns an optional on the stored + /// object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + template + constexpr detail::invoke_result_t and_then(F &&f) const & + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), **this) + : result(nullopt); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr detail::invoke_result_t and_then(F &&f) const && + { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : result(nullopt); + } + #endif + #endif + + #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto map(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto map(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + #else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + map(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + #endif + + #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ + !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) + /// Carries out some operation on the stored object if there is one. + template TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto transform(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto transform(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto transform(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto Transform(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template TL_OPTIONAL_11_CONSTEXPR auto Transform(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template constexpr auto Transform(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + template constexpr auto Transform(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + #else + /// Carries out some operation on the stored object if there is one. + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + /// \group map + /// \synopsis template auto transform(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + transform(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + /// \group map + /// \synopsis template auto Transform(F &&f) &&; + template + TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) const & + { + return detail::optional_map_impl(*this, AuForward(f)); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + constexpr decltype(detail::optional_map_impl(AuDecalVal(), + AuDecalVal())) + Transform(F &&f) const && + { + return detail::optional_map_impl(AuMove(*this), AuForward(f)); + } + #endif + #endif + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & + { + return has_value() ? *this : AuForward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + + template * = nullptr> + optional or_else(F &&f) const & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & + { + return has_value() ? *this : AuForward(f)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional or_else(F &&f) const && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional or_else(F &&f) const && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + #endif + + /// Calls `f` if the optional is empty + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) & + { + return has_value() ? *this : AuForward(f)(); + } + + template * = nullptr> + optional OrElse(F &&f) && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + + template * = nullptr> + optional OrElse(F &&f) const & + { + if (has_value()) + return *this; + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional TL_OPTIONAL_11_CONSTEXPR OrElse(F &&f) const & + { + return has_value() ? *this : AuForward(f)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template * = nullptr> + optional OrElse(F &&f) const && + { + if (has_value()) + return AuMove(*this); + + AuForward(f)(); + return nullopt; + } + + template * = nullptr> + optional OrElse(F &&f) const && + { + return has_value() ? AuMove(*this) : AuForward(f)(); + } + #endif + + /// Maps the stored value with `f` if there is one, otherwise returns `u` + template U map_or(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + template U map_or(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + + template U map_or(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template U map_or(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + #endif + template U MapOr(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + template U MapOr(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + + template U MapOr(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template U MapOr(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u); + } + #endif + + /// Maps the stored value with `f` if there is one, otherwise calls + /// `u` and returns the result. + template + detail::invoke_result_t map_or_else(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t map_or_else(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + #endif + + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) const & + { + return has_value() ? detail::invoke(AuForward(f), **this) + : AuForward(u)(); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + template + detail::invoke_result_t MapOrElse(F &&f, U &&u) const && + { + return has_value() ? detail::invoke(AuForward(f), AuMove(**this)) + : AuForward(u)(); + } + #endif + + /// Returns `u` if `*this` has a value, otherwise an empty optional. + template + constexpr optional::type> conjunction(U &&u) const + { + using result = optional>; + return has_value() ? result{u} : result { nullopt }; + } + + template + constexpr optional::type> Conjunction(U &&u) const + { + using result = optional>; + return has_value() ? result{u} : result { nullopt }; + } + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & + { + return has_value() ? *this : rhs; + } + + constexpr optional disjunction(const optional &rhs) const & + { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && + { + return has_value() ? AuMove(*this) : rhs; + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(const optional &rhs) const && + { + return has_value() ? AuMove(*this) : rhs; + } + #endif + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & + { + return has_value() ? *this : AuMove(rhs); + } + + constexpr optional disjunction(optional &&rhs) const & + { + return has_value() ? *this : AuMove(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional disjunction(optional &&rhs) const && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + #endif + + /// Returns `rhs` if `*this` is empty, otherwise the current value. + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(const optional &rhs) & + { + return has_value() ? *this : rhs; + } + + constexpr optional Disjunction(const optional &rhs) const & + { + return has_value() ? *this : rhs; + } + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(const optional &rhs) && + { + return has_value() ? AuMove(*this) : rhs; + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional Disjunction(const optional &rhs) const && + { + return has_value() ? AuMove(*this) : rhs; + } + #endif + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(optional &&rhs) & + { + return has_value() ? *this : AuMove(rhs); + } + + constexpr optional Disjunction(optional &&rhs) const & + { + return has_value() ? *this : AuMove(rhs); + } + + TL_OPTIONAL_11_CONSTEXPR optional Disjunction(optional &&rhs) && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + + #ifndef TL_OPTIONAL_NO_CONSTRR + constexpr optional Disjunction(optional &&rhs) const && + { + return has_value() ? AuMove(*this) : AuMove(rhs); + } + #endif + + + /// Takes the value out of the optional, leaving it empty + optional take() + { + optional ret = AuMove(*this); + reset(); + return ret; + } + + optional Take() + { + optional ret = AuMove(*this); + reset(); + return ret; + } + + using value_type = T &; + + /// Constructs an optional that does not contain a value. + constexpr optional() noexcept : m_value(nullptr) + { } + + 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. + 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. + TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; + + /// Constructs the stored value with `u`. + template >::value> + * = nullptr> + constexpr optional(U &&u) noexcept : m_value(std::addressof(u)) + { + static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); + } + + template + constexpr explicit optional(const optional &rhs) noexcept : 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`. + template >::value> + * = nullptr> + optional &operator=(U &&u) + { + static_assert(std::is_lvalue_reference::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 optional &operator=(const optional &rhs) noexcept + { + m_value = std::addressof(rhs.value()); + return *this; + } + + /// Rebinds this optional to `u`. + template >::value> + * = nullptr> + optional &emplace(U &&u) noexcept + { + return *this = AuForward(u); + } + + void swap(optional &rhs) noexcept + { + AuSwap(m_value, rhs.m_value); + } + + void Swap(optional &rhs) noexcept + { + AuSwap(m_value, rhs.m_value); + } + + /// Returns a pointer to the stored value + constexpr const T *operator->() const noexcept + { + return m_value; + } + + TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept + { + return m_value; + } + +/// Returns the stored value + TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept + { + return *m_value; + } + + constexpr const T &operator*() const noexcept + { + return *m_value; + } + + constexpr bool has_value() const noexcept + { + return m_value != nullptr; + } + + constexpr bool HasValue() const noexcept + { + return m_value != nullptr; + } + + constexpr explicit operator bool() const noexcept + { + return m_value != nullptr; + } + + /// Returns the contained value if there is one, otherwise throws bad_optional_access + TL_OPTIONAL_11_CONSTEXPR T &value() + { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + TL_OPTIONAL_11_CONSTEXPR const T &value() const + { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + + TL_OPTIONAL_11_CONSTEXPR T &Value() + { + if (has_value()) + return *m_value; + throw bad_optional_access(); + } + + 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` + template constexpr T value_or(U &&u) const &noexcept + { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + /// \group value_or + template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && noexcept + { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + /// Returns the stored value if there is one, otherwise returns `u` + template constexpr T ValueOr(U &&u) const &noexcept + { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + /// \group value_or + template TL_OPTIONAL_11_CONSTEXPR T ValueOr(U &&u) && noexcept + { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? **this : static_cast(AuForward(u)); + } + + /// Destroys the stored value if one exists, making the optional empty + void reset() noexcept + { + m_value = nullptr; + } + + void Reset() noexcept + { + m_value = nullptr; + } + + AuUInt HashCode() const + { + return AuHashCode(m_value); + } + + private: + T *m_value; + }; // namespace tl + + + +} // namespace tl + +namespace std +{ + template struct hash> + { + ::std::size_t operator()(const tl::optional &o) const + { + if (!o.has_value()) + return 0; + + return AuHashCode>(*o); + } + }; +} + +#endif diff --git a/Include/auROXTL/auOptional.hpp b/Include/auROXTL/auOptional.hpp index a80f988..7215d12 100644 --- a/Include/auROXTL/auOptional.hpp +++ b/Include/auROXTL/auOptional.hpp @@ -7,8 +7,21 @@ ***/ #pragma once -#if !defined(AURORA_RUNTIME_AU_OPTIONAL) - #define AURORA_RUNTIME_AU_OPTIONAL std::optional + +#if defined(DO_NOT_USEtartanllama) + + #if !defined(AURORA_RUNTIME_AU_OPTIONAL) + #define AURORA_RUNTIME_AU_OPTIONAL std::optional + #endif + +#else + + #include "ThirdParty/tartanllamaOptional.hpp" + + #if !defined(AURORA_RUNTIME_AU_OPTIONAL) + #define AURORA_RUNTIME_AU_OPTIONAL tl::optional + #endif + #endif #if defined(_AURORA_AVOID_DUMB_STL_TYPES) diff --git a/Include/auROXTL/auOptionalEx.hpp b/Include/auROXTL/auOptionalEx.hpp index ab7b951..9c753a5 100644 --- a/Include/auROXTL/auOptionalEx.hpp +++ b/Include/auROXTL/auOptionalEx.hpp @@ -10,6 +10,11 @@ #include "auCopyMoveUtils.hpp" #include "auHashUtils.hpp" +#if defined(DO_NOT_USEtartanllama) + +// @DEPRECATED +// WONT FINISH, probably +// Use forked tartanllama optional instead (aurora should compile with either) template struct AuOptionalEx { @@ -88,4 +93,15 @@ struct AuOptionalEx AuSwap(this->type, ex.type); AuSwap(this->hasValue, ex.hasValue); } -}; \ No newline at end of file + + // TODO finish me +}; + +#else + +#include "ThirdParty/tartanllamaOptional.hpp" + +template +using AuOptionalEx = tl::optional; + +#endif