| 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 |