Skip to content

Commit 739de01

Browse files
authored
[libc] Add simple 'tuple' type to CPP helpers (#157739)
Summary: This patch adds support for `cpp::tuple` with basic support for creating and modifing tuples.
1 parent f3b7ad4 commit 739de01

File tree

6 files changed

+251
-0
lines changed

6 files changed

+251
-0
lines changed

libc/src/__support/CPP/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,14 @@ add_object_library(
212212
libc.src.__support.macros.properties.os
213213
)
214214

215+
add_header_library(
216+
tuple
217+
HDRS
218+
tuple.h
219+
DEPENDS
220+
.utility
221+
)
222+
215223
add_header_library(
216224
simd
217225
HDRS

libc/src/__support/CPP/tuple.h

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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

libc/src/__support/CPP/utility/integer_sequence.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8+
89
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
910
#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
1011

1112
#include "src/__support/CPP/type_traits/is_integral.h"
1213
#include "src/__support/macros/config.h"
1314

15+
#include <stddef.h>
16+
1417
namespace LIBC_NAMESPACE_DECL {
1518
namespace cpp {
1619

@@ -34,6 +37,13 @@ template <typename T, int N>
3437
using make_integer_sequence =
3538
typename detail::make_integer_sequence<T, N - 1>::type;
3639

40+
// index sequence
41+
template <size_t... Ints>
42+
using index_sequence = integer_sequence<size_t, Ints...>;
43+
template <int N>
44+
using make_index_sequence =
45+
typename detail::make_integer_sequence<size_t, N - 1>::type;
46+
3747
} // namespace cpp
3848
} // namespace LIBC_NAMESPACE_DECL
3949

libc/test/src/__support/CPP/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ add_libc_test(
130130
libc.src.__support.CPP.optional
131131
)
132132

133+
add_libc_test(
134+
tuple_test
135+
SUITE
136+
libc-cpp-utils-tests
137+
SRCS
138+
tuple_test.cpp
139+
DEPENDS
140+
libc.src.__support.CPP.tuple
141+
)
142+
133143
add_libc_test(
134144
span_test
135145
SUITE
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//===-- Unittests for cpp::tuple ------------------------------------------===//
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+
#include "src/__support/CPP/tuple.h"
10+
#include <stddef.h>
11+
12+
#include "test/UnitTest/FPMatcher.h"
13+
#include "test/UnitTest/Test.h"
14+
15+
using namespace LIBC_NAMESPACE::cpp;
16+
17+
TEST(LlvmLibcTupleTest, Construction) {
18+
tuple<int, double> t(42, 3.14);
19+
EXPECT_EQ(get<0>(t), 42);
20+
EXPECT_FP_EQ(get<1>(t), 3.14);
21+
}
22+
23+
TEST(LlvmLibcTupleTest, MakeTuple) {
24+
auto t = make_tuple(1, 2.5, 'x');
25+
EXPECT_EQ(get<0>(t), 1);
26+
EXPECT_FP_EQ(get<1>(t), 2.5);
27+
EXPECT_EQ(get<2>(t), 'x');
28+
}
29+
30+
TEST(LlvmLibcTupleTest, TieAssignment) {
31+
int a = 0;
32+
double b = 0;
33+
char c = 0;
34+
auto t = make_tuple(7, 8.5, 'y');
35+
tie(a, b, c) = t;
36+
EXPECT_EQ(a, 7);
37+
EXPECT_FP_EQ(b, 8.5);
38+
EXPECT_EQ(c, 'y');
39+
}
40+
41+
TEST(LlvmLibcTupleTest, StructuredBindings) {
42+
auto t = make_tuple(7, 8.5, 'y');
43+
auto [x, y, z] = t;
44+
EXPECT_EQ(x, 7);
45+
EXPECT_FP_EQ(y, 8.5);
46+
EXPECT_EQ(z, 'y');
47+
}
48+
49+
TEST(LlvmLibcTupleTest, TupleCat) {
50+
tuple<int, double> t(42, 3.14);
51+
auto t1 = make_tuple(1, 2.5, 'x');
52+
auto t2 = tuple_cat(t, t1);
53+
EXPECT_EQ(get<0>(t2), 42);
54+
EXPECT_FP_EQ(get<1>(t2), 3.14);
55+
EXPECT_EQ(get<2>(t2), 1);
56+
EXPECT_FP_EQ(get<3>(t2), 2.5);
57+
EXPECT_EQ(get<4>(t2), 'x');
58+
}
59+
60+
TEST(LlvmLibcTupleTest, ConstTuple) {
61+
const auto t = make_tuple(100, 200.5);
62+
EXPECT_EQ(get<0>(t), 100);
63+
EXPECT_FP_EQ(get<1>(t), 200.5);
64+
}
65+
66+
TEST(LlvmLibcTupleTest, RvalueAssignment) {
67+
auto t = make_tuple(0, 0.0);
68+
t = make_tuple(9, 9.5);
69+
EXPECT_EQ(get<0>(t), 9);
70+
EXPECT_FP_EQ(get<1>(t), 9.5);
71+
}

utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,14 @@ libc_support_library(
660660
],
661661
)
662662

663+
libc_support_library(
664+
name = "__support_cpp_tuple",
665+
hdrs = ["src/__support/CPP/tuple.h"],
666+
deps = [
667+
"__support_cpp_utility",
668+
],
669+
)
670+
663671
libc_support_library(
664672
name = "__support_cpp_limits",
665673
hdrs = ["src/__support/CPP/limits.h"],

0 commit comments

Comments
 (0)