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