/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2012-2017 Danny Robson */ #ifndef CRUFT_UTIL_TYPES_TRAITS_HPP #define CRUFT_UTIL_TYPES_TRAITS_HPP #include #include /////////////////////////////////////////////////////////////////////////////// /// applies a series of type-modifiers to a provided type. /// /// modifiers are applied in the order they are provided. /// /// use without any modifiers results in the identity modifier. namespace util { //------------------------------------------------------------------------- template class ...ModifierT> struct compose; //------------------------------------------------------------------------- template struct compose { using type = TypeT; }; //------------------------------------------------------------------------- template < typename TypeT, template class HeadT, template class ...TailT > struct compose : public compose< typename HeadT::type, TailT... > { }; //------------------------------------------------------------------------- template class ...Args> using chain_t = typename compose::type; } /////////////////////////////////////////////////////////////////////////////// template struct is_dereferencable : std::false_type { }; template struct is_dereferencable : std::true_type { }; template struct is_dereferencable> : std::true_type { }; template struct is_dereferencable> : std::true_type { }; template struct is_dereferencable> : std::true_type { }; /////////////////////////////////////////////////////////////////////////////// template struct dereferenced_type { typedef typename std::enable_if< std::is_pointer::value, std::remove_pointer >::type type; }; //----------------------------------------------------------------------------- template struct dereferenced_type> { typedef T type; }; template struct dereferenced_type> { typedef T type; }; template struct dereferenced_type> { typedef T type; }; /////////////////////////////////////////////////////////////////////////////// /// find the unsigned version of a type if one exists template struct try_unsigned { typedef typename std::make_unsigned::type type; }; //----------------------------------------------------------------------------- template <> struct try_unsigned { typedef double type; }; template <> struct try_unsigned { typedef float type; }; /////////////////////////////////////////////////////////////////////////////// /// find the signed version of a type if one exists template struct try_signed { typedef typename std::make_signed::type type; }; //----------------------------------------------------------------------------- template <> struct try_signed { typedef double type; }; template <> struct try_signed { typedef float type; }; /////////////////////////////////////////////////////////////////////////////// /// checks if a type can be converted in all cases without modification template struct is_lossless_cast : std::enable_if< std::is_integral::value && std::is_integral::value && std::is_signed::value == std::is_signed::value && sizeof (T) <= sizeof (U), std::true_type >::value { }; /////////////////////////////////////////////////////////////////////////////// template struct remove_restrict { using type = T; }; template struct remove_restrict { using type = T*; }; template using remove_restrict_t = typename remove_restrict::type; /////////////////////////////////////////////////////////////////////////////// /// removes the noexcept type specifier from invokable types namespace detail { template struct remove_noexcept { using type = T; }; //------------------------------------------------------------------------- template struct remove_noexcept { using type = ResultT(&)(Args...); }; //------------------------------------------------------------------------- template struct remove_noexcept { using type = ResultT(*const)(Args...); }; //------------------------------------------------------------------------- template struct remove_noexcept { using type = ResultT(*)(Args...); }; //------------------------------------------------------------------------- template struct remove_noexcept { using type = ResultT(ClassT::*)(Args...); }; //------------------------------------------------------------------------- template struct remove_noexcept { using type = ResultT(ClassT::*)(Args...) const; }; }; //----------------------------------------------------------------------------- template struct remove_noexcept : public detail::remove_noexcept { }; //----------------------------------------------------------------------------- template using remove_noexcept_t = typename remove_noexcept::type; /////////////////////////////////////////////////////////////////////////////// /// removes any `const' qualifier from the supplied member function template struct remove_member_const { using type = FuncT; }; //----------------------------------------------------------------------------- template struct remove_member_const { using type = ReturnT(ClassT::*const)(Args...); }; //----------------------------------------------------------------------------- template struct remove_member_const { using type = ReturnT(ClassT::*)(Args...); }; /////////////////////////////////////////////////////////////////////////////// /// type traits class for querying invokable type return values and argument /// types. /// /// if the type is invokable the alias `return_type' will be defined for the /// return type, and the alias tuple `argument_types' will be defined for the /// arguments; namespace detail { template struct func_traits { }; //------------------------------------------------------------------------- template struct func_traits { using return_type = ResultT; using argument_types = std::tuple; }; //------------------------------------------------------------------------- template struct func_traits { using return_type = ResultT; using argument_types = std::tuple; }; //------------------------------------------------------------------------- template struct func_traits { using return_type = ResultT; using argument_types = std::tuple; }; }; //----------------------------------------------------------------------------- template struct func_traits : public ::detail::func_traits< // we apply as many transforms as possible before palming it off to the // detail class so that we don't have to write as many distinct cases. ::util::chain_t > { // we may as well record the underlying type here. it might prove useful // to someone. using type = T; }; /////////////////////////////////////////////////////////////////////////////// template struct function_argument_count : public std::integral_constant< size_t, std::tuple_size_v< typename func_traits::argument_types > > { }; //----------------------------------------------------------------------------- template constexpr auto function_argument_count_v = function_argument_count::value; /////////////////////////////////////////////////////////////////////////////// template struct nth_argument : std::tuple_element< N, typename func_traits::argument_types > { }; template using nth_argument_t = typename nth_argument::type; /////////////////////////////////////////////////////////////////////////////// template > struct is_container : public std::false_type {}; template struct is_container< T, std::void_t< typename T::value_type, typename T::reference, typename T::const_reference, typename T::iterator, typename T::const_iterator, typename T::difference_type, typename T::size_type > > : public std::true_type {}; template struct is_container> : public std::true_type {}; template constexpr auto is_container_v = is_container::value; /////////////////////////////////////////////////////////////////////////////// #include #include #include template struct is_contiguous : public std::false_type {}; template struct is_contiguous> : public std::true_type {}; template struct is_contiguous>: public std::true_type {}; template struct is_contiguous>: public std::true_type {}; template constexpr auto is_contiguous_v = is_contiguous::value; /////////////////////////////////////////////////////////////////////////////// /// stores the type of '::value_type' for a given type, or the type itself if /// it does not have such a type. template > struct inner_type { using type = ValueT; }; //----------------------------------------------------------------------------- template struct inner_type< ValueT, std::void_t > { using type = typename ValueT::value_type; }; //----------------------------------------------------------------------------- template using inner_type_t = typename inner_type::type; /////////////////////////////////////////////////////////////////////////////// template < template class TemplateT, typename QueryT > struct is_same_template_template : public std::false_type {}; //----------------------------------------------------------------------------- template < template class TemplateT, template class QueryT, typename ...Args > struct is_same_template_template< TemplateT, QueryT > : public std::conditional_t< std::is_same_v< TemplateT, QueryT >, std::true_type, std::false_type > { }; //----------------------------------------------------------------------------- template