Skip to content

Commit

Permalink
feat: Implement tuple_cat
Browse files Browse the repository at this point in the history
  • Loading branch information
Tradias committed Sep 16, 2024
1 parent f08232b commit b1535c0
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
51 changes: 49 additions & 2 deletions src/ltpl/tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef LTPL_LTPL_TUPLE_HPP
#define LTPL_LTPL_TUPLE_HPP

#include <array>
#include <cstddef>
#include <type_traits>
#include <utility>
Expand All @@ -17,6 +18,9 @@ class Tuple;

namespace detail
{
template <class... T>
struct TypeList;

// A type that can be constructed from anything, useful for extracting the nth-element of a type list later.
template <std::size_t>
struct Anything
Expand Down Expand Up @@ -200,14 +204,23 @@ template <std::size_t... Ns>
struct GetNth
{
template <class Nth>
constexpr Nth& operator()(Anything<Ns>..., Nth& nth, auto&...) noexcept
constexpr Nth&& operator()(Anything<Ns>..., Nth&& nth, auto&&...) noexcept
{
return nth;
return static_cast<Nth&&>(nth);
}
};

// An implementation of nth-element similar to the `Concept expansion` described by Kris Jusiak in his talk `The Nth
// Element: A Case Study - CppNow 2022` but compatible with every C++20 compiler and easily backportable to C++14.
template <std::size_t I, class... T>
constexpr decltype(auto) get_nth(T&&... t) noexcept
{
return [&]<std::size_t... Ns>(std::index_sequence<Ns...>) -> decltype(auto)
{
return GetNth<Ns...>{}(static_cast<T&&>(t)...);
}(std::make_index_sequence<I>{});
}

template <std::size_t I, class... T>
constexpr decltype(auto) get(ltpl::Tuple<T...>& tuple) noexcept
{
Expand All @@ -231,6 +244,12 @@ constexpr bool all_true(bool const (&array)[N]) noexcept
}
return true;
}

struct TupleCatIndex
{
std::size_t outer;
std::size_t inner;
};
} // namespace detail

template <class... T>
Expand Down Expand Up @@ -460,6 +479,34 @@ template <class... T>
{
return Tuple<T&&...>(static_cast<T&&>(v)...);
}

template <class... Tuples>
[[nodiscard]] constexpr decltype(auto) tuple_cat(Tuples&&... tuples) noexcept
{
constexpr auto total_size = (std::tuple_size_v<std::remove_cvref_t<Tuples>> + ...);
constexpr auto indices = [&]
{
std::array<detail::TupleCatIndex, total_size> array{};
size_t i{};
for (std::size_t outer{}; auto tuple_size : {std::tuple_size_v<std::remove_cvref_t<Tuples>>...})
{
for (size_t inner{}; inner != tuple_size; ++inner)
{
array[i] = {outer, inner};
++i;
}
++outer;
}
return array;
}();
return [&]<std::size_t... I>(std::index_sequence<I...>)
{
using Ret =
Tuple<std::tuple_element_t<indices[I].inner, std::remove_cvref_t<decltype(detail::get_nth<indices[I].outer>(
static_cast<Tuples&&>(tuples)...))>>...>;
return Ret{ltpl::get<indices[I].inner>(detail::get_nth<indices[I].outer>(static_cast<Tuples&&>(tuples)...))...};
}(std::make_index_sequence<total_size>{});
}
} // namespace ltpl

template <std::size_t I, class... T>
Expand Down
4 changes: 4 additions & 0 deletions test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <test.hpp>
#include <test/framework.hpp>
#include <test_cat.hpp>
#include <test_comparison.hpp>
#include <test_constructor.hpp>
#include <test_copy_assignment.hpp>
Expand Down Expand Up @@ -172,6 +173,9 @@ int main()
run_test<&test_tie>();
run_test<&test_make_tuple>();

// test_cat
run_test<&test_tuple_cat>();

print_test_results();
return context.failed_tests;
}
30 changes: 30 additions & 0 deletions test/test_cat.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2022 Dennis Hezel
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

#ifndef LTPL_TEST_TEST_CAT_HPP
#define LTPL_TEST_TEST_CAT_HPP

#include <ltpl/tuple.hpp>
#include <test/factory.hpp>
#include <test/framework.hpp>
#include <test/utility.hpp>

namespace test
{
void test_tuple_cat()
{
static constexpr Immovable move_only{1};
static constexpr ltpl::Tuple<const Immovable&, double> tuple{move_only, 12.};
static constexpr auto tuple2 = ltpl::tuple_cat(tuple, ltpl::Tuple<int>{});
CHECK(std::is_same_v<const ltpl::Tuple<const Immovable&, double, int>, decltype(tuple2)>);
int i = 42;
auto tuple3 = ltpl::tuple_cat(tuple, ltpl::Tuple<int&&>{std::move(i)});
CHECK(std::is_same_v<ltpl::Tuple<const Immovable&, double, int&&>, decltype(tuple3)>);
CHECK_EQ(12., ltpl::get<1>(tuple3));
CHECK_EQ(42, ltpl::get<2>(tuple3));
}
} // namespace test

#endif // LTPL_TEST_TEST_CAT_HPP

0 comments on commit b1535c0

Please sign in to comment.