|
| 1 | +//===-- tuple utility -------------------------------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H |
| 10 | +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H |
| 11 | + |
| 12 | +#include "src/__support/CPP/type_traits/decay.h" |
| 13 | +#include "src/__support/CPP/utility/integer_sequence.h" |
| 14 | + |
| 15 | +namespace LIBC_NAMESPACE_DECL { |
| 16 | +namespace cpp { |
| 17 | + |
| 18 | +template <typename... Ts> struct tuple; |
| 19 | +template <> struct tuple<> {}; |
| 20 | + |
| 21 | +template <typename Head, typename... Tail> |
| 22 | +struct tuple<Head, Tail...> : tuple<Tail...> { |
| 23 | + Head head; |
| 24 | + |
| 25 | + LIBC_INLINE constexpr tuple() = default; |
| 26 | + |
| 27 | + template <typename OHead, typename... OTail> |
| 28 | + LIBC_INLINE constexpr tuple &operator=(const tuple<OHead, OTail...> &other) { |
| 29 | + head = other.get_head(); |
| 30 | + this->get_tail() = other.get_tail(); |
| 31 | + return *this; |
| 32 | + } |
| 33 | + |
| 34 | + LIBC_INLINE constexpr tuple(const Head &h, const Tail &...t) |
| 35 | + : tuple<Tail...>(t...), head(h) {} |
| 36 | + |
| 37 | + LIBC_INLINE constexpr Head &get_head() { return head; } |
| 38 | + LIBC_INLINE constexpr const Head &get_head() const { return head; } |
| 39 | + |
| 40 | + LIBC_INLINE constexpr tuple<Tail...> &get_tail() { return *this; } |
| 41 | + LIBC_INLINE constexpr const tuple<Tail...> &get_tail() const { return *this; } |
| 42 | +}; |
| 43 | + |
| 44 | +template <typename... Ts> LIBC_INLINE constexpr auto make_tuple(Ts &&...args) { |
| 45 | + return tuple<cpp::decay_t<Ts>...>(static_cast<Ts &&>(args)...); |
| 46 | +} |
| 47 | +template <typename... Ts> LIBC_INLINE constexpr auto tie(Ts &...args) { |
| 48 | + return tuple<Ts &...>(args...); |
| 49 | +} |
| 50 | + |
| 51 | +template <size_t I, typename Head, typename... Tail> |
| 52 | +LIBC_INLINE constexpr auto &get(tuple<Head, Tail...> &t) { |
| 53 | + if constexpr (I == 0) |
| 54 | + return t.get_head(); |
| 55 | + else |
| 56 | + return get<I - 1>(t.get_tail()); |
| 57 | +} |
| 58 | +template <size_t I, typename Head, typename... Tail> |
| 59 | +LIBC_INLINE constexpr const auto &get(const tuple<Head, Tail...> &t) { |
| 60 | + if constexpr (I == 0) |
| 61 | + return t.get_head(); |
| 62 | + else |
| 63 | + return get<I - 1>(t.get_tail()); |
| 64 | +} |
| 65 | +template <size_t I, typename Head, typename... Tail> |
| 66 | +LIBC_INLINE constexpr auto &&get(tuple<Head, Tail...> &&t) { |
| 67 | + if constexpr (I == 0) |
| 68 | + return static_cast<Head &&>(t.get_head()); |
| 69 | + else |
| 70 | + return get<I - 1>(static_cast<tuple<Tail...> &&>(t.get_tail())); |
| 71 | +} |
| 72 | +template <size_t I, typename Head, typename... Tail> |
| 73 | +LIBC_INLINE constexpr const auto &&get(const tuple<Head, Tail...> &&t) { |
| 74 | + if constexpr (I == 0) |
| 75 | + return static_cast<const Head &&>(t.get_head()); |
| 76 | + else |
| 77 | + return get<I - 1>(static_cast<const tuple<Tail...> &&>(t.get_tail())); |
| 78 | +} |
| 79 | + |
| 80 | +template <typename T> struct tuple_size; |
| 81 | +template <typename... Ts> struct tuple_size<tuple<Ts...>> { |
| 82 | + static constexpr size_t value = sizeof...(Ts); |
| 83 | +}; |
| 84 | + |
| 85 | +template <size_t I, typename T> struct tuple_element; |
| 86 | +template <size_t I, typename Head, typename... Tail> |
| 87 | +struct tuple_element<I, tuple<Head, Tail...>> |
| 88 | + : tuple_element<I - 1, tuple<Tail...>> {}; |
| 89 | +template <typename Head, typename... Tail> |
| 90 | +struct tuple_element<0, tuple<Head, Tail...>> { |
| 91 | + using type = cpp::remove_cv_t<cpp::remove_reference_t<Head>>; |
| 92 | +}; |
| 93 | + |
| 94 | +namespace internal { |
| 95 | +template <typename... As, typename... Bs, size_t... I, size_t... J> |
| 96 | +LIBC_INLINE constexpr auto |
| 97 | +tuple_cat(const tuple<As...> &a, const tuple<Bs...> &b, |
| 98 | + cpp::index_sequence<I...>, cpp::index_sequence<J...>) { |
| 99 | + return tuple<As..., Bs...>(get<I>(a)..., get<J>(b)...); |
| 100 | +} |
| 101 | + |
| 102 | +template <typename First, typename Second, typename... Rest> |
| 103 | +LIBC_INLINE constexpr auto tuple_cat(const First &f, const Second &s, |
| 104 | + const Rest &...rest) { |
| 105 | + auto concat = |
| 106 | + tuple_cat(f, s, cpp::make_index_sequence<tuple_size<First>::value>{}, |
| 107 | + cpp::make_index_sequence<tuple_size<Second>::value>{}); |
| 108 | + if constexpr (sizeof...(Rest)) |
| 109 | + return tuple_cat(concat, rest...); |
| 110 | + else |
| 111 | + return concat; |
| 112 | +} |
| 113 | +} // namespace internal |
| 114 | + |
| 115 | +template <typename... Tuples> |
| 116 | +LIBC_INLINE constexpr auto tuple_cat(const Tuples &...tuples) { |
| 117 | + static_assert(sizeof...(Tuples) > 0, "need at least one element"); |
| 118 | + if constexpr (sizeof...(Tuples) == 1) |
| 119 | + return (tuples, ...); |
| 120 | + else |
| 121 | + return internal::tuple_cat(tuples...); |
| 122 | +} |
| 123 | + |
| 124 | +} // namespace cpp |
| 125 | +} // namespace LIBC_NAMESPACE_DECL |
| 126 | + |
| 127 | +// Standard namespace definitions required for structured binding support. |
| 128 | +namespace std { |
| 129 | + |
| 130 | +template <class T> struct tuple_size; |
| 131 | +template <size_t I, class T> struct tuple_element; |
| 132 | + |
| 133 | +template <typename... Ts> |
| 134 | +struct tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> |
| 135 | + : LIBC_NAMESPACE::cpp::tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> {}; |
| 136 | + |
| 137 | +template <size_t I, typename... Ts> |
| 138 | +struct tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> |
| 139 | + : LIBC_NAMESPACE::cpp::tuple_element<I, LIBC_NAMESPACE::cpp::tuple<Ts...>> { |
| 140 | +}; |
| 141 | + |
| 142 | +} // namespace std |
| 143 | + |
| 144 | +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H |
0 commit comments