OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 * | 6 * |
7 * | 7 * |
8 * This header provides some of the helpers (std::integral_constant) and | 8 * This header provides some of the helpers (std::integral_constant) and |
9 * type transformations (std::conditional) which will become available with | 9 * type transformations (std::conditional) which will become available with |
10 * C++11 in the type_traits header. | 10 * C++11 in the type_traits header. |
11 * | |
12 * Because we lack constexpr, we cannot mimic | |
13 * std::integral_constant::'constexpr operator T()'. | |
14 * As a result we introduce SkTBool and SkTIf similar to Boost in order to | |
15 * minimize the visual noise of many uses of '::value'. | |
16 */ | 11 */ |
17 | 12 |
18 #ifndef SkTLogic_DEFINED | 13 #ifndef SkTLogic_DEFINED |
19 #define SkTLogic_DEFINED | 14 #define SkTLogic_DEFINED |
20 | 15 |
21 #include <stdint.h> | 16 #include <stdint.h> |
22 | 17 |
23 /** Represents a templated integer constant. | 18 namespace skstd { |
24 * Pre-C++11 version of std::integral_constant. | 19 |
25 */ | 20 template <typename T, T v> struct integral_constant { |
26 template <typename T, T v> struct SkTIntegralConstant { | 21 static const/*expr*/ T value = v; |
27 static const T value = v; | 22 using value_type = T; |
28 typedef T value_type; | 23 using type = integral_constant<T, v>; |
29 typedef SkTIntegralConstant<T, v> type; | 24 //constexpr operator value_type() const noexcept { return value; } |
| 25 //constexpr value_type operator()() const noexcept { return value; } |
30 }; | 26 }; |
31 | 27 |
32 /** Convenience specialization of SkTIntegralConstant. */ | 28 template <bool B> using bool_constant = integral_constant<bool, B>; |
33 template <bool b> struct SkTBool : SkTIntegralConstant<bool, b> { }; | |
34 | 29 |
35 /** Pre-C++11 version of std::is_empty<T>. */ | 30 using true_type = bool_constant<true>; |
36 template <typename T> | 31 using false_type = bool_constant<false>; |
37 class SkTIsEmpty { | 32 |
38 struct Derived : public T { char unused; }; | 33 template <bool B, typename T, typename F> struct conditional { using type = T; }
; |
39 public: | 34 template <typename T, typename F> struct conditional<false, T, F> { using type =
F; }; |
| 35 template <bool B, typename T, typename F> using conditional_t = typename conditi
onal<B, T, F>::type; |
| 36 |
| 37 template <bool B, typename T = void> struct enable_if { using type = T; }; |
| 38 template <typename T> struct enable_if<false, T> {}; |
| 39 template <bool B, typename T = void> using enable_if_t = typename enable_if<B, T
>::type; |
| 40 |
| 41 template <typename T> struct remove_const { using type = T; }; |
| 42 template <typename T> struct remove_const<const T> { using type = T; }; |
| 43 template <typename T> using remove_const_t = typename remove_const<T>::type; |
| 44 |
| 45 template <typename T> struct remove_volatile { using type = T; }; |
| 46 template <typename T> struct remove_volatile<volatile T> { using type = T; }; |
| 47 template <typename T> using remove_volatile_t = typename remove_volatile<T>::typ
e; |
| 48 |
| 49 template <typename T> struct remove_cv { using type = remove_volatile_t<remove_c
onst_t<T>>; }; |
| 50 template <typename T> using remove_cv_t = typename remove_cv<T>::type; |
| 51 |
| 52 template <typename T> struct remove_reference { using type = T; }; |
| 53 template <typename T> struct remove_reference<T&> { using type = T; }; |
| 54 template <typename T> struct remove_reference<T&&> { using type = T; }; |
| 55 template <typename T> using remove_reference_t = typename remove_reference<T>::t
ype; |
| 56 |
| 57 template <typename T, typename U> struct is_same : false_type {}; |
| 58 template <typename T> struct is_same<T, T> : true_type {}; |
| 59 |
| 60 template <typename T> struct is_void : is_same<void, remove_cv_t<T>> {}; |
| 61 |
| 62 template <typename T> struct is_const : false_type {}; |
| 63 template <typename T> struct is_const<const T> : true_type {}; |
| 64 |
| 65 template <typename T> struct is_volatile : false_type {}; |
| 66 template <typename T> struct is_volatile<volatile T> : true_type {}; |
| 67 |
| 68 template <typename T> struct is_reference : false_type {}; |
| 69 template <typename T> struct is_reference<T&> : true_type {}; |
| 70 template <typename T> struct is_reference<T&&> : true_type {}; |
| 71 |
| 72 template <typename T> struct is_lvalue_reference : false_type {}; |
| 73 template <typename T> struct is_lvalue_reference<T&> : true_type {}; |
| 74 |
| 75 template <typename T> struct is_empty_detector { |
| 76 struct Derived : public remove_cv_t<T> { char unused; }; |
40 static const bool value = sizeof(Derived) == sizeof(char); | 77 static const bool value = sizeof(Derived) == sizeof(char); |
41 }; | 78 }; |
| 79 template <typename T> struct is_empty : bool_constant<is_empty_detector<T>::valu
e> {}; |
42 | 80 |
43 /** Pre-C++11 version of std::true_type. */ | 81 template <typename T> struct add_const { using type = const T; }; |
44 typedef SkTBool<true> SkTrue; | 82 template <typename T> using add_const_t = typename add_const<T>::type; |
45 | 83 |
46 /** Pre-C++11 version of std::false_type. */ | 84 template <typename T> struct add_volatile { using type = volatile T; }; |
47 typedef SkTBool<false> SkFalse; | 85 template <typename T> using add_volatile_t = typename add_volatile<T>::type; |
48 | 86 |
49 /** SkTIf_c::type = (condition) ? T : F; | 87 template <typename T> struct add_cv { using type = add_volatile_t<add_const_t<T>
>; }; |
50 * Pre-C++11 version of std::conditional. | 88 template <typename T> using add_cv_t = typename add_cv<T>::type; |
51 */ | 89 |
52 template <bool condition, typename T, typename F> struct SkTIf_c { | 90 template <typename T> struct add_rvalue_reference { |
53 typedef F type; | 91 using type = conditional_t<is_void<T>::value || is_reference<T>::value, T, T
&&>; |
54 }; | 92 }; |
55 template <typename T, typename F> struct SkTIf_c<true, T, F> { | 93 template <typename T> using add_rvalue_reference_t = typename add_rvalue_referen
ce<T>::type; |
56 typedef T type; | 94 |
| 95 } // namespace skstd |
| 96 |
| 97 // The sknonstd namespace contains things we would like to be proposed and feel
std-ish. |
| 98 namespace sknonstd { |
| 99 |
| 100 // The name 'copy' here is fraught with peril. In this case it means 'append', n
ot 'overwrite'. |
| 101 // Alternate proposed names are 'propagate', 'augment', or 'append' (and 'add',
but already taken). |
| 102 // std::experimental::propagate_const already exists for other purposes in TSv2. |
| 103 // These also follow the <dest, source> pattern used by boost. |
| 104 template <typename D, typename S> struct copy_const { |
| 105 using type = skstd::conditional_t<skstd::is_const<S>::value, skstd::add_cons
t_t<D>, D>; |
57 }; | 106 }; |
| 107 template <typename D, typename S> using copy_const_t = typename copy_const<D, S>
::type; |
58 | 108 |
59 /** SkTIf::type = (Condition::value) ? T : F; */ | 109 template <typename D, typename S> struct copy_volatile { |
60 template <typename Condition, typename T, typename F> struct SkTIf { | 110 using type = skstd::conditional_t<skstd::is_volatile<S>::value, skstd::add_v
olatile_t<D>, D>; |
61 typedef typename SkTIf_c<static_cast<bool>(Condition::value), T, F>::type ty
pe; | |
62 }; | 111 }; |
| 112 template <typename D, typename S> using copy_volatile_t = typename copy_volatile
<D, S>::type; |
63 | 113 |
64 /** SkTMux::type = (a && b) ? Both : (a) ? A : (b) ? B : Neither; */ | 114 template <typename D, typename S> struct copy_cv { |
65 template <typename a, typename b, typename Both, typename A, typename B, typenam
e Neither> | 115 using type = copy_volatile_t<copy_const_t<D, S>, S>; |
66 struct SkTMux { | |
67 typedef typename SkTIf<a, typename SkTIf<b, Both, A>::type, | |
68 typename SkTIf<b, B, Neither>::type>::type type; | |
69 }; | 116 }; |
| 117 template <typename D, typename S> using copy_cv_t = typename copy_cv<D, S>::type
; |
70 | 118 |
71 /** SkTEnableIf_c::type = (condition) ? T : [does not exist]; */ | 119 // The name 'same' here means 'overwrite'. |
72 template <bool condition, class T = void> struct SkTEnableIf_c { }; | 120 // Alternate proposed names are 'replace', 'transfer', or 'qualify_from'. |
73 template <class T> struct SkTEnableIf_c<true, T> { | 121 // same_xxx<D, S> can be written as copy_xxx<remove_xxx_t<D>, S> |
74 typedef T type; | 122 template <typename D, typename S> using same_const = copy_const<skstd::remove_co
nst_t<D>, S>; |
75 }; | 123 template <typename D, typename S> using same_const_t = typename same_const<D, S>
::type; |
| 124 template <typename D, typename S> using same_volatile =copy_volatile<skstd::remo
ve_volatile_t<D>,S>; |
| 125 template <typename D, typename S> using same_volatile_t = typename same_volatile
<D, S>::type; |
| 126 template <typename D, typename S> using same_cv = copy_cv<skstd::remove_cv_t<D>,
S>; |
| 127 template <typename D, typename S> using same_cv_t = typename same_cv<D, S>::type
; |
76 | 128 |
77 /** SkTEnableIf::type = (Condition::value) ? T : [does not exist]; */ | 129 } // namespace sknonstd |
78 template <class Condition, class T = void> struct SkTEnableIf | |
79 : public SkTEnableIf_c<static_cast<bool>(Condition::value), T> { }; | |
80 | 130 |
81 /** Use as a return type to enable a function only when cond_type::value is true
, | 131 /** Use as a return type to enable a function only when cond_type::value is true
, |
82 * like C++14's std::enable_if_t. E.g. (N.B. this is a dumb example.) | 132 * like C++14's std::enable_if_t. E.g. (N.B. this is a dumb example.) |
83 * SK_WHEN(SkTrue, int) f(void* ptr) { return 1; } | 133 * SK_WHEN(true_type, int) f(void* ptr) { return 1; } |
84 * SK_WHEN(!SkTrue, int) f(void* ptr) { return 2; } | 134 * SK_WHEN(!true_type, int) f(void* ptr) { return 2; } |
85 */ | 135 */ |
86 #define SK_WHEN(cond_prefix, T) typename SkTEnableIf_c<cond_prefix::value, T>::t
ype | 136 #define SK_WHEN(cond_prefix, T) skstd::enable_if_t<cond_prefix::value, T> |
87 #define SK_WHEN_C(cond, T) typename SkTEnableIf_c<cond, T>::type | |
88 | 137 |
89 // See http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector | 138 // See http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector |
90 #define SK_CREATE_MEMBER_DETECTOR(member)
\ | 139 #define SK_CREATE_MEMBER_DETECTOR(member)
\ |
91 template <typename T>
\ | 140 template <typename T>
\ |
92 class HasMember_##member {
\ | 141 class HasMember_##member {
\ |
93 struct Fallback { int member; };
\ | 142 struct Fallback { int member; };
\ |
94 struct Derived : T, Fallback {};
\ | 143 struct Derived : T, Fallback {};
\ |
95 template <typename U, U> struct Check;
\ | 144 template <typename U, U> struct Check;
\ |
96 template <typename U> static uint8_t func(Check<int Fallback::*, &U::member>
*); \ | 145 template <typename U> static uint8_t func(Check<int Fallback::*, &U::member>
*); \ |
97 template <typename U> static uint16_t func(...);
\ | 146 template <typename U> static uint16_t func(...);
\ |
98 public:
\ | 147 public:
\ |
99 typedef HasMember_##member type;
\ | 148 typedef HasMember_##member type;
\ |
100 static const bool value = sizeof(func<Derived>(NULL)) == sizeof(uint16_t);
\ | 149 static const bool value = sizeof(func<Derived>(NULL)) == sizeof(uint16_t);
\ |
101 } | 150 } |
102 | 151 |
103 // Same sort of thing as SK_CREATE_MEMBER_DETECTOR, but checks for the existence
of a nested type. | 152 // Same sort of thing as SK_CREATE_MEMBER_DETECTOR, but checks for the existence
of a nested type. |
104 #define SK_CREATE_TYPE_DETECTOR(type) \ | 153 #define SK_CREATE_TYPE_DETECTOR(type) \ |
105 template <typename T> \ | 154 template <typename T> \ |
106 class HasType_##type { \ | 155 class HasType_##type { \ |
107 template <typename U> static uint8_t func(typename U::type*); \ | 156 template <typename U> static uint8_t func(typename U::type*); \ |
108 template <typename U> static uint16_t func(...); \ | 157 template <typename U> static uint16_t func(...); \ |
109 public: \ | 158 public: \ |
110 static const bool value = sizeof(func<T>(NULL)) == sizeof(uint8_t); \ | 159 static const bool value = sizeof(func<T>(NULL)) == sizeof(uint8_t); \ |
111 } | 160 } |
112 | 161 |
113 namespace skstd { | |
114 | |
115 template <typename T> struct remove_const { using type = T; }; | |
116 template <typename T> struct remove_const<const T> { using type = T; }; | |
117 template <typename T> using remove_const_t = typename remove_const<T>::type; | |
118 | |
119 template <typename T> struct remove_volatile { using type = T; }; | |
120 template <typename T> struct remove_volatile<volatile T> { using type = T; }; | |
121 template <typename T> using remove_volatile_t = typename remove_volatile<T>::typ
e; | |
122 | |
123 template <typename T> struct remove_cv { using type = remove_volatile_t<remove_c
onst_t<T>>; }; | |
124 template <typename T> using remove_cv_t = typename remove_cv<T>::type; | |
125 | |
126 template <typename T> struct remove_reference { using type = T; }; | |
127 template <typename T> struct remove_reference<T&> { using type = T; }; | |
128 template <typename T> struct remove_reference<T&&> { using type = T; }; | |
129 template <typename T> using remove_reference_t = typename remove_reference<T>::t
ype; | |
130 | |
131 template <typename T, typename U> struct is_same : SkFalse {}; | |
132 template <typename T> struct is_same<T, T> : SkTrue {}; | |
133 | |
134 template <typename T> struct is_void : is_same<void, remove_cv_t<T>> {}; | |
135 | |
136 template <typename T> struct is_reference : SkFalse {}; | |
137 template <typename T> struct is_reference<T&> : SkTrue {}; | |
138 template <typename T> struct is_reference<T&&> : SkTrue {}; | |
139 | |
140 template <typename T> struct is_lvalue_reference : SkFalse {}; | |
141 template <typename T> struct is_lvalue_reference<T&> : SkTrue {}; | |
142 | |
143 template <typename T> struct add_rvalue_reference { | |
144 using type = typename SkTIf_c<is_void<T>::value || is_reference<T>::value, T
, T&&>::type; | |
145 }; | |
146 template <typename T> using add_rvalue_reference_t = typename add_rvalue_referen
ce<T>::type; | |
147 | |
148 } // namespace skstd | |
149 | |
150 /** | |
151 * SkTIsConst<T>::value is true if the type T is const. | |
152 * The type T is constrained not to be an array or reference type. | |
153 */ | |
154 template <typename T> struct SkTIsConst { | |
155 static T* t; | |
156 static uint16_t test(const volatile void*); | |
157 static uint32_t test(volatile void *); | |
158 static const bool value = (sizeof(uint16_t) == sizeof(test(t))); | |
159 }; | |
160 | |
161 #endif | 162 #endif |
OLD | NEW |