File tuple_tools.h
File List > code_source > templat > include > TempLat > util > tuple_tools.h
Go to the documentation of this file
#ifndef TEMPLAT_UTIL_TUPLETOOLS_H
#define TEMPLAT_UTIL_TUPLETOOLS_H
/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
Released under the MIT license, see LICENSE.md. */
#include <tuple>
#include <functional>
#include "TempLat/parallel/device.h"
namespace TempLat
{
// If you wonder about how performant this is, take a look at https://godbolt.org/z/d33cMaEG1
template <size_t i, typename Head, typename... Tail>
requires(i <= sizeof...(Tail))
DEVICE_INLINE_FUNCTION constexpr auto tuple_last(const device::tuple<Head, Tail...> &t)
{
static_assert(i <= sizeof...(Tail), "Cannot take a longer tail than the tuple.");
if constexpr (sizeof...(Tail) + 1 == i)
return device::apply([](auto &head, auto &...tail) { return device::tie(head, tail...); }, t);
else if constexpr (sizeof...(Tail) == i)
return device::apply([](auto & /*head*/, auto &...tail) { return device::tie(tail...); }, t);
else
return device::apply([](auto & /*head*/, auto &...tail) { return tuple_last<i>(device::tie(tail...)); }, t);
}
template <int i, typename Head, typename... Tail>
DEVICE_INLINE_FUNCTION constexpr auto tuple_first(const device::tuple<Head, Tail...> &t)
{
static_assert(i <= sizeof...(Tail), "Cannot take a longer sequence than the tuple.");
static_assert(i >= 0, "Cannot take a longer sequence than the tuple.");
if constexpr (i == 0)
return device::tuple();
else if constexpr (i == 1)
return device::apply([](auto &head, auto &.../*tail*/) { return device::tie(head); }, t);
else
return device::apply(
[](auto &head, auto &...tail) {
return device::tuple_cat(device::tie(head), tuple_first<i - 1>(device::tie(tail...)));
},
t);
}
template <size_t n, int add, typename... IDX>
DEVICE_INLINE_FUNCTION constexpr auto tuple_add_to_nth_mod(device::tuple<IDX...> &tt)
{
static_assert(n < sizeof...(IDX));
device::get<n>(tt) += add;
return tt;
}
template <size_t n, int add, typename... IDX>
DEVICE_INLINE_FUNCTION constexpr auto tuple_add_to_nth(const device::tuple<IDX...> &tt)
{
constexpr int len = sizeof...(IDX);
if constexpr (n >= 1) {
return device::tuple_cat(tuple_first<n>(tt), device::make_tuple((int)device::get<n>(tt) + add),
tuple_last<len - n - 1>(tt));
} else if constexpr (n == 0) {
return device::tuple_cat(device::make_tuple((int)device::get<0>(tt) + add), tuple_last<len - 1>(tt));
}
}
template <typename... Args, std::size_t... Is>
DEVICE_INLINE_FUNCTION auto reverse_tuple(const device::tuple<Args...> &tuple, std::index_sequence<Is...>)
{
return device::tie(device::get<sizeof...(Args) - 1 - Is>(tuple)...);
}
template <typename... Args> DEVICE_INLINE_FUNCTION auto reverse_tuple(const device::tuple<Args...> &tuple)
{
return reverse_tuple(tuple, std::make_index_sequence<sizeof...(Args)>());
}
template <typename Arg, size_t N, std::size_t... Is>
DEVICE_INLINE_FUNCTION auto reverse_array(const device::array<Arg, N> &array, std::index_sequence<Is...>)
{
return device::array<Arg, N>{{device::get<N - 1 - Is>(array)...}};
}
template <typename Arg, size_t N> DEVICE_INLINE_FUNCTION auto reverse_array(const device::array<Arg, N> &array)
{
return reverse_array(array, std::make_index_sequence<N>());
}
template <typename T, T... I> constexpr auto make_tuple_sequence_helper(std::integer_sequence<T, I...>)
{
return device::make_tuple(I...);
}
template <std::size_t I, typename T = std::size_t> constexpr auto make_tuple_sequence()
{
return make_tuple_sequence_helper(std::make_integer_sequence<T, I>());
}
} // namespace TempLat
#endif