//===-- tuple utility -------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H #define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H #include "src/__support/CPP/type_traits/decay.h" #include "src/__support/CPP/utility/integer_sequence.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { template struct tuple; template <> struct tuple<> {}; template struct tuple : tuple { Head head; LIBC_INLINE constexpr tuple() = default; template LIBC_INLINE constexpr tuple &operator=(const tuple &other) { head = other.get_head(); this->get_tail() = other.get_tail(); return *this; } LIBC_INLINE constexpr tuple(const Head &h, const Tail &...t) : tuple(t...), head(h) {} LIBC_INLINE constexpr Head &get_head() { return head; } LIBC_INLINE constexpr const Head &get_head() const { return head; } LIBC_INLINE constexpr tuple &get_tail() { return *this; } LIBC_INLINE constexpr const tuple &get_tail() const { return *this; } }; template LIBC_INLINE constexpr auto make_tuple(Ts &&...args) { return tuple...>(static_cast(args)...); } template LIBC_INLINE constexpr auto tie(Ts &...args) { return tuple(args...); } template LIBC_INLINE constexpr auto &get(tuple &t) { if constexpr (Idx == 0) return t.get_head(); else return get(t.get_tail()); } template LIBC_INLINE constexpr const auto &get(const tuple &t) { if constexpr (Idx == 0) return t.get_head(); else return get(t.get_tail()); } template LIBC_INLINE constexpr auto &&get(tuple &&t) { if constexpr (Idx == 0) return static_cast(t.get_head()); else return get(static_cast &&>(t.get_tail())); } template LIBC_INLINE constexpr const auto &&get(const tuple &&t) { if constexpr (Idx == 0) return static_cast(t.get_head()); else return get(static_cast &&>(t.get_tail())); } template struct tuple_size; template struct tuple_size> { static constexpr size_t value = sizeof...(Ts); }; template struct tuple_element; template struct tuple_element> : tuple_element> {}; template struct tuple_element<0, tuple> { using type = cpp::remove_cv_t>; }; namespace internal { template LIBC_INLINE constexpr auto tuple_cat(const tuple &a, const tuple &b, cpp::index_sequence, cpp::index_sequence) { return tuple(get(a)..., get(b)...); } template LIBC_INLINE constexpr auto tuple_cat(const First &f, const Second &s, const Rest &...rest) { auto concat = tuple_cat(f, s, cpp::make_index_sequence::value>{}, cpp::make_index_sequence::value>{}); if constexpr (sizeof...(Rest)) return tuple_cat(concat, rest...); else return concat; } } // namespace internal template LIBC_INLINE constexpr auto tuple_cat(const Tuples &...tuples) { static_assert(sizeof...(Tuples) > 0, "need at least one element"); if constexpr (sizeof...(Tuples) == 1) return (tuples, ...); else return internal::tuple_cat(tuples...); } } // namespace cpp } // namespace LIBC_NAMESPACE_DECL // Standard namespace definitions required for structured binding support. namespace std { template struct tuple_size; template struct tuple_element; template struct tuple_size> : LIBC_NAMESPACE::cpp::tuple_size> {}; template struct tuple_element> : LIBC_NAMESPACE::cpp::tuple_element> {}; } // namespace std #endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H