Skip to content

Commit b1535c0

Browse files
committed
feat: Implement tuple_cat
1 parent f08232b commit b1535c0

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

src/ltpl/tuple.hpp

+49-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef LTPL_LTPL_TUPLE_HPP
77
#define LTPL_LTPL_TUPLE_HPP
88

9+
#include <array>
910
#include <cstddef>
1011
#include <type_traits>
1112
#include <utility>
@@ -17,6 +18,9 @@ class Tuple;
1718

1819
namespace detail
1920
{
21+
template <class... T>
22+
struct TypeList;
23+
2024
// A type that can be constructed from anything, useful for extracting the nth-element of a type list later.
2125
template <std::size_t>
2226
struct Anything
@@ -200,14 +204,23 @@ template <std::size_t... Ns>
200204
struct GetNth
201205
{
202206
template <class Nth>
203-
constexpr Nth& operator()(Anything<Ns>..., Nth& nth, auto&...) noexcept
207+
constexpr Nth&& operator()(Anything<Ns>..., Nth&& nth, auto&&...) noexcept
204208
{
205-
return nth;
209+
return static_cast<Nth&&>(nth);
206210
}
207211
};
208212

209213
// An implementation of nth-element similar to the `Concept expansion` described by Kris Jusiak in his talk `The Nth
210214
// Element: A Case Study - CppNow 2022` but compatible with every C++20 compiler and easily backportable to C++14.
215+
template <std::size_t I, class... T>
216+
constexpr decltype(auto) get_nth(T&&... t) noexcept
217+
{
218+
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) -> decltype(auto)
219+
{
220+
return GetNth<Ns...>{}(static_cast<T&&>(t)...);
221+
}(std::make_index_sequence<I>{});
222+
}
223+
211224
template <std::size_t I, class... T>
212225
constexpr decltype(auto) get(ltpl::Tuple<T...>& tuple) noexcept
213226
{
@@ -231,6 +244,12 @@ constexpr bool all_true(bool const (&array)[N]) noexcept
231244
}
232245
return true;
233246
}
247+
248+
struct TupleCatIndex
249+
{
250+
std::size_t outer;
251+
std::size_t inner;
252+
};
234253
} // namespace detail
235254

236255
template <class... T>
@@ -460,6 +479,34 @@ template <class... T>
460479
{
461480
return Tuple<T&&...>(static_cast<T&&>(v)...);
462481
}
482+
483+
template <class... Tuples>
484+
[[nodiscard]] constexpr decltype(auto) tuple_cat(Tuples&&... tuples) noexcept
485+
{
486+
constexpr auto total_size = (std::tuple_size_v<std::remove_cvref_t<Tuples>> + ...);
487+
constexpr auto indices = [&]
488+
{
489+
std::array<detail::TupleCatIndex, total_size> array{};
490+
size_t i{};
491+
for (std::size_t outer{}; auto tuple_size : {std::tuple_size_v<std::remove_cvref_t<Tuples>>...})
492+
{
493+
for (size_t inner{}; inner != tuple_size; ++inner)
494+
{
495+
array[i] = {outer, inner};
496+
++i;
497+
}
498+
++outer;
499+
}
500+
return array;
501+
}();
502+
return [&]<std::size_t... I>(std::index_sequence<I...>)
503+
{
504+
using Ret =
505+
Tuple<std::tuple_element_t<indices[I].inner, std::remove_cvref_t<decltype(detail::get_nth<indices[I].outer>(
506+
static_cast<Tuples&&>(tuples)...))>>...>;
507+
return Ret{ltpl::get<indices[I].inner>(detail::get_nth<indices[I].outer>(static_cast<Tuples&&>(tuples)...))...};
508+
}(std::make_index_sequence<total_size>{});
509+
}
463510
} // namespace ltpl
464511

465512
template <std::size_t I, class... T>

test/main.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <test.hpp>
77
#include <test/framework.hpp>
8+
#include <test_cat.hpp>
89
#include <test_comparison.hpp>
910
#include <test_constructor.hpp>
1011
#include <test_copy_assignment.hpp>
@@ -172,6 +173,9 @@ int main()
172173
run_test<&test_tie>();
173174
run_test<&test_make_tuple>();
174175

176+
// test_cat
177+
run_test<&test_tuple_cat>();
178+
175179
print_test_results();
176180
return context.failed_tests;
177181
}

test/test_cat.hpp

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2022 Dennis Hezel
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
#ifndef LTPL_TEST_TEST_CAT_HPP
7+
#define LTPL_TEST_TEST_CAT_HPP
8+
9+
#include <ltpl/tuple.hpp>
10+
#include <test/factory.hpp>
11+
#include <test/framework.hpp>
12+
#include <test/utility.hpp>
13+
14+
namespace test
15+
{
16+
void test_tuple_cat()
17+
{
18+
static constexpr Immovable move_only{1};
19+
static constexpr ltpl::Tuple<const Immovable&, double> tuple{move_only, 12.};
20+
static constexpr auto tuple2 = ltpl::tuple_cat(tuple, ltpl::Tuple<int>{});
21+
CHECK(std::is_same_v<const ltpl::Tuple<const Immovable&, double, int>, decltype(tuple2)>);
22+
int i = 42;
23+
auto tuple3 = ltpl::tuple_cat(tuple, ltpl::Tuple<int&&>{std::move(i)});
24+
CHECK(std::is_same_v<ltpl::Tuple<const Immovable&, double, int&&>, decltype(tuple3)>);
25+
CHECK_EQ(12., ltpl::get<1>(tuple3));
26+
CHECK_EQ(42, ltpl::get<2>(tuple3));
27+
}
28+
} // namespace test
29+
30+
#endif // LTPL_TEST_TEST_CAT_HPP

0 commit comments

Comments
 (0)