/*
 * Copyright (c) Atmosphère-NX
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
#pragma once
#include 
#include 
#include 
#include 
namespace ams::util {
    namespace impl {
        class NulloptHelper {
            public:
                template
                static consteval T CreateInstance() {
                    return T(T::ConstructionArgument::Token);
                }
        };
        template
        struct OptionalFunction {
            F &m_f;
        };
    }
    struct nullopt_t {
        private:
            friend class impl::NulloptHelper;
            enum class ConstructionArgument {
                Token,
            };
        public:
            consteval nullopt_t(ConstructionArgument) { /* ... */ }
    };
    constexpr inline nullopt_t nullopt = impl::NulloptHelper::CreateInstance();
    namespace impl {
        template
        struct OptionalPayloadBase {
            using StoredType = typename std::remove_const::type;
            struct EmptyType{};
            template::value>
            union StorageType {
                EmptyType m_empty;
                U m_value;
                constexpr ALWAYS_INLINE StorageType() : m_empty() { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(in_place_t, Args &&... args) : m_value(std::forward(args)...) { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(std::initializer_list il, Args &&... args) : m_value(il, std::forward(args)...) { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(OptionalFunction f, Arg &&arg) : m_value(std::invoke(std::forward(f.m_f), std::forward(arg))) { /* ... */ }
            };
            template
            union StorageType {
                EmptyType m_empty;
                U m_value;
                constexpr ALWAYS_INLINE StorageType() : m_empty() { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(in_place_t, Args &&... args) : m_value(std::forward(args)...) { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(std::initializer_list il, Args &&... args) : m_value(il, std::forward(args)...) { /* ... */ }
                template
                constexpr ALWAYS_INLINE StorageType(OptionalFunction f, Arg &&arg) : m_value(std::invoke(std::forward(f.m_f), std::forward(arg))) { /* ... */ }
                constexpr ALWAYS_INLINE ~StorageType() { /* ... */ }
            };
            StorageType m_payload;
            bool m_engaged = false;
            constexpr OptionalPayloadBase() = default;
            constexpr ~OptionalPayloadBase() = default;
            template
            constexpr OptionalPayloadBase(in_place_t tag, Args &&... args) : m_payload(tag, std::forward(args)...), m_engaged(true) { /* ... */ }
            template
            constexpr OptionalPayloadBase(std::initializer_list il, Args &&... args) : m_payload(il, std::forward(args)...), m_engaged(true) { /* ... */ }
            constexpr OptionalPayloadBase(bool engaged, const OptionalPayloadBase &rhs) { AMS_UNUSED(engaged); if (rhs.m_engaged) { this->Construct(rhs.Get()); } }
            constexpr OptionalPayloadBase(bool engaged, OptionalPayloadBase &&rhs) { AMS_UNUSED(engaged); if (rhs.m_engaged) { this->Construct(std::move(rhs.Get())); } }
            constexpr OptionalPayloadBase(const OptionalPayloadBase &) = default;
            constexpr OptionalPayloadBase(OptionalPayloadBase &&) = default;
            constexpr OptionalPayloadBase &operator=(const OptionalPayloadBase &) = default;
            constexpr OptionalPayloadBase &operator=(OptionalPayloadBase &&) = default;
            constexpr void CopyAssign(const OptionalPayloadBase &rhs) {
                if (m_engaged && rhs.m_engaged) {
                    this->Get() = rhs.Get();
                } else if (rhs.m_engaged) {
                    this->Construct(rhs.Get());
                } else {
                    this->Reset();
                }
            }
            constexpr void MoveAssign(OptionalPayloadBase &&rhs) {
                if (m_engaged && rhs.m_engaged) {
                    this->Get() = std::move(rhs.Get());
                } else if (rhs.m_engaged) {
                    this->Construct(std::move(rhs.Get()));
                } else {
                    this->Reset();
                }
            }
            template
            constexpr void Construct(Args &&... args) {
                std::construct_at(std::addressof(m_payload.m_value), std::forward(args)...);
                m_engaged = true;
            }
            constexpr void Destroy() {
                m_engaged = false;
                std::destroy_at(std::addressof(m_payload.m_value));
            }
            template
            constexpr void Apply(impl::OptionalFunction f, Arg &&arg) {
                std::construct_at(std::addressof(m_payload), f, std::forward(arg));
                m_engaged = true;
            }
            constexpr ALWAYS_INLINE       T &Get()       { return m_payload.m_value; }
            constexpr ALWAYS_INLINE const T &Get() const { return m_payload.m_value; }
            constexpr void Reset() {
                if (m_engaged) {
                    this->Destroy();
                }
            }
        };
        template::value, bool = std::is_trivially_copy_assignable::value && std::is_trivially_copy_constructible::value, bool = std::is_trivially_move_assignable::value && std::is_trivially_move_constructible::value>
        struct OptionalPayload;
        template
        struct OptionalPayload : OptionalPayloadBase {
            using OptionalPayloadBase::OptionalPayloadBase;
            constexpr OptionalPayload() = default;
        };
        template
        struct OptionalPayload : OptionalPayloadBase {
            using OptionalPayloadBase::OptionalPayloadBase;
            constexpr OptionalPayload() = default;
            constexpr ~OptionalPayload() = default;
            constexpr OptionalPayload(const OptionalPayload &) = default;
            constexpr OptionalPayload(OptionalPayload &&) = default;
            constexpr OptionalPayload& operator=(OptionalPayload &&) = default;
            constexpr OptionalPayload &operator=(const OptionalPayload &rhs) {
                this->CopyAssign(rhs);
                return *this;
            }
        };
        template
        struct OptionalPayload : OptionalPayloadBase {
            using OptionalPayloadBase::OptionalPayloadBase;
            constexpr OptionalPayload() = default;
            constexpr ~OptionalPayload() = default;
            constexpr OptionalPayload(const OptionalPayload &) = default;
            constexpr OptionalPayload(OptionalPayload &&) = default;
            constexpr OptionalPayload& operator=(const OptionalPayload &) = default;
            constexpr OptionalPayload &operator=(OptionalPayload &&rhs) {
                this->MoveAssign(std::move(rhs));
                return *this;
            }
        };
        template
        struct OptionalPayload : OptionalPayloadBase {
            using OptionalPayloadBase::OptionalPayloadBase;
            constexpr OptionalPayload() = default;
            constexpr ~OptionalPayload() = default;
            constexpr OptionalPayload(const OptionalPayload &) = default;
            constexpr OptionalPayload(OptionalPayload &&) = default;
            constexpr OptionalPayload &operator=(const OptionalPayload &rhs) {
                this->CopyAssign(rhs);
                return *this;
            }
            constexpr OptionalPayload &operator=(OptionalPayload &&rhs) {
                this->MoveAssign(std::move(rhs));
                return *this;
            }
        };
        template
        struct OptionalPayload : OptionalPayload {
            using OptionalPayload::OptionalPayload;
            constexpr OptionalPayload() = default;
            constexpr OptionalPayload(const OptionalPayload &) = default;
            constexpr OptionalPayload(OptionalPayload &&) = default;
            constexpr OptionalPayload& operator=(const OptionalPayload &) = default;
            constexpr OptionalPayload& operator=(OptionalPayload &&) = default;
            constexpr ~OptionalPayload() { this->Reset(); }
        };
        template
        class OptionalBaseImpl {
            protected:
                using StoredType = std::remove_const_t;
                template
                constexpr void ConstructImpl(Args &&... args) { static_cast(this)->m_payload.Construct(std::forward(args)...); }
                constexpr void DestructImpl() { static_cast(this)->m_payload.Destroy(); }
                constexpr void ResetImpl() { static_cast(this)->m_payload.Reset(); }
                template
                constexpr void ApplyImpl(OptionalFunction f, Arg &&arg) {
                    static_cast(this)->m_payload.Apply(f, std::forward(arg));
                }
                constexpr ALWAYS_INLINE bool IsEngagedImpl() const { return static_cast(this)->m_payload.m_engaged; }
                constexpr ALWAYS_INLINE       T &GetImpl()       { return static_cast(this)->m_payload.Get(); }
                constexpr ALWAYS_INLINE const T &GetImpl() const { return static_cast(this)->m_payload.Get(); }
        };
        template::value, bool = std::is_trivially_move_constructible::value>
        struct OptionalBase : OptionalBaseImpl> {
            OptionalPayload m_payload;
            constexpr OptionalBase() = default;
            template::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, Args &&... args) : m_payload(in_place, std::forward(args)...) { /* ... */ }
            template &, Args...>::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, std::initializer_list il, Args &&... args) : m_payload(in_place, il, std::forward(args)...) { /* ... */ }
            constexpr OptionalBase(const OptionalBase &rhs) : m_payload(rhs.m_payload.m_engaged, rhs.m_payload) { /* ... */ }
            constexpr OptionalBase(OptionalBase &&rhs) : m_payload(rhs.m_payload.m_engaged, std::move(rhs.m_payload)) { /* ... */ }
            constexpr OptionalBase &operator=(const OptionalBase &) = default;
            constexpr OptionalBase &operator=(OptionalBase &&) = default;
        };
        template
        struct OptionalBase : OptionalBaseImpl> {
            OptionalPayload m_payload;
            constexpr OptionalBase() = default;
            template::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, Args &&... args) : m_payload(in_place, std::forward(args)...) { /* ... */ }
            template &, Args...>::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, std::initializer_list il, Args &&... args) : m_payload(in_place, il, std::forward(args)...) { /* ... */ }
            constexpr OptionalBase(const OptionalBase &rhs) : m_payload(rhs.m_payload.m_engaged, rhs.m_payload) { /* ... */ }
            constexpr OptionalBase(OptionalBase &&rhs) = default;
            constexpr OptionalBase &operator=(const OptionalBase &) = default;
            constexpr OptionalBase &operator=(OptionalBase &&) = default;
        };
        template
        struct OptionalBase : OptionalBaseImpl> {
            OptionalPayload m_payload;
            constexpr OptionalBase() = default;
            template::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, Args &&... args) : m_payload(in_place, std::forward(args)...) { /* ... */ }
            template &, Args...>::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, std::initializer_list il, Args &&... args) : m_payload(in_place, il, std::forward(args)...) { /* ... */ }
            constexpr OptionalBase(const OptionalBase &rhs) = default;
            constexpr OptionalBase(OptionalBase &&rhs) : m_payload(rhs.m_payload.m_engaged, std::move(rhs.m_payload)) { /* ... */ }
            constexpr OptionalBase &operator=(const OptionalBase &) = default;
            constexpr OptionalBase &operator=(OptionalBase &&) = default;
        };
        template
        struct OptionalBase : OptionalBaseImpl> {
            OptionalPayload m_payload;
            constexpr OptionalBase() = default;
            template::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, Args &&... args) : m_payload(in_place, std::forward(args)...) { /* ... */ }
            template &, Args...>::value, bool> = false>
            constexpr explicit OptionalBase(in_place_t, std::initializer_list il, Args &&... args) : m_payload(in_place, il, std::forward(args)...) { /* ... */ }
            constexpr OptionalBase(const OptionalBase &rhs) = default;
            constexpr OptionalBase(OptionalBase &&rhs) = default;
            constexpr OptionalBase &operator=(const OptionalBase &) = default;
            constexpr OptionalBase &operator=(OptionalBase &&) = default;
        };
    }
    template
    class optional;
    namespace impl {
        template
        constexpr inline bool ConvertsFromOptional = 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
        constexpr inline bool AssignsFromOptional = std::is_assignable &>::value ||
                                                    std::is_assignable &>::value ||
                                                    std::is_assignable &&>::value ||
                                                    std::is_assignable &&>::value;
        template
        constexpr inline bool IsOptional = false;
        template
        constexpr inline bool IsOptional> = true;
    }
    template
    class optional : private impl::OptionalBase, private impl::EnableCopyMove::value, std::is_copy_constructible::value && std::is_copy_assignable::value, std::is_move_constructible::value, std::is_move_constructible::value && std::is_move_assignable::value, optional> {
        static_assert(!std::is_same, ::ams::util::nullopt_t>::value);
        static_assert(!std::is_same, ::ams::util::in_place_t>::value);
        static_assert(!std::is_reference::value);
        private:
            using Base = impl::OptionalBase;
            template static constexpr inline bool IsNotSelf = !std::is_same>::value;
            template static constexpr inline bool IsNotTag  = !std::is_same<::ams::util::in_place_t, std::remove_cvref_t>::value && !std::is_same<::std::in_place_t, std::remove_cvref_t>::value;
            template
            using Requires = std::enable_if_t<(Cond && ...), bool>;
        public:
            using value_type = T;
        public:
            constexpr optional() { /* ... */ }
            constexpr optional(nullopt_t) { /* ... */ }
            template, IsNotTag, std::is_constructible::value, std::is_convertible::value> = true>
            constexpr optional(U &&u) : Base(::ams::util::in_place, std::forward(u)) { /* ... */ }
            template, IsNotTag, std::is_constructible::value, !std::is_convertible::value> = false>
            constexpr explicit optional(U &&u) : Base(::ams::util::in_place, std::forward(u)) { /* ... */ }
            template::value, std::is_constructible::value, std::is_convertible::value, !impl::ConvertsFromOptional> = true>
            constexpr optional(const optional &u) {
                if (u) {
                    this->emplace(*u);
                }
            }
            template::value, std::is_constructible::value, !std::is_convertible::value, !impl::ConvertsFromOptional> = false>
            constexpr explicit optional(const optional &u) {
                if (u) {
                    this->emplace(*u);
                }
            }
            template::value, std::is_constructible::value, std::is_convertible::value, !impl::ConvertsFromOptional> = true>
            constexpr optional(optional &&u) {
                if (u) {
                    this->emplace(std::move(*u));
                }
            }
            template::value, std::is_constructible::value, !std::is_convertible::value, !impl::ConvertsFromOptional> = false>
            constexpr explicit optional(optional &&u) {
                if (u) {
                    this->emplace(std::move(*u));
                }
            }
            template::value> = false>
            constexpr explicit optional(in_place_t, Args &&... args) : Base(::ams::util::in_place, std::forward(args)...) { /* ... */ }
            template &, Args...>::value> = false>
            constexpr explicit optional(in_place_t, std::initializer_list il, Args &&... args) : Base(::ams::util::in_place, il, std::forward(args)...) { /* ... */ }
            constexpr optional &operator=(nullopt_t) { this->ResetImpl(); return *this; }
            template
            constexpr std::enable_if_t && !(std::is_scalar::value && std::is_same>::value) && std::is_constructible::value && std::is_assignable::value,
                                       optional &>
            operator =(U &&u) {
                if (this->IsEngagedImpl()) {
                    this->GetImpl() = std::forward(u);
                } else {
                    this->ConstructImpl(std::forward(u));
                }
                return *this;
            }
            template
            constexpr std::enable_if_t::value && std::is_constructible::value && std::is_assignable::value && !impl::ConvertsFromOptional && !impl::AssignsFromOptional,
                                       optional &>
            operator =(const optional &u) {
                if (u) {
                    if (this->IsEngagedImpl()) {
                        this->GetImpl() = *u;
                    } else {
                        this->ConstructImpl(*u);
                    }
                } else {
                    this->ResetImpl();
                }
                return *this;
            }
            template
            constexpr std::enable_if_t::value && std::is_constructible::value && std::is_assignable::value && !impl::ConvertsFromOptional && !impl::AssignsFromOptional,
                                       optional &>
            operator =(optional &&u) {
                if (u) {
                    if (this->IsEngagedImpl()) {
                        this->GetImpl() = std::move(*u);
                    } else {
                        this->ConstructImpl(std::move(*u));
                    }
                } else {
                    this->ResetImpl();
                }
                return *this;
            }
            template
            constexpr std::enable_if_t::value, T &> emplace(Args &&... args) {
                this->ResetImpl();
                this->ConstructImpl(std::forward(args)...);
                return this->GetImpl();
            }
            template
            constexpr std::enable_if_t &, Args...>::value, T &> emplace(std::initializer_list il, Args &&... args) {
                this->ResetImpl();
                this->ConstructImpl(il, std::forward(args)...);
                return this->GetImpl();
            }
            constexpr void swap(optional &rhs) {
                if (this->IsEngagedImpl() && rhs.IsEngagedImpl()) {
                    std::swap(this->GetImpl(), rhs.GetImpl());
                } else if (this->IsEngagedImpl()) {
                    rhs.ConstructImpl(std::move(this->GetImpl()));
                    this->DestructImpl();
                } else if (rhs.IsEngagedImpl()) {
                    this->ConstructImpl(std::move(rhs.GetImpl()));
                    rhs.DestructImpl();
                }
            }
            constexpr ALWAYS_INLINE const T *operator ->() const { return std::addressof(this->GetImpl()); }
            constexpr ALWAYS_INLINE       T *operator ->()       { return std::addressof(this->GetImpl()); }
            constexpr ALWAYS_INLINE const T &operator *() const & { return this->GetImpl(); }
            constexpr ALWAYS_INLINE       T &operator *()       & { return this->GetImpl(); }
            constexpr ALWAYS_INLINE const T &&operator *() const && { return std::move(this->GetImpl()); }
            constexpr ALWAYS_INLINE       T &&operator *()       && { return std::move(this->GetImpl()); }
            constexpr ALWAYS_INLINE explicit operator bool() const { return this->IsEngagedImpl(); }
            constexpr ALWAYS_INLINE bool has_value() const { return this->IsEngagedImpl(); }
            constexpr ALWAYS_INLINE const T &value() const & { /* AMS_ASSERT(this->IsEngagedImpl()); */ return this->GetImpl(); }
            constexpr ALWAYS_INLINE       T &value()       & { /* AMS_ASSERT(this->IsEngagedImpl()); */ return this->GetImpl(); }
            constexpr ALWAYS_INLINE const T &&value() const && { /* AMS_ASSERT(this->IsEngagedImpl()); */ return std::move(this->GetImpl()); }
            constexpr ALWAYS_INLINE       T &&value()       && { /* AMS_ASSERT(this->IsEngagedImpl()); */ return std::move(this->GetImpl()); }
            template
            constexpr T value_or(U &&u) const & {
                static_assert(std::is_copy_constructible::value);
                static_assert(std::is_convertible::value);
                return this->IsEngagedImpl() ? this->GetImpl() : static_cast(std::forward(u));
            }
            template
            constexpr T value_or(U &&u) && {
                static_assert(std::is_move_constructible::value);
                static_assert(std::is_convertible::value);
                return this->IsEngagedImpl() ? std::move(this->GetImpl()) : static_cast(std::forward(u));
            }
            template
            constexpr auto and_then(F &&f) & {
                using U = typename std::remove_cvref::type>::type;
                static_assert(impl::IsOptional::type>);
                return this->IsEngagedImpl() ? std::invoke(std::forward(f), **this) : U{};
            }
            template
            constexpr auto and_then(F &&f) const & {
                using U = typename std::remove_cvref::type>::type;
                static_assert(impl::IsOptional::type>);
                return this->IsEngagedImpl() ? std::invoke(std::forward(f), **this) : U{};
            }
            template
            constexpr auto and_then(F &&f) && {
                using U = typename std::remove_cvref::type>::type;
                static_assert(impl::IsOptional::type>);
                return this->IsEngagedImpl() ? std::invoke(std::forward(f), std::move(**this)) : U{};
            }
            template
            constexpr auto and_then(F &&f) const && {
                using U = typename std::remove_cvref::type>::type;
                static_assert(impl::IsOptional::type>);
                return this->IsEngagedImpl() ? std::invoke(std::forward(f), std::move(**this)) : U{};
            }
            template
            constexpr auto transform(F &&f) & {
                using U = typename std::remove_cvref::type>::type;
                return this->IsEngagedImpl() ? optional(impl::OptionalFunction{f}, **this) : optional{};
            }
            template
            constexpr auto transform(F &&f) const & {
                using U = typename std::remove_cvref::type>::type;
                return this->IsEngagedImpl() ? optional(impl::OptionalFunction{f}, **this) : optional{};
            }
            template
            constexpr auto transform(F &&f) && {
                using U = typename std::remove_cvref::type>::type;
                return this->IsEngagedImpl() ? optional(impl::OptionalFunction