1 // Copyright 2018 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ASTC_CODEC_BASE_TYPE_TRAITS_H_ 16 #define ASTC_CODEC_BASE_TYPE_TRAITS_H_ 17 18 #include <iterator> 19 #include <type_traits> 20 21 namespace astc_codec { 22 namespace base { 23 24 namespace details { 25 26 // a simple helper class for SFINAE below. 27 template<class X = void> 28 struct dummy { 29 using type = X; 30 }; 31 32 } // namespace details 33 34 // add some convenience shortcuts for an overly complex std::enable_if syntax 35 36 // Use 'enable_if<Predicate,Type>' instead of 37 // 'typename std::enable_if<Predicate::value,Type>::type' 38 template<class Predicate, class Type = void*> 39 using enable_if = typename std::enable_if<Predicate::value, Type>::type; 40 41 // Use 'enable_if_c<BooleanFlag,Type>' instead of 42 // 'typename std::enable_if<BooleanFlag,Type>::type' 43 template<bool predicate, class Type = void*> 44 using enable_if_c = typename std::enable_if<predicate, Type>::type; 45 46 // Use 'enable_if_convertible<From,To,Type>' instead of 47 // 'typename std::enable_if<std::is_convertible<From,To>::value, Type>::type' 48 template<class From, class To, class Type = void*> 49 using enable_if_convertible = enable_if<std::is_convertible<From, To>>; 50 51 // ----------------------------------------------------------------------------- 52 // A predicate for checking if some object is callable with a specific 53 // signature. Examples: 54 // 55 // is_callable_as<int, void()>::value == false. 56 // is_callable_as<strcmp, void()>::value == false. 57 // is_callable_as<strcmp, int(const char*, const char*)>::value == true 58 // 59 template<class F, class Signature, class X = void> 60 struct is_callable_as : std::false_type {}; 61 62 // This specialization is SFINAE-d out if template arguments can't be combined 63 // into a call expression F(), or if the result of that call is not |R| 64 template<class F, class R, class... Args> 65 struct is_callable_as<F, R(Args...), 66 typename std::enable_if<std::is_same< 67 typename details::dummy<decltype(std::declval<F>()( 68 std::declval<Args>()...))>::type, 69 R>::value>::type> : std::true_type {}; 70 71 // 72 // A similar predicate to only check arguments of the function call and ignore 73 // the specified return type 74 // 75 // is_callable_as<strcmp, int(const char*, const char*)>::value == true 76 // is_callable_as<strcmp, void(const char*, const char*)>::value == false 77 // is_callable_with_args<strcmp, void(const char*, const char*)>::value == true 78 // 79 template<class F, class Signature, class X = void> 80 struct is_callable_with_args : std::false_type {}; 81 82 template<class F, class R, class... Args> 83 struct is_callable_with_args< 84 F, R(Args...), 85 typename std::enable_if< 86 !std::is_same<typename details::dummy<decltype( 87 std::declval<F>()(std::declval<Args>()...))>::type, 88 F>::value>::type> : std::true_type {}; 89 90 // ----------------------------------------------------------------------------- 91 // Check if a type |T| is any instantiation of a template |U|. Examples: 92 // 93 // is_template_instantiation_of<int, std::vector>::value == false 94 // is_template_instantiation_of< 95 // std::list<std::vector<int>>, std::vector>::value == false 96 // is_template_instantiation_of<std::vector<int>, std::vector>::value == true 97 // is_template_instantiation_of< 98 // std::vector<std::vector<int>>, std::vector>::value == true 99 // 100 template<class T, template<class...> class U> 101 struct is_template_instantiation_of : std::false_type {}; 102 103 template<template<class...> class U, class... Args> 104 struct is_template_instantiation_of<U<Args...>, U> : std::true_type {}; 105 // ----------------------------------------------------------------------------- 106 107 // 108 // is_range<T> - check if type |T| is a range-like type. 109 // 110 // It makes sure that expressions std::begin(t) and std::end(t) are well-formed 111 // and those return the same type. 112 // 113 // Note: with expression SFINAE from C++14 is_range_helper<> could be renamed to 114 // is_range<> with no extra code. C++11 needs an extra level of enable_if<> 115 // to make it work when the type isn't a range. 116 // 117 118 namespace details { 119 120 template<class T> 121 using is_range_helper = std::is_same< 122 decltype(std::begin( 123 std::declval<typename std::add_lvalue_reference<T>::type>())), 124 decltype( 125 std::end(std::declval<typename std::add_lvalue_reference<T>::type>()))>; 126 127 } // namespace details 128 129 template<class T, class = void> 130 struct is_range : std::false_type {}; 131 132 template<class T> 133 struct is_range< 134 T, typename std::enable_if<details::is_range_helper<T>::value>::type> 135 : std::true_type {}; 136 137 //////////////////////////////////////////////////////////////////////////////// 138 // 139 // A class to incapsulate integer sequence 0, 1, ..., <num_args> 140 // Seq<int...> 141 // Useful to pass function parameters in an array/tuple to call it later. 142 // 143 144 template<int...> 145 struct Seq {}; 146 147 // A 'maker' class to construct Seq<int...> given only <num_args> 148 // value. 149 // MakeSeq<N, S...> works this way, e.g. 150 // 151 // MakeSeq<2> inherits MakeSeq<2 - 1, 2 - 1> == MakeSeq<1, 1> 152 // MakeSeq<1, 1> : MakeSeq<1 - 1, 1 - 1, 1> == MakeSeq<0, 0, 1> 153 // MakeSeq<0, 0, 1> == MakeSeq<0, S...> and defines |type| = Seq<0, 1> 154 155 template<int N, int... S> 156 struct MakeSeq : MakeSeq<N - 1, N - 1, S...> {}; 157 158 template<int... S> 159 struct MakeSeq<0, S...> { 160 using type = Seq<S...>; 161 }; 162 163 // 164 // MakeSeqT alias to quickly create Seq<...>: 165 // MakeSeqT<3> == Seq<0, 1, 2> 166 template<int... S> 167 using MakeSeqT = typename MakeSeq<S...>::type; 168 169 } // namespace base 170 } // namespace astc_codec 171 172 #endif // ASTC_CODEC_BASE_TYPE_TRAITS_H_ 173