/* * Copyright (c) 2021, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include namespace AK::Detail { template struct Tuple { }; template struct Tuple { Tuple(T&& value) requires(!IsSame < T &&, T const& >) : value(forward(value)) { } Tuple(T const& value) : value(value) { } template U& get() { static_assert(IsSame, "Invalid tuple access"); return value; } template U const& get() const { return const_cast&>(*this).get(); } template U& get_with_index() { static_assert(IsSame && index == 0, "Invalid tuple access"); return value; } template U const& get_with_index() const { return const_cast&>(*this).get_with_index(); } private: T value; }; template struct Tuple : Tuple { template Tuple(FirstT&& first, RestT&&... rest) : Tuple(forward(rest)...) , value(forward(first)) { } Tuple(T&& first, TRest&&... rest) : Tuple(move(rest)...) , value(move(first)) { } template U& get() { if constexpr (IsSame) return value; else return Tuple::template get(); } template U const& get() const { return const_cast&>(*this).get(); } template U& get_with_index() { if constexpr (IsSame && index == 0) return value; else return Tuple::template get_with_index(); } template U const& get_with_index() const { return const_cast&>(*this).get_with_index(); } private: T value; }; } namespace AK { template struct Tuple : Detail::Tuple { using Types = TypeList; using Detail::Tuple::Tuple; using Indices = MakeIndexSequence; Tuple(Tuple&& other) : Tuple(move(other), Indices()) { } Tuple(Tuple const& other) : Tuple(other, Indices()) { } Tuple& operator=(Tuple&& other) { set(move(other), Indices()); return *this; } Tuple& operator=(Tuple const& other) { set(other, Indices()); return *this; } template auto& get() { return Detail::Tuple::template get(); } template auto& get() { return Detail::Tuple::template get_with_index, index>(); } template auto& get() const { return Detail::Tuple::template get(); } template auto& get() const { return Detail::Tuple::template get_with_index, index>(); } template auto apply_as_args(F&& f) { return apply_as_args(forward(f), Indices()); } template auto apply_as_args(F&& f) const { return apply_as_args(forward(f), Indices()); } static constexpr auto size() { return sizeof...(Ts); } private: template Tuple(Tuple&& other, IndexSequence) : Detail::Tuple(move(other.get())...) { } template Tuple(Tuple const& other, IndexSequence) : Detail::Tuple(other.get()...) { } template void set(Tuple&& other, IndexSequence) { ((get() = move(other.get())), ...); } template void set(Tuple const& other, IndexSequence) { ((get() = other.get()), ...); } template auto apply_as_args(F&& f, IndexSequence) { return forward(f)(get()...); } template auto apply_as_args(F&& f, IndexSequence) const { return forward(f)(get()...); } }; template Tuple(Args... args) -> Tuple; } #if USING_AK_GLOBALLY using AK::Tuple; #endif