/* * 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 */ #ifndef CRUFT_UTIL_TUPLE_TYPE_HPP #define CRUFT_UTIL_TUPLE_TYPE_HPP #include "../types.hpp" #include "../types/traits.hpp" #include #include namespace util::tuple::type { /////////////////////////////////////////////////////////////////////////// /// call a provided FunctorT with type_tag for each type in the /// tuple-like type TupleT. template< typename TupleT, typename FunctorT, size_t S = 0 > void each (FunctorT &&func) { static_assert (S < std::tuple_size_v); using value_type = typename std::tuple_element::type; func (util::type_tag {}); if constexpr (S + 1 < std::tuple_size_v) { each (std::forward (func)); } } /////////////////////////////////////////////////////////////////////////////// /// Statically map the member types of a tuple via F<>::type /// /// TupleT: tuple type /// FieldT: type mapping object, conversion uses FieldT<>::type /// Indices: tuple indexing helper 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. 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; /////////////////////////////////////////////////////////////////////////// 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; } #endif