249 lines
7.1 KiB
C++
249 lines
7.1 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 {
|
|
namespace detail {
|
|
// Call the function for the value at the index `S`, then increment
|
|
// the index and call ourselves again if we haven't reached the end.
|
|
//
|
|
// A detail function is used to simplify the case for empty tuples;
|
|
// ie, we'd like to keep the index assertion, but a constexpr-if won't
|
|
// elide the assertion.
|
|
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)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
/// Call a provided functor of type FunctionT with each value in a
|
|
/// provided tuple-like object TupleT
|
|
template<
|
|
typename FunctionT,
|
|
typename TupleT
|
|
>
|
|
void
|
|
each (FunctionT &&func, TupleT &&value)
|
|
{
|
|
if constexpr (std::tuple_size_v<std::decay_t<TupleT>> > 0) {
|
|
return detail::each (
|
|
std::forward<FunctionT> (func),
|
|
std::forward<TupleT> (value)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
namespace detail {
|
|
template <
|
|
typename TupleT,
|
|
typename FunctionT,
|
|
std::size_t... IndicesV
|
|
>
|
|
bool
|
|
all (TupleT &&val, FunctionT &&pred, std::index_sequence<IndicesV...>)
|
|
{
|
|
return (pred (std::get<IndicesV> (val)) && ...);
|
|
}
|
|
}
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Returns true if all members of the tuple satisfy the predicate.
|
|
template <typename TupleT, typename FunctionT>
|
|
bool
|
|
all (TupleT &&val, FunctionT &&pred)
|
|
{
|
|
return detail::all (
|
|
std::forward<TupleT> (val),
|
|
std::forward<FunctionT> (pred),
|
|
std::make_index_sequence<
|
|
std::tuple_size_v<
|
|
std::remove_cvref_t<TupleT>
|
|
>
|
|
> {}
|
|
);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Returns true if all members of the tuple are convertible to true.
|
|
template <typename TupleT>
|
|
bool
|
|
all (TupleT &&val)
|
|
{
|
|
return all (
|
|
std::forward<TupleT> (val),
|
|
[] (auto const &i) { return bool (i); }
|
|
);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Returns true if none of the members of the tuple satisfy the predicate.
|
|
template <typename TupleT, typename FunctionT>
|
|
bool
|
|
none (TupleT &&val, FunctionT &&pred)
|
|
{
|
|
return all (
|
|
std::forward<TupleT> (val),
|
|
[&pred] (auto &&arg) { return !pred (arg); }
|
|
);
|
|
}
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
/// Returns true if none of the members of the tuple are convertible to
|
|
/// true.
|
|
template <typename TupleT>
|
|
bool
|
|
none (TupleT &&val)
|
|
{
|
|
return all (
|
|
std::forward<TupleT> (val),
|
|
[] (auto const &i) { return !bool (i); }
|
|
);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
namespace detail {
|
|
template <typename FuncT, typename ArgT, std::size_t ...Indices>
|
|
auto
|
|
map (std::index_sequence<Indices...>, FuncT &&func, ArgT &&arg)
|
|
{
|
|
return std::forward_as_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)
|
|
);
|
|
}
|
|
}
|