1 /*
2  * Copyright (C) 2005 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_TYPE_HELPERS_H
18 #define ANDROID_TYPE_HELPERS_H
19 
20 #include <new>
21 #include <type_traits>
22 
23 #include <stdint.h>
24 #include <string.h>
25 #include <sys/types.h>
26 
27 // ---------------------------------------------------------------------------
28 
29 namespace android {
30 
31 /*
32  * Types traits
33  */
34 
35 template <typename T> struct trait_trivial_ctor { enum { value = false }; };
36 template <typename T> struct trait_trivial_dtor { enum { value = false }; };
37 template <typename T> struct trait_trivial_copy { enum { value = false }; };
38 template <typename T> struct trait_trivial_move { enum { value = false }; };
39 template <typename T> struct trait_pointer      { enum { value = false }; };
40 template <typename T> struct trait_pointer<T*>  { enum { value = true }; };
41 
42 template <typename TYPE>
43 struct traits {
44     enum {
45         // whether this type is a pointer
46         is_pointer          = trait_pointer<TYPE>::value,
47         // whether this type's constructor is a no-op
48         has_trivial_ctor    = is_pointer || trait_trivial_ctor<TYPE>::value,
49         // whether this type's destructor is a no-op
50         has_trivial_dtor    = is_pointer || trait_trivial_dtor<TYPE>::value,
51         // whether this type type can be copy-constructed with memcpy
52         has_trivial_copy    = is_pointer || trait_trivial_copy<TYPE>::value,
53         // whether this type can be moved with memmove
54         has_trivial_move    = is_pointer || trait_trivial_move<TYPE>::value
55     };
56 };
57 
58 template <typename T, typename U>
59 struct aggregate_traits {
60     enum {
61         is_pointer          = false,
62         has_trivial_ctor    =
63             traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
64         has_trivial_dtor    =
65             traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
66         has_trivial_copy    =
67             traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
68         has_trivial_move    =
69             traits<T>::has_trivial_move && traits<U>::has_trivial_move
70     };
71 };
72 
73 #define ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
74     template<> struct trait_trivial_ctor< T >   { enum { value = true }; };
75 
76 #define ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
77     template<> struct trait_trivial_dtor< T >   { enum { value = true }; };
78 
79 #define ANDROID_TRIVIAL_COPY_TRAIT( T ) \
80     template<> struct trait_trivial_copy< T >   { enum { value = true }; };
81 
82 #define ANDROID_TRIVIAL_MOVE_TRAIT( T ) \
83     template<> struct trait_trivial_move< T >   { enum { value = true }; };
84 
85 #define ANDROID_BASIC_TYPES_TRAITS( T ) \
86     ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
87     ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
88     ANDROID_TRIVIAL_COPY_TRAIT( T ) \
89     ANDROID_TRIVIAL_MOVE_TRAIT( T )
90 
91 // ---------------------------------------------------------------------------
92 
93 /*
94  * basic types traits
95  */
96 
97 ANDROID_BASIC_TYPES_TRAITS( void )
98 ANDROID_BASIC_TYPES_TRAITS( bool )
99 ANDROID_BASIC_TYPES_TRAITS( char )
100 ANDROID_BASIC_TYPES_TRAITS( unsigned char )
101 ANDROID_BASIC_TYPES_TRAITS( short )
102 ANDROID_BASIC_TYPES_TRAITS( unsigned short )
103 ANDROID_BASIC_TYPES_TRAITS( int )
104 ANDROID_BASIC_TYPES_TRAITS( unsigned int )
105 ANDROID_BASIC_TYPES_TRAITS( long )
106 ANDROID_BASIC_TYPES_TRAITS( unsigned long )
107 ANDROID_BASIC_TYPES_TRAITS( long long )
108 ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
109 ANDROID_BASIC_TYPES_TRAITS( float )
110 ANDROID_BASIC_TYPES_TRAITS( double )
111 
112 // ---------------------------------------------------------------------------
113 
114 
115 /*
116  * compare and order types
117  */
118 
119 template<typename TYPE> inline
120 int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
121     return (lhs < rhs) ? 1 : 0;
122 }
123 
124 template<typename TYPE> inline
125 int compare_type(const TYPE& lhs, const TYPE& rhs) {
126     return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
127 }
128 
129 /*
130  * create, destroy, copy and move types...
131  */
132 
133 template<typename TYPE> inline
134 void construct_type(TYPE* p, size_t n) {
135     if (!traits<TYPE>::has_trivial_ctor) {
136         while (n > 0) {
137             n--;
138             new(p++) TYPE;
139         }
140     }
141 }
142 
143 template<typename TYPE> inline
144 void destroy_type(TYPE* p, size_t n) {
145     if (!traits<TYPE>::has_trivial_dtor) {
146         while (n > 0) {
147             n--;
148             p->~TYPE();
149             p++;
150         }
151     }
152 }
153 
154 template<typename TYPE>
155 typename std::enable_if<traits<TYPE>::has_trivial_copy>::type
156 inline
157 copy_type(TYPE* d, const TYPE* s, size_t n) {
158     memcpy(d,s,n*sizeof(TYPE));
159 }
160 
161 template<typename TYPE>
162 typename std::enable_if<!traits<TYPE>::has_trivial_copy>::type
163 inline
164 copy_type(TYPE* d, const TYPE* s, size_t n) {
165     while (n > 0) {
166         n--;
167         new(d) TYPE(*s);
168         d++, s++;
169     }
170 }
171 
172 template<typename TYPE> inline
173 void splat_type(TYPE* where, const TYPE* what, size_t n) {
174     if (!traits<TYPE>::has_trivial_copy) {
175         while (n > 0) {
176             n--;
177             new(where) TYPE(*what);
178             where++;
179         }
180     } else {
181         while (n > 0) {
182             n--;
183             *where++ = *what;
184         }
185     }
186 }
187 
188 template<typename TYPE>
189 struct use_trivial_move : public std::integral_constant<bool,
190     (traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
191     || traits<TYPE>::has_trivial_move
192 > {};
193 
194 template<typename TYPE>
195 typename std::enable_if<use_trivial_move<TYPE>::value>::type
196 inline
197 move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
198     memmove(d, s, n*sizeof(TYPE));
199 }
200 
201 template<typename TYPE>
202 typename std::enable_if<!use_trivial_move<TYPE>::value>::type
203 inline
204 move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
205     d += n;
206     s += n;
207     while (n > 0) {
208         n--;
209         --d, --s;
210         if (!traits<TYPE>::has_trivial_copy) {
211             new(d) TYPE(*s);
212         } else {
213             *d = *s;
214         }
215         if (!traits<TYPE>::has_trivial_dtor) {
216             s->~TYPE();
217         }
218     }
219 }
220 
221 template<typename TYPE>
222 typename std::enable_if<use_trivial_move<TYPE>::value>::type
223 inline
224 move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
225     memmove(d, s, n*sizeof(TYPE));
226 }
227 
228 template<typename TYPE>
229 typename std::enable_if<!use_trivial_move<TYPE>::value>::type
230 inline
231 move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
232     while (n > 0) {
233         n--;
234         if (!traits<TYPE>::has_trivial_copy) {
235             new(d) TYPE(*s);
236         } else {
237             *d = *s;
238         }
239         if (!traits<TYPE>::has_trivial_dtor) {
240             s->~TYPE();
241         }
242         d++, s++;
243     }
244 }
245 
246 // ---------------------------------------------------------------------------
247 
248 /*
249  * a key/value pair
250  */
251 
252 template <typename KEY, typename VALUE>
253 struct key_value_pair_t {
254     typedef KEY key_t;
255     typedef VALUE value_t;
256 
257     KEY     key;
258     VALUE   value;
259     key_value_pair_t() { }
260     key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
261     key_value_pair_t& operator=(const key_value_pair_t& o) {
262         key = o.key;
263         value = o.value;
264         return *this;
265     }
266     key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v)  { }
267     explicit key_value_pair_t(const KEY& k) : key(k) { }
268     inline bool operator < (const key_value_pair_t& o) const {
269         return strictly_order_type(key, o.key);
270     }
271     inline const KEY& getKey() const {
272         return key;
273     }
274     inline const VALUE& getValue() const {
275         return value;
276     }
277 };
278 
279 template <typename K, typename V>
280 struct trait_trivial_ctor< key_value_pair_t<K, V> >
281 { enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
282 template <typename K, typename V>
283 struct trait_trivial_dtor< key_value_pair_t<K, V> >
284 { enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
285 template <typename K, typename V>
286 struct trait_trivial_copy< key_value_pair_t<K, V> >
287 { enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
288 template <typename K, typename V>
289 struct trait_trivial_move< key_value_pair_t<K, V> >
290 { enum { value = aggregate_traits<K,V>::has_trivial_move }; };
291 
292 // ---------------------------------------------------------------------------
293 
294 /*
295  * Hash codes.
296  */
297 typedef uint32_t hash_t;
298 
299 template <typename TKey>
300 hash_t hash_type(const TKey& key);
301 
302 /* Built-in hash code specializations */
303 #define ANDROID_INT32_HASH(T) \
304         template <> inline hash_t hash_type(const T& value) { return hash_t(value); }
305 #define ANDROID_INT64_HASH(T) \
306         template <> inline hash_t hash_type(const T& value) { \
307                 return hash_t((value >> 32) ^ value); }
308 #define ANDROID_REINTERPRET_HASH(T, R) \
309         template <> inline hash_t hash_type(const T& value) { \
310             R newValue; \
311             static_assert(sizeof(newValue) == sizeof(value), "size mismatch"); \
312             memcpy(&newValue, &value, sizeof(newValue)); \
313             return hash_type(newValue); \
314         }
315 
316 ANDROID_INT32_HASH(bool)
317 ANDROID_INT32_HASH(int8_t)
318 ANDROID_INT32_HASH(uint8_t)
319 ANDROID_INT32_HASH(int16_t)
320 ANDROID_INT32_HASH(uint16_t)
321 ANDROID_INT32_HASH(int32_t)
322 ANDROID_INT32_HASH(uint32_t)
323 ANDROID_INT64_HASH(int64_t)
324 ANDROID_INT64_HASH(uint64_t)
325 ANDROID_REINTERPRET_HASH(float, uint32_t)
326 ANDROID_REINTERPRET_HASH(double, uint64_t)
327 
328 template <typename T> inline hash_t hash_type(T* const & value) {
329     return hash_type(uintptr_t(value));
330 }
331 
332 }; // namespace android
333 
334 // ---------------------------------------------------------------------------
335 
336 #endif // ANDROID_TYPE_HELPERS_H
337