/* * 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 */ #pragma once #include "index.hpp" #include "../types.hpp" #include #include #include #include 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; static_assert (S < std::tuple_size_v); std::invoke (func, std::get (value)); if constexpr (S + 1 < std::tuple_size_v) { each ( std::forward (func), std::forward (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> > 0) { return detail::each ( std::forward (func), std::forward (value) ); } } /////////////////////////////////////////////////////////////////////////// namespace detail { template < typename TupleT, typename FunctionT, std::size_t... IndicesV > bool all (TupleT &&val, FunctionT &&pred, std::index_sequence) { return (pred (std::get (val)) && ...); } } ///------------------------------------------------------------------------ /// Returns true if all members of the tuple satisfy the predicate. template bool all (TupleT &&val, FunctionT &&pred) { return detail::all ( std::forward (val), std::forward (pred), std::make_index_sequence< std::tuple_size_v< std::remove_cvref_t > > {} ); } ///------------------------------------------------------------------------ /// Returns true if all members of the tuple are convertible to true. template bool all (TupleT &&val) { return all ( std::forward (val), [] (auto const &i) { return bool (i); } ); } ///------------------------------------------------------------------------ /// Returns true if none of the members of the tuple satisfy the predicate. template bool none (TupleT &&val, FunctionT &&pred) { return all ( std::forward (val), [&pred] (auto &&arg) { return !pred (arg); } ); } ///------------------------------------------------------------------------ /// Returns true if none of the members of the tuple are convertible to /// true. template bool none (TupleT &&val) { return all ( std::forward (val), [] (auto const &i) { return !bool (i); } ); } /////////////////////////////////////////////////////////////////////////// namespace detail { template auto map (std::index_sequence, FuncT &&func, ArgT &&arg) { return std::tuple ( std::invoke (func, std::get (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> > > auto map (FuncT &&func, ArgT &&arg) { return detail::map ( IndicesV{}, std::forward (func), std::forward (arg) ); } /////////////////////////////////////////////////////////////////////////// // return a tuple that contains the 'nth' element from each of the supplied // tuple-like arguments template auto nth (TupleT&&...args) { return std::make_tuple ( std::get (args)... ); } /////////////////////////////////////////////////////////////////////////// namespace detail { template auto zip (std::index_sequence, TupleT &&...args) { return std::make_tuple ( nth (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 auto zip (Args &&...args) { static_assert (sizeof...(args) > 0); // ensure all the types have the same static size using all_t = std::tuple...>; using first_t = std::tuple_element_t<0,all_t>; static constexpr auto arity = std::tuple_size_v; static_assert (( (arity == std::tuple_size_v>) && ... )); return detail::zip ( std::make_index_sequence {}, std::forward (args)... ); } /////////////////////////////////////////////////////////////////////////// namespace detail { template auto reverse (index::indices, TupleT &&val) { return std::make_tuple ( std::get (val)... ); } }; //------------------------------------------------------------------------- template auto reverse (TupleT &&val) { return detail::reverse ( index::make_reverse_t< std::tuple_size_v> > {}, std::forward (val) ); } /////////////////////////////////////////////////////////////////////////// namespace detail { template // requires ( // std::is_convertible_v< // std::tuple_element_t, // std::common_type< // std::tuple_element_t... // > // > && ... // ) auto transform_array (std::index_sequence, FunctionT &&func, TupleT &&val) { using value_type = std::common_type_t< std::invoke_result_t< FunctionT, std::tuple_element_t> >... >; constexpr auto arity = std::tuple_size_v< std::remove_cvref_t >; return std::array { { value_type (std::invoke (func, std::get (val)))... } }; } } ///------------------------------------------------------------------------ /// Transform each element of a tuple with the supplied function and /// return an array of the return values. /// /// The function must return types that have a computable common type. template auto transform_array (FunctionT &&func, TupleT &&val) { return detail::transform_array ( std::make_index_sequence< std::tuple_size_v< std::remove_cvref_t > > {}, std::forward (func), std::forward (val ) ); } }