diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-17 00:21:48 +0100 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-17 22:29:50 +0100 |
commit | a141c401f78467bc15f62882fca5d55a007cacbb (patch) | |
tree | 908ac71a8640f78f45d22c6808c5fa6e373000fa /asl/option.hpp | |
parent | cb77cbe9ce4cddad6a460aa190ff70f0c13e4703 (diff) |
Reorganize everything
Diffstat (limited to 'asl/option.hpp')
-rw-r--r-- | asl/option.hpp | 509 |
1 files changed, 0 insertions, 509 deletions
diff --git a/asl/option.hpp b/asl/option.hpp deleted file mode 100644 index d12d4ce..0000000 --- a/asl/option.hpp +++ /dev/null @@ -1,509 +0,0 @@ -#pragma once - -#include "asl/assert.hpp" -#include "asl/meta.hpp" -#include "asl/maybe_uninit.hpp" -#include "asl/functional.hpp" -#include "asl/annotations.hpp" -#include "asl/hash.hpp" - -namespace asl -{ - -struct nullopt_t {}; -static constexpr nullopt_t nullopt{}; - -// @Todo(option) Reference -// @Todo(option) Function -// @Todo(option) Arrays - -template<is_object T> class option; - -namespace option_internal -{ - -template<typename T, typename U> -concept not_constructible_from_option = - !constructible_from<T, option<U>&> && - !constructible_from<T, const option<U>&> && - !constructible_from<T, option<U>&&> && - !constructible_from<T, const option<U>&&>; - -template<typename T, typename U> -concept not_assignable_from_option = - !assignable_from<T&, option<U>&> && - !assignable_from<T&, const option<U>&> && - !assignable_from<T&, option<U>&&> && - !assignable_from<T&, const option<U>&&>; - -template<typename T, typename U> -concept not_constructible_assignable_from_option = - not_constructible_from_option<T, U> && - not_assignable_from_option<T, U>; - -} // namespace option_internal - -template<typename T> -concept is_option = requires -{ - typename T::type; - requires same_as<un_cvref_t<T>, option<typename T::type>>; -}; - -template<is_object T> -class option -{ - static constexpr bool kHasNiche = has_niche<T>; - - using HasValueMarker = select_t<kHasNiche, empty, bool>; - - maybe_uninit<T> m_payload{}; - ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value{}; - - template<is_object U> - friend class option; - - template<typename... Args> - constexpr void construct(Args&&... args) - { - ASL_ASSERT(!has_value()); - - if constexpr (!kHasNiche) - { - m_payload.construct_unsafe(ASL_FWD(args)...); - m_has_value = true; - } - else - { - if constexpr (move_assignable<T>) - { - m_payload.assign_unsafe(ASL_MOVE(T{ASL_FWD(args)...})); - } - else - { - m_payload.destroy_unsafe(); - m_payload.construct_unsafe(ASL_FWD(args)...); - } - } - } - - template<typename U> - constexpr void assign(U&& arg) - { - ASL_ASSERT(has_value()); - m_payload.assign_unsafe(ASL_FWD(arg)); - } - -public: - using type = T; - - constexpr option() : option{nullopt} {} - - // NOLINTNEXTLINE(*-explicit-conversions) - constexpr option(nullopt_t) requires (!kHasNiche) {} - - // NOLINTNEXTLINE(*-explicit-conversions) - constexpr option(nullopt_t) requires kHasNiche : m_payload{in_place, niche_t{}} {} - - template<typename U = T> - constexpr explicit (!convertible_from<T, U&&>) - option(U&& value) - requires ( - kHasNiche && - constructible_from<T, U&&> && - !same_as<un_cvref_t<U>, option> - ) - : m_payload{in_place, ASL_FWD(value)} - {} - - template<typename U = T> - constexpr explicit (!convertible_from<T, U&&>) - option(U&& value) - requires ( - !kHasNiche && - constructible_from<T, U&&> && - !is_option<U> - ) - : m_payload{in_place, ASL_FWD(value)} - , m_has_value{true} - {} - - constexpr option(const option& other) requires trivially_copy_constructible<T> = default; - constexpr option(const option& other) requires (!copy_constructible<T>) = delete; - - constexpr option(const option& other) - requires copy_constructible<T> && (!trivially_copy_constructible<T>) - : option{nullopt} - { - if (other.has_value()) - { - construct(other.m_payload.as_init_unsafe()); - } - } - - constexpr option(option&& other) requires trivially_move_constructible<T> = default; - constexpr option(option&& other) requires (!move_constructible<T>) = delete; - - constexpr option(option&& other) - requires move_constructible<T> && (!trivially_move_constructible<T>) - : option{nullopt} - { - if (other.has_value()) - { - construct(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - } - - template<typename U> - constexpr explicit (!convertible_from<T, const U&>) - option(const option<U>& other) - requires ( - constructible_from<T, const U&> && - option_internal::not_constructible_from_option<T, U> - ) - : option{nullopt} - { - if (other.has_value()) - { - construct(other.m_payload.as_init_unsafe()); - } - } - - template<typename U> - constexpr explicit (!convertible_from<T, U&&>) - option(option<U>&& other) - requires ( - constructible_from<T, U&&> && - option_internal::not_constructible_from_option<T, U> - ) - : option{nullopt} - { - if (other.has_value()) - { - construct(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - } - - constexpr option& operator=(nullopt_t) & - { - reset(); - return *this; - } - - template<typename U = T> - constexpr option& operator=(U&& value) & - requires ( - assignable_from<T&, U&&> && - constructible_from<T, U&&> && - !is_option<U> - ) - { - if (has_value()) - { - assign(ASL_FWD(value)); - } - else - { - construct(ASL_FWD(value)); - } - - return *this; - } - - constexpr option& operator=(const option& other) & - requires (!copy_assignable<T>) = delete; - - constexpr option& operator=(const option& other) & - requires trivially_copy_assignable<T> = default; - - constexpr option& operator=(const option& other) & - requires copy_assignable<T> && (!trivially_copy_constructible<T>) - { - if (&other == this) { return *this; } - - if (other.has_value()) - { - if (has_value()) - { - assign(other.m_payload.as_init_unsafe()); - } - else - { - construct(other.m_payload.as_init_unsafe()); - } - } - else if (has_value()) - { - reset(); - } - - return *this; - } - - constexpr option& operator=(option&& other) & - requires (!move_assignable<T>) = delete; - - constexpr option& operator=(option&& other) & - requires trivially_move_assignable<T> = default; - - constexpr option& operator=(option&& other) & - requires move_assignable<T> && (!trivially_move_constructible<T>) - { - if (&other == this) { return *this; } - - if (other.has_value()) - { - if (has_value()) - { - assign(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - else - { - construct(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - } - else if (has_value()) - { - reset(); - } - - return *this; - } - - template<typename U = T> - constexpr option& operator=(const option<U>& other) & - requires ( - constructible_from<T, const U&> && - assignable_from<T&, const U&> && - option_internal::not_constructible_assignable_from_option<T, U> - ) - { - if (other.has_value()) - { - if (has_value()) - { - assign(other.m_payload.as_init_unsafe()); - } - else - { - construct(other.m_payload.as_init_unsafe()); - } - } - else if (has_value()) - { - reset(); - } - - return *this; - } - - template<typename U = T> - constexpr option& operator=(option<U>&& other) & - requires ( - constructible_from<T, U&&> && - assignable_from<T&, U&&> && - option_internal::not_constructible_assignable_from_option<T, U> - ) - { - if (other.has_value()) - { - if (has_value()) - { - assign(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - else - { - construct(ASL_MOVE(other.m_payload.as_init_unsafe())); - } - } - else if (has_value()) - { - reset(); - } - - return *this; - } - - constexpr ~option() requires trivially_destructible<T> = default; - constexpr ~option() requires (!trivially_destructible<T>) - { - reset(); - } - - constexpr void reset() - { - if (!has_value()) { return; } - - if constexpr (kHasNiche) - { - if constexpr (move_assignable<T>) - { - m_payload.assign_unsafe(ASL_MOVE(T{niche_t{}})); - } - else - { - m_payload.destroy_unsafe(); - m_payload.construct_unsafe(niche_t{}); - } - } - else - { - m_has_value = false; - m_payload.destroy_unsafe(); - } - } - - constexpr bool has_value() const - { - if constexpr (kHasNiche) - { - return m_payload.as_init_unsafe() != niche_t{}; - } - else - { - return m_has_value; - } - } - - // @Todo(C++23) Deducing this - constexpr T&& value() && - { - ASL_ASSERT_RELEASE(has_value()); - return ASL_MOVE(m_payload).as_init_unsafe(); - } - - constexpr T& value() & - { - ASL_ASSERT_RELEASE(has_value()); - return m_payload.as_init_unsafe(); - } - - constexpr const T& value() const& - { - ASL_ASSERT_RELEASE(has_value()); - return m_payload.as_init_unsafe(); - } - - template<typename U> - constexpr T value_or(U&& other_value) const& - requires copy_constructible<T> && convertible_from<T, U&&> - { - return has_value() ? value() : static_cast<T>(ASL_FWD(other_value)); - } - - template<typename U> - constexpr T value_or(U&& other_value) && - requires move_constructible<T> && convertible_from<T, U&&> - { - return has_value() ? ASL_MOVE(value()) : static_cast<T>(ASL_FWD(other_value)); - } - - template<typename... Args> - constexpr T& emplace(Args&&... args) & - requires constructible_from<T, Args&&...> - { - if (has_value()) { reset(); } - construct(ASL_FWD(args)...); - return value(); - } - - template<typename F> - constexpr auto and_then(F&& f) & - requires is_option<result_of_t<F(T&)>> - { - if (has_value()) - { - return invoke(ASL_FWD(f), value()); - } - return un_cvref_t<result_of_t<F(T&)>>{}; - } - - template<typename F> - constexpr auto and_then(F&& f) const& - requires is_option<result_of_t<F(const T&)>> - { - if (has_value()) - { - return invoke(ASL_FWD(f), value()); - } - return un_cvref_t<result_of_t<F(const T&)>>{}; - } - - template<typename F> - constexpr auto and_then(F&& f) && - requires is_option<result_of_t<F(T)>> - { - if (has_value()) - { - return invoke(ASL_FWD(f), ASL_MOVE(value())); - } - return un_cvref_t<result_of_t<F(T)>>{}; - } - - template<typename F> - constexpr auto transform(F&& f) & - { - using U = un_cvref_t<result_of_t<F(T&)>>; - if (has_value()) - { - return option<U>{ invoke(ASL_FWD(f), value()) }; - } - return option<U>{}; - } - - template<typename F> - constexpr auto transform(F&& f) const& - { - using U = un_cvref_t<result_of_t<F(const T&)>>; - if (has_value()) - { - return option<U>{ invoke(ASL_FWD(f), value()) }; - } - return option<U>{}; - } - - template<typename F> - constexpr auto transform(F&& f) && - { - using U = un_cvref_t<result_of_t<F(T)>>; - if (has_value()) - { - return option<U>{ invoke(ASL_FWD(f), ASL_MOVE(value())) }; - } - return option<U>{}; - } - - template<typename F> - constexpr option or_else(F&& f) const& - requires same_as<un_cvref_t<result_of_t<F()>>, option> - { - return has_value() ? *this : invoke(ASL_FWD(f)); - } - - template<typename F> - constexpr option or_else(F&& f) && - requires same_as<un_cvref_t<result_of_t<F()>>, option> - { - return has_value() ? ASL_MOVE(*this) : invoke(ASL_FWD(f)); - } - - template<typename H> - requires (!uniquely_represented<option>) && hashable<T> - friend H AslHashValue(H h, const option& opt) - { - if (!opt.has_value()) - { - return H::combine(ASL_MOVE(h), 0); - } - return H::combine(ASL_MOVE(h), 1, opt.value()); - } -}; - -template<typename T> -requires has_niche<T> && uniquely_represented<T> -struct is_uniquely_represented<option<T>> : true_type {}; - -template<typename T> -option(T) -> option<T>; - -} // namespace asl |