diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt index a389a6d1702fe..13b2ef920efb8 100644 --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -211,6 +211,14 @@ add_object_library( libc.src.__support.macros.properties.os ) +add_header_library( + tuple + HDRS + tuple.h + DEPENDS + .utility +) + add_header_library( simd HDRS diff --git a/libc/src/__support/CPP/tuple.h b/libc/src/__support/CPP/tuple.h new file mode 100644 index 0000000000000..cce8e0ef2bfae --- /dev/null +++ b/libc/src/__support/CPP/tuple.h @@ -0,0 +1,144 @@ +//===-- 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 (I == 0) + return t.get_head(); + else + return get(t.get_tail()); +} +template +LIBC_INLINE constexpr const auto &get(const tuple &t) { + if constexpr (I == 0) + return t.get_head(); + else + return get(t.get_tail()); +} +template +LIBC_INLINE constexpr auto &&get(tuple &&t) { + if constexpr (I == 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 (I == 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 diff --git a/libc/src/__support/CPP/utility/integer_sequence.h b/libc/src/__support/CPP/utility/integer_sequence.h index 06643d505aca0..17c3dbfd229cc 100644 --- a/libc/src/__support/CPP/utility/integer_sequence.h +++ b/libc/src/__support/CPP/utility/integer_sequence.h @@ -5,12 +5,15 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H #include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/macros/config.h" +#include + namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -34,6 +37,13 @@ template using make_integer_sequence = typename detail::make_integer_sequence::type; +// index sequence +template +using index_sequence = integer_sequence; +template +using make_index_sequence = + typename detail::make_integer_sequence::type; + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt index 3e1379d812c37..702f788febfe8 100644 --- a/libc/test/src/__support/CPP/CMakeLists.txt +++ b/libc/test/src/__support/CPP/CMakeLists.txt @@ -130,6 +130,16 @@ add_libc_test( libc.src.__support.CPP.optional ) +add_libc_test( + tuple_test + SUITE + libc-cpp-utils-tests + SRCS + tuple_test.cpp + DEPENDS + libc.src.__support.CPP.tuple +) + add_libc_test( span_test SUITE diff --git a/libc/test/src/__support/CPP/tuple_test.cpp b/libc/test/src/__support/CPP/tuple_test.cpp new file mode 100644 index 0000000000000..0b05ae4d97103 --- /dev/null +++ b/libc/test/src/__support/CPP/tuple_test.cpp @@ -0,0 +1,71 @@ +//===-- Unittests for cpp::tuple ------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/CPP/tuple.h" +#include + +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using namespace LIBC_NAMESPACE::cpp; + +TEST(LlvmLibcTupleTest, Construction) { + tuple t(42, 3.14); + EXPECT_EQ(get<0>(t), 42); + EXPECT_FP_EQ(get<1>(t), 3.14); +} + +TEST(LlvmLibcTupleTest, MakeTuple) { + auto t = make_tuple(1, 2.5, 'x'); + EXPECT_EQ(get<0>(t), 1); + EXPECT_FP_EQ(get<1>(t), 2.5); + EXPECT_EQ(get<2>(t), 'x'); +} + +TEST(LlvmLibcTupleTest, TieAssignment) { + int a = 0; + double b = 0; + char c = 0; + auto t = make_tuple(7, 8.5, 'y'); + tie(a, b, c) = t; + EXPECT_EQ(a, 7); + EXPECT_FP_EQ(b, 8.5); + EXPECT_EQ(c, 'y'); +} + +TEST(LlvmLibcTupleTest, StructuredBindings) { + auto t = make_tuple(7, 8.5, 'y'); + auto [x, y, z] = t; + EXPECT_EQ(x, 7); + EXPECT_FP_EQ(y, 8.5); + EXPECT_EQ(z, 'y'); +} + +TEST(LlvmLibcTupleTest, TupleCat) { + tuple t(42, 3.14); + auto t1 = make_tuple(1, 2.5, 'x'); + auto t2 = tuple_cat(t, t1); + EXPECT_EQ(get<0>(t2), 42); + EXPECT_FP_EQ(get<1>(t2), 3.14); + EXPECT_EQ(get<2>(t2), 1); + EXPECT_FP_EQ(get<3>(t2), 2.5); + EXPECT_EQ(get<4>(t2), 'x'); +} + +TEST(LlvmLibcTupleTest, ConstTuple) { + const auto t = make_tuple(100, 200.5); + EXPECT_EQ(get<0>(t), 100); + EXPECT_FP_EQ(get<1>(t), 200.5); +} + +TEST(LlvmLibcTupleTest, RvalueAssignment) { + auto t = make_tuple(0, 0.0); + t = make_tuple(9, 9.5); + EXPECT_EQ(get<0>(t), 9); + EXPECT_FP_EQ(get<1>(t), 9.5); +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index bb76da4153108..46d416357c6cd 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -659,6 +659,14 @@ libc_support_library( ], ) +libc_support_library( + name = "__support_cpp_tuple", + hdrs = ["src/__support/CPP/tuple.h"], + deps = [ + "__support_cpp_utility", + ], +) + libc_support_library( name = "__support_cpp_limits", hdrs = ["src/__support/CPP/limits.h"],