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