145 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H10#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H11 12#include "src/__support/CPP/type_traits/decay.h"13#include "src/__support/CPP/utility/integer_sequence.h"14 15namespace LIBC_NAMESPACE_DECL {16namespace cpp {17 18template <typename... Ts> struct tuple;19template <> struct tuple<> {};20 21template <typename Head, typename... Tail>22struct 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 44template <typename... Ts> LIBC_INLINE constexpr auto make_tuple(Ts &&...args) {45 return tuple<cpp::decay_t<Ts>...>(static_cast<Ts &&>(args)...);46}47template <typename... Ts> LIBC_INLINE constexpr auto tie(Ts &...args) {48 return tuple<Ts &...>(args...);49}50 51template <size_t Idx, typename Head, typename... Tail>52LIBC_INLINE constexpr auto &get(tuple<Head, Tail...> &t) {53 if constexpr (Idx == 0)54 return t.get_head();55 else56 return get<Idx - 1>(t.get_tail());57}58template <size_t Idx, typename Head, typename... Tail>59LIBC_INLINE constexpr const auto &get(const tuple<Head, Tail...> &t) {60 if constexpr (Idx == 0)61 return t.get_head();62 else63 return get<Idx - 1>(t.get_tail());64}65template <size_t Idx, typename Head, typename... Tail>66LIBC_INLINE constexpr auto &&get(tuple<Head, Tail...> &&t) {67 if constexpr (Idx == 0)68 return static_cast<Head &&>(t.get_head());69 else70 return get<Idx - 1>(static_cast<tuple<Tail...> &&>(t.get_tail()));71}72template <size_t Idx, typename Head, typename... Tail>73LIBC_INLINE constexpr const auto &&get(const tuple<Head, Tail...> &&t) {74 if constexpr (Idx == 0)75 return static_cast<const Head &&>(t.get_head());76 else77 return get<Idx - 1>(static_cast<const tuple<Tail...> &&>(t.get_tail()));78}79 80template <typename T> struct tuple_size;81template <typename... Ts> struct tuple_size<tuple<Ts...>> {82 static constexpr size_t value = sizeof...(Ts);83};84 85template <size_t Idx, typename T> struct tuple_element;86template <size_t Idx, typename Head, typename... Tail>87struct tuple_element<Idx, tuple<Head, Tail...>>88 : tuple_element<Idx - 1, tuple<Tail...>> {};89template <typename Head, typename... Tail>90struct tuple_element<0, tuple<Head, Tail...>> {91 using type = cpp::remove_cv_t<cpp::remove_reference_t<Head>>;92};93 94namespace internal {95template <typename... As, typename... Bs, size_t... Idx, size_t... J>96LIBC_INLINE constexpr auto97tuple_cat(const tuple<As...> &a, const tuple<Bs...> &b,98 cpp::index_sequence<Idx...>, cpp::index_sequence<J...>) {99 return tuple<As..., Bs...>(get<Idx>(a)..., get<J>(b)...);100}101 102template <typename First, typename Second, typename... Rest>103LIBC_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 else111 return concat;112}113} // namespace internal114 115template <typename... Tuples>116LIBC_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 else121 return internal::tuple_cat(tuples...);122}123 124} // namespace cpp125} // namespace LIBC_NAMESPACE_DECL126 127// Standard namespace definitions required for structured binding support.128namespace std {129 130template <class T> struct tuple_size;131template <size_t Idx, class T> struct tuple_element;132 133template <typename... Ts>134struct tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>>135 : LIBC_NAMESPACE::cpp::tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> {};136 137template <size_t Idx, typename... Ts>138struct tuple_element<Idx, LIBC_NAMESPACE::cpp::tuple<Ts...>>139 : LIBC_NAMESPACE::cpp::tuple_element<Idx,140 LIBC_NAMESPACE::cpp::tuple<Ts...>> {};141 142} // namespace std143 144#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H145