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
29namespace android {
30
31/*
32 * Types traits
33 */
34
35template <typename T> struct trait_trivial_ctor { enum { value = false }; };
36template <typename T> struct trait_trivial_dtor { enum { value = false }; };
37template <typename T> struct trait_trivial_copy { enum { value = false }; };
38template <typename T> struct trait_trivial_move { enum { value = false }; };
39template <typename T> struct trait_pointer      { enum { value = false }; };
40template <typename T> struct trait_pointer<T*>  { enum { value = true }; };
41
42template <typename TYPE>
43struct 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
58template <typename T, typename U>
59struct 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
97ANDROID_BASIC_TYPES_TRAITS( void )
98ANDROID_BASIC_TYPES_TRAITS( bool )
99ANDROID_BASIC_TYPES_TRAITS( char )
100ANDROID_BASIC_TYPES_TRAITS( unsigned char )
101ANDROID_BASIC_TYPES_TRAITS( short )
102ANDROID_BASIC_TYPES_TRAITS( unsigned short )
103ANDROID_BASIC_TYPES_TRAITS( int )
104ANDROID_BASIC_TYPES_TRAITS( unsigned int )
105ANDROID_BASIC_TYPES_TRAITS( long )
106ANDROID_BASIC_TYPES_TRAITS( unsigned long )
107ANDROID_BASIC_TYPES_TRAITS( long long )
108ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
109ANDROID_BASIC_TYPES_TRAITS( float )
110ANDROID_BASIC_TYPES_TRAITS( double )
111
112// ---------------------------------------------------------------------------
113
114
115/*
116 * compare and order types
117 */
118
119template<typename TYPE> inline
120int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
121    return (lhs < rhs) ? 1 : 0;
122}
123
124template<typename TYPE> inline
125int 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
133template<typename TYPE> inline
134void 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
143template<typename TYPE> inline
144void 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
154template<typename TYPE>
155typename std::enable_if<traits<TYPE>::has_trivial_copy>::type
156inline
157copy_type(TYPE* d, const TYPE* s, size_t n) {
158    memcpy(d,s,n*sizeof(TYPE));
159}
160
161template<typename TYPE>
162typename std::enable_if<!traits<TYPE>::has_trivial_copy>::type
163inline
164copy_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
172template<typename TYPE> inline
173void 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
188template<typename TYPE>
189struct 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
194template<typename TYPE>
195typename std::enable_if<use_trivial_move<TYPE>::value>::type
196inline
197move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
198    memmove(d, s, n*sizeof(TYPE));
199}
200
201template<typename TYPE>
202typename std::enable_if<!use_trivial_move<TYPE>::value>::type
203inline
204move_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
221template<typename TYPE>
222typename std::enable_if<use_trivial_move<TYPE>::value>::type
223inline
224move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
225    memmove(d, s, n*sizeof(TYPE));
226}
227
228template<typename TYPE>
229typename std::enable_if<!use_trivial_move<TYPE>::value>::type
230inline
231move_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
252template <typename KEY, typename VALUE>
253struct 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
279template <typename K, typename V>
280struct trait_trivial_ctor< key_value_pair_t<K, V> >
281{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
282template <typename K, typename V>
283struct trait_trivial_dtor< key_value_pair_t<K, V> >
284{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
285template <typename K, typename V>
286struct trait_trivial_copy< key_value_pair_t<K, V> >
287{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
288template <typename K, typename V>
289struct 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 */
297typedef uint32_t hash_t;
298
299template <typename TKey>
300hash_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
316ANDROID_INT32_HASH(bool)
317ANDROID_INT32_HASH(int8_t)
318ANDROID_INT32_HASH(uint8_t)
319ANDROID_INT32_HASH(int16_t)
320ANDROID_INT32_HASH(uint16_t)
321ANDROID_INT32_HASH(int32_t)
322ANDROID_INT32_HASH(uint32_t)
323ANDROID_INT64_HASH(int64_t)
324ANDROID_INT64_HASH(uint64_t)
325ANDROID_REINTERPRET_HASH(float, uint32_t)
326ANDROID_REINTERPRET_HASH(double, uint64_t)
327
328template <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