| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 | #ifndef __GBLIBCPP_TUPLE__#define __GBLIBCPP_TUPLE__#include <cstddef>#include <type_traits>#include <utility>#include <functional>namespace std {template <std::size_t I, typename T>struct tuple_element;template <std::size_t I, typename T>using tuple_element_t = typename tuple_element<I, T>::type;template <typename T>struct tuple_size;template <typename T>inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;template <std::size_t I, typename T>struct tuple_element<I, const T> {    using type = std::add_const_t<tuple_element_t<I, T>>;};template <std::size_t I, typename T>struct tuple_element<I, volatile T> {    using type = std::add_volatile_t<tuple_element_t<I, T>>;};template <std::size_t I, typename T>struct tuple_element<I, const volatile T> {    using type = std::add_cv_t<tuple_element_t<I, T>>;};namespace __helpers {template <typename T, typename = void>struct __const_tuple_size {};template <typename T>struct __const_tuple_size<T, void_t<decltype(std::tuple_size<T>::value)>>    : std::integral_constant<std::size_t, std::tuple_size<T>::value> {};} // namespace __helperstemplate <typename T>struct tuple_size<const T> : __helpers::__const_tuple_size<T> {};template <typename... Types>class tuple;template <std::size_t I, typename Type, typename... Types>struct tuple_element<I, std::tuple<Type, Types...>>    : tuple_element<I-1, std::tuple<Types...>> {};template <typename Type, typename... Types>struct tuple_element<0, std::tuple<Type, Types...>> { using type = Type; };template <typename... Types>struct tuple_size<std::tuple<Types...>>    : std::integral_constant<std::size_t, sizeof...(Types)> {};template <std::size_t I, typename... Types>constexpr auto get(std::tuple<Types...>& tpl) noexcept    -> tuple_element_t<I, std::tuple<Types...>>&{ return tpl.template _getl<I>(); }template <std::size_t I, typename... Types>constexpr auto get(std::tuple<Types...>&& tpl) noexcept    -> tuple_element_t<I, std::tuple<Types...>>&&{ return tpl.template _getr<I>(); }template <std::size_t I, typename... Types>constexpr auto get(const std::tuple<Types...>& tpl) noexcept    -> tuple_element_t<I, std::tuple<Types...>> const&{ return tpl.template _getl<I>(); }template <std::size_t I, typename... Types>constexpr auto get(const std::tuple<Types...>&& tpl) noexcept    -> tuple_element_t<I, std::tuple<Types...>> const&&{ return tpl.template _getr<I>(); }namespace __helpers {template <std::size_t I, typename Type, typename... Types>class tuple_impl {    template <std::size_t, typename, typename...>    friend class tuple_impl;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(std::tuple<UTypes...>& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>>&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(std::tuple<UTypes...>&& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>>&&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(const std::tuple<UTypes...>& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>> const&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(const std::tuple<UTypes...>&& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>> const&&;    Type val;    tuple_impl<I+1, Types...> next;    template <std::size_t J>    constexpr auto& _getl(void)    {        if constexpr (I == J)            return val;        else            return next.template _getl<J>();    }    template <std::size_t J>    constexpr const auto& _getl(void) const    {        if constexpr (I == J)            return val;        else            return next.template _getl<J>();    }    template <std::size_t J>    constexpr auto&& _getr(void)    {        if constexpr (I == J)            return std::move(val);        else            return std::move(next.template _getr<J>());    }    template <std::size_t J>    constexpr const auto&& _getr(void) const    {        if constexpr (I == J)            return std::move(val);        else            return std::move(next.template _getr<J>());    }public:    constexpr tuple_impl()        : val(), next() {}        constexpr tuple_impl(const tuple_impl& arg) = default;    constexpr tuple_impl(tuple_impl&& arg) = default;    constexpr tuple_impl(const Type& val, const Types&... vals)        : val(val), next(vals...) {}        template <typename UType, typename... UTypes>    constexpr tuple_impl(UType&& val, UTypes&&... vals)        : val(std::forward<UType>(val)), next(std::forward<UTypes>(vals)...) {}    template <typename... UTypes>    constexpr tuple_impl(const std::tuple<UTypes...>& other)        : val(std::get<I>(other)), next(other) {}    template <typename... UTypes>    constexpr tuple_impl(std::tuple<UTypes...>&& other)        : val(std::get<I>(other)), next(std::move(other)) {}        constexpr tuple_impl& operator=(const tuple_impl& other) = default;    constexpr tuple_impl& operator=(tuple_impl&& other) = default;};template <std::size_t I, typename Type>class tuple_impl<I, Type> {    template <std::size_t, typename, typename...>    friend class tuple_impl;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(std::tuple<UTypes...>& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>>&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(std::tuple<UTypes...>&& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>>&&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(const std::tuple<UTypes...>& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>> const&;    template <std::size_t J, typename... UTypes>    friend constexpr auto std::get(const std::tuple<UTypes...>&& tpl) noexcept        -> tuple_element_t<J, std::tuple<UTypes...>> const&&;    Type val;    template <std::size_t>    constexpr Type& _getl(void) { return val; }    template <std::size_t>    constexpr Type const& _getl(void) const { return val; }    template <std::size_t>    constexpr Type&& _getr(void) { return std::move(val); }    template <std::size_t>    constexpr Type const&& _getr(void) const { return std::move(val); }public:    constexpr tuple_impl()        : val() {}        constexpr tuple_impl(const tuple_impl& arg) = default;    constexpr tuple_impl(tuple_impl&& arg) = default;    constexpr tuple_impl(const Type& val) : val(val) {}    template <typename UType>    constexpr tuple_impl(UType&& val) : val(std::forward<UType>(val)) {}    template <typename... UTypes>    constexpr tuple_impl(const std::tuple<UTypes...>& other)        : val(std::get<I>(other)) {}    template <typename... UTypes>    constexpr tuple_impl(std::tuple<UTypes...>&& other)        : val(std::get<I>(other)) {}    constexpr tuple_impl& operator=(const tuple_impl& other) = default;    constexpr tuple_impl& operator=(tuple_impl&& other) = default;};} // namespace __helperstemplate <typename... Types>class tuple : public __helpers::tuple_impl<0, Types...> {private:    using base = __helpers::tuple_impl<0, Types...>;    template <typename... UTypes, std::size_t... I>    constexpr void __copy_assignment(const tuple<UTypes...>& other, std::index_sequence<I...>)    { ((std::get<I>(*this) = std::get<I>(other)), ...); }    template <typename... UTypes, std::size_t... I>    constexpr void __move_assignment(tuple<UTypes...>&& other, std::index_sequence<I...>)    { ((std::get<I>(*this) = std::forward<UTypes>(std::get<I>(other))), ...); }public:    constexpr tuple() : base() {}    constexpr tuple(const Types&... args)        : base(args...) {}        template <typename... UTypes, enable_if_t<        sizeof...(UTypes) == sizeof...(Types)        && sizeof...(Types) >= 1        && !(sizeof...(Types) == 1 && (... && std::is_same_v<tuple, UTypes>))    , bool> = true>    constexpr tuple(UTypes&&... args)        : base(std::forward<UTypes>(args)...) {}    template <typename... UTypes>    constexpr tuple(const tuple<UTypes...>& other)        : base(other) {}    template <typename... UTypes>    constexpr tuple(tuple<UTypes...>&& other)        : base(std::move(other)) {}        // TODO: std::pair constructors    constexpr tuple(const tuple&) = default;    constexpr tuple(tuple&&) = default;    constexpr tuple& operator=(const tuple& other) = default;    constexpr tuple& operator=(tuple&& other) = default;    template <typename... UTypes, enable_if_t<        sizeof...(Types) == sizeof...(UTypes)        && (... && std::is_assignable_v<Types&, const UTypes&>)        , bool> = true>    constexpr tuple& operator=(const tuple<UTypes...>& other)    {        __copy_assignment(other, index_sequence_for<Types...> {});        return *this;    }    template <typename... UTypes, enable_if_t<        sizeof...(Types) == sizeof...(UTypes)        && (... && std::is_assignable_v<Types&, UTypes>)        , bool> = true>    constexpr tuple& operator=(tuple<UTypes...>&& other)    {        __move_assignment(std::move(other), index_sequence_for<Types...> {});        return *this;    }    constexpr void swap(tuple& other) { std::swap(*this, other); }};template <typename... Types>tuple(Types...) -> tuple<Types...>;namespace __helpers {struct ignore_t {    template <typename T>    constexpr void operator=(T&&) const noexcept {}};template <typename _T, typename T = std::decay_t<_T>>struct __to_tuple_type { using type = T; };template <typename _T, typename T>struct __to_tuple_type<_T, std::reference_wrapper<T>>{ using type = std::add_lvalue_reference_t<T>; };template <typename T, typename Tuple, std::size_t... I>constexpr T make_from_tuple_impl(Tuple&& tpl, std::index_sequence<I...>){    return T { std::get<I>(std::forward<Tuple>(tpl))... };}template <typename Func, typename Tuple, std::size_t... I>constexpr auto apply_impl(Func&& func, Tuple&& tpl, std::index_sequence<I...>){    return std::invoke(        std::forward<Func>(func),        std::get<I>(std::forward<Tuple>(tpl))...);}} // namespace __helpersinline constexpr __helpers::ignore_t ignore;template <typename... Types>constexpr void swap(std::tuple<Types...>& lhs, std::tuple<Types...>& rhs)    noexcept(noexcept(lhs.swap(rhs))){    lhs.swap(rhs);}template <typename... Types>constexpr auto make_tuple(Types&&... args)    -> std::tuple<typename __helpers::__to_tuple_type<Types>::type...>{    return std::tuple<typename __helpers::__to_tuple_type<Types>::type...>        { std::forward<Types>(args)... };}template <typename... Types>constexpr std::tuple<Types&...> tie(Types&... args) noexcept{    return { args... };}template <typename... Types>constexpr std::tuple<Types&&...> forward_as_tuple(Types&&... args) noexcept{    return { std::forward<Types>(args)... };}template <typename T, typename Tuple>constexpr T make_from_tuple(Tuple&& tpl){    return __helpers::make_from_tuple_impl<T>(        std::forward<Tuple>(tpl),        std::make_index_sequence<            std::tuple_size_v<std::remove_cvref_t<Tuple>>> {}    );}template <typename Func, typename Tuple>constexpr decltype(auto) apply(Func&& func, Tuple&& tpl){    return __helpers::apply_impl(        std::forward<Func>(func), std::forward<Tuple>(tpl),        std::make_index_sequence<            std::tuple_size_v<std::remove_cvref_t<Tuple>>> {}    );}} // namespace std#endif
 |