/* * 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 "../types.hpp" #include "../types/traits.hpp" #include #include #include namespace cruft::tuple::type { /////////////////////////////////////////////////////////////////////////// /// Invoke a provided FunctorT with the provided arguments and a /// type_tag for each type in the tuple-like type TupleT. /// /// The order of invocation is low-index to high-index (left to right). /// /// \tparam TupleT A tuple-like type /// \tparam FunctorT An invokable type /// \tparam S The index to be invoked; this is private. /// \tparam ArgsT User supplied arguments template< typename TupleT, typename FunctorT, size_t S = 0, typename ...ArgsT > void each (FunctorT &&func, ArgsT &&...args) { /// Get a handle on the type we need to forward. static_assert (S < std::tuple_size_v); using value_type = typename std::tuple_element::type; /// Call the user's invokable. std::invoke (func, args..., cruft::type_tag {}); /// Recurse into ourselves with a higher index if we haven't reached /// the end. if constexpr (S + 1 < std::tuple_size_v) { each ( std::forward (func), std::forward (args)... ); } } /////////////////////////////////////////////////////////////////////////////// /// Convert a tuple-type holding an initial set of types into a tuple-type /// holding a different set of types using the supplied transform: /// `FieldT<...>`. /// /// \tparam TupleT The initial tuple-type /// \tparam FieldT The type-transform type. /// The conversion uses FieldT<...>::type to perform the /// conversions. template < typename TupleT, template < typename > class FieldT, typename Indices = std::make_index_sequence< std::tuple_size::value > > struct map; //----------------------------------------------------------------------------- template < typename TupleT, template < typename > class FieldT, size_t ...Indices > struct map< TupleT, FieldT, std::index_sequence > { typedef std::tuple< typename FieldT< typename std::tuple_element::type >::type... > type; }; /////////////////////////////////////////////////////////////////////////// /// Query the index of the first occurrence of type `T' in the tuple-like /// type `TupleT'. /// /// If the query type does not occur in the tuple type a compiler error /// should be generated. /// /// \tparam TupleT The tuple-type to be queried /// \tparam ValueT The value-type we are searching for /// /// The index will be defined as the size_t `::value` if it has been found. template< typename TupleT, typename ValueT, typename = std::make_index_sequence< std::tuple_size_v > > struct index { }; //------------------------------------------------------------------------- // specialisation for tuples with matching first elements. the index is 0. template< typename ValueT, typename ...TailT, size_t ...Indices > struct index< std::tuple, ValueT, std::index_sequence > { static constexpr std::size_t value = 0; }; //------------------------------------------------------------------------- // specialisation for tuples with non-matching first elements. // increment and recurse. template< typename ValueT, typename HeadT, typename ...TailT, size_t ...Indices > struct index< std::tuple, ValueT, std::index_sequence > { static constexpr std::size_t value = 1u + index,ValueT>::value; }; //------------------------------------------------------------------------- // convert the tuple type (which is not a tuple or it would have matched // the tuple specialisation, into the equivalent std::tuple and requery // against that. template < typename TupleT, typename ValueT, size_t ...Indices > struct index< TupleT, ValueT, std::index_sequence > { static constexpr std::size_t value = index< std::tuple...>, ValueT, std::index_sequence >::value; }; /////////////////////////////////////////////////////////////////////////// /// Transform a tuple-like type (ie, something that responds to /// tuple_element) into a tuple template < typename TupleT, typename Indices = std::make_index_sequence< std::tuple_size_v > > struct entuple; //------------------------------------------------------------------------- template < typename TupleT, size_t ...Indices > struct entuple< TupleT, std::index_sequence > { using type = std::tuple< std::tuple_element_t... >; }; //------------------------------------------------------------------------- template using entuple_t = typename entuple::type; /////////////////////////////////////////////////////////////////////////// /// Concatenate a variadic collection of tuple-like types template struct cat; //------------------------------------------------------------------------- template <> struct cat<> { using type = std::tuple<>; }; //------------------------------------------------------------------------- template struct cat { using type = decltype( std::tuple_cat ( std::declval< entuple_t > (), std::declval< typename cat::type > () ) ); }; //------------------------------------------------------------------------- template using cat_t = typename cat::type; /////////////////////////////////////////////////////////////////////////// /// Remove a type from a tuple-like type template < typename DoomedT, typename TupleT > struct remove; //------------------------------------------------------------------------- template < typename DoomedT > struct remove< DoomedT, std::tuple<> > { using type = std::tuple<>; }; //------------------------------------------------------------------------- template < typename DoomedT, typename HeadT, typename ...TailT > struct remove< DoomedT, std::tuple > { using type = cat_t< std::conditional_t< std::is_same_v, std::tuple< >, std::tuple >, typename remove>::type >; }; //------------------------------------------------------------------------- template using remove_t = typename remove::type; /////////////////////////////////////////////////////////////////////////// /// Remove duplicate types from the list of held types in a tuple template struct unique; //------------------------------------------------------------------------- template <> struct unique> { using type = std::tuple<>; }; //------------------------------------------------------------------------- template struct unique< std::tuple > { using type = cat_t< std::tuple, typename unique< typename remove< HeadT, std::tuple >::type >::type >; }; //------------------------------------------------------------------------- template using unique_t = typename unique::type; /////////////////////////////////////////////////////////////////////////// /// Convenience accessor for the 'nth' type of a tuple. template struct nth; //------------------------------------------------------------------------- template struct nth,0> { using type = HeadT; }; //------------------------------------------------------------------------- template struct nth,IndexV> : nth,IndexV-1> { }; //------------------------------------------------------------------------- template using nth_t = typename nth::type; /////////////////////////////////////////////////////////////////////////// /// Extract the first CountV types of the tuple-like-object and store them /// in a tuple definition. template < std::size_t CountV, typename TupleT, typename Indices = std::make_index_sequence > struct prefix; //------------------------------------------------------------------------- template < std::size_t CountV, typename TupleT, std::size_t ...IndexV > struct prefix< CountV, TupleT, std::index_sequence > { using type = std::tuple< std::tuple_element_t... >; }; //------------------------------------------------------------------------- template using prefix_t = typename prefix::type; };