blob: fa4fcd08cc04f1ae93abba18c9c620eef1caa034 [file] [log] [blame] [edit]
//===-- 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 <typename... Ts> struct tuple;
template <> struct tuple<> {};
template <typename Head, typename... Tail>
struct tuple<Head, Tail...> : tuple<Tail...> {
Head head;
LIBC_INLINE constexpr tuple() = default;
template <typename OHead, typename... OTail>
LIBC_INLINE constexpr tuple &operator=(const tuple<OHead, OTail...> &other) {
head = other.get_head();
this->get_tail() = other.get_tail();
return *this;
}
LIBC_INLINE constexpr tuple(const Head &h, const Tail &...t)
: tuple<Tail...>(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<Tail...> &get_tail() { return *this; }
LIBC_INLINE constexpr const tuple<Tail...> &get_tail() const { return *this; }
};
template <typename... Ts> LIBC_INLINE constexpr auto make_tuple(Ts &&...args) {
return tuple<cpp::decay_t<Ts>...>(static_cast<Ts &&>(args)...);
}
template <typename... Ts> LIBC_INLINE constexpr auto tie(Ts &...args) {
return tuple<Ts &...>(args...);
}
template <size_t Idx, typename Head, typename... Tail>
LIBC_INLINE constexpr auto &get(tuple<Head, Tail...> &t) {
if constexpr (Idx == 0)
return t.get_head();
else
return get<Idx - 1>(t.get_tail());
}
template <size_t Idx, typename Head, typename... Tail>
LIBC_INLINE constexpr const auto &get(const tuple<Head, Tail...> &t) {
if constexpr (Idx == 0)
return t.get_head();
else
return get<Idx - 1>(t.get_tail());
}
template <size_t Idx, typename Head, typename... Tail>
LIBC_INLINE constexpr auto &&get(tuple<Head, Tail...> &&t) {
if constexpr (Idx == 0)
return static_cast<Head &&>(t.get_head());
else
return get<Idx - 1>(static_cast<tuple<Tail...> &&>(t.get_tail()));
}
template <size_t Idx, typename Head, typename... Tail>
LIBC_INLINE constexpr const auto &&get(const tuple<Head, Tail...> &&t) {
if constexpr (Idx == 0)
return static_cast<const Head &&>(t.get_head());
else
return get<Idx - 1>(static_cast<const tuple<Tail...> &&>(t.get_tail()));
}
template <typename T> struct tuple_size;
template <typename... Ts> struct tuple_size<tuple<Ts...>> {
static constexpr size_t value = sizeof...(Ts);
};
template <size_t Idx, typename T> struct tuple_element;
template <size_t Idx, typename Head, typename... Tail>
struct tuple_element<Idx, tuple<Head, Tail...>>
: tuple_element<Idx - 1, tuple<Tail...>> {};
template <typename Head, typename... Tail>
struct tuple_element<0, tuple<Head, Tail...>> {
using type = cpp::remove_cv_t<cpp::remove_reference_t<Head>>;
};
namespace internal {
template <typename... As, typename... Bs, size_t... Idx, size_t... J>
LIBC_INLINE constexpr auto
tuple_cat(const tuple<As...> &a, const tuple<Bs...> &b,
cpp::index_sequence<Idx...>, cpp::index_sequence<J...>) {
return tuple<As..., Bs...>(get<Idx>(a)..., get<J>(b)...);
}
template <typename First, typename Second, typename... Rest>
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<tuple_size<First>::value>{},
cpp::make_index_sequence<tuple_size<Second>::value>{});
if constexpr (sizeof...(Rest))
return tuple_cat(concat, rest...);
else
return concat;
}
} // namespace internal
template <typename... Tuples>
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 <class T> struct tuple_size;
template <size_t Idx, class T> struct tuple_element;
template <typename... Ts>
struct tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>>
: LIBC_NAMESPACE::cpp::tuple_size<LIBC_NAMESPACE::cpp::tuple<Ts...>> {};
template <size_t Idx, typename... Ts>
struct tuple_element<Idx, LIBC_NAMESPACE::cpp::tuple<Ts...>>
: LIBC_NAMESPACE::cpp::tuple_element<Idx,
LIBC_NAMESPACE::cpp::tuple<Ts...>> {};
} // namespace std
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_TUPLE_H