libcruft-util/tuple/value.hpp

151 lines
4.2 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "index.hpp"
#include "../types.hpp"
#include <cstddef>
#include <functional>
#include <tuple>
#include <utility>
namespace cruft::tuple::value {
///////////////////////////////////////////////////////////////////////////
/// Call a provided functor of type FunctionT with each value in a
/// provided tuple-like object TupleT
template<
typename FunctionT,
typename TupleT,
std::size_t S = 0
>
void
each (FunctionT &&func, TupleT &&value)
{
using tuple_t = std::decay_t<TupleT>;
static_assert (S < std::tuple_size_v<tuple_t>);
std::invoke (func, std::get<S> (value));
if constexpr (S + 1 < std::tuple_size_v<tuple_t>) {
each<FunctionT,TupleT,S+1> (std::forward<FunctionT> (func), std::forward<TupleT> (value));
}
}
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename FuncT, typename ArgT, std::size_t ...Indices>
auto
map (std::index_sequence<Indices...>, FuncT &&func, ArgT &&arg)
{
return std::tuple (
std::invoke (func, std::get<Indices> (arg))...
);
}
};
/// returns a tuple of the result of applying the provided function to
/// each value of the supplied tuple.
template <
typename FuncT,
typename ArgT,
typename IndicesV = std::make_index_sequence<
std::tuple_size_v<std::decay_t<ArgT>>
>
>
auto map (FuncT &&func, ArgT &&arg)
{
return detail::map (
IndicesV{},
std::forward<FuncT> (func),
std::forward<ArgT> (arg)
);
}
///////////////////////////////////////////////////////////////////////////
// return a tuple that contains the 'nth' element from each of the supplied
// tuple-like arguments
template <size_t N, typename ...TupleT>
auto
nth (TupleT&&...args)
{
return std::make_tuple (
std::get<N> (args)...
);
}
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename ...TupleT, size_t ...Elements>
auto
zip (std::index_sequence<Elements...>, TupleT &&...args)
{
return std::make_tuple (
nth<Elements> (args...)...
);
}
};
/// converts m arguments of n-tuples into one m-tuple of n-tuples by taking
/// successive elements from each argument tuple.
///
/// eg, zip (('a', 1.f), (0, nullptr)) becomes (('a', 0), (1.f, nullptr))
template <typename ...Args >
auto
zip (Args &&...args)
{
static_assert (sizeof...(args) > 0);
// ensure all the types have the same static size
using all_t = std::tuple<std::decay_t<Args>...>;
using first_t = std::tuple_element_t<0,all_t>;
static constexpr auto arity = std::tuple_size_v<first_t>;
static_assert ((
(arity == std::tuple_size_v<std::decay_t<Args>>) && ...
));
return detail::zip (
std::make_index_sequence<arity> {},
std::forward<Args> (args)...
);
}
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename TupleT, size_t ...Indices>
auto
reverse (index::indices<Indices...>, TupleT &&val)
{
return std::make_tuple (
std::get<Indices> (val)...
);
}
};
//-------------------------------------------------------------------------
template <typename TupleT>
auto
reverse (TupleT &&val)
{
return detail::reverse (
index::make_reverse_t<
std::tuple_size_v<std::decay_t<TupleT>>
> {},
std::forward<TupleT> (val)
);
}
}