• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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