/
meta_util_impl.h
383 lines (320 loc) · 12.2 KB
/
meta_util_impl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/**********************************************************\
Original Author: Georg Fritzsche
Created: December 22, 2009
License: Dual license model; choose one of two:
New BSD License
http://www.opensource.org/licenses/bsd-license.php
- or -
GNU Lesser General Public License, version 2.1
http://www.gnu.org/licenses/lgpl-2.1.html
Copyright 2009 Georg Fritzsche, Firebreath development team
\**********************************************************/
#pragma once
#ifndef H_META_UTIL_IMPL_22122009
#define H_META_UTIL_IMPL_22122009
#include <utility>
//Workaround for conflict between boost 1.48+ and Apple's AssertMacros.h
#ifdef check
#undef check
#endif
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/and.hpp>
#include <boost/type_traits.hpp>
#include <boost/variant/variant_fwd.hpp>
namespace FB { namespace meta { namespace detail
{
class yes { char c; };
class no { yes y[2]; };
#define FB_HAS_TYPE(Type_, Name_) \
template<class T> \
struct Name_ { \
template<class U> static yes test(typename U::Type_ const*); \
template<class U> static no test(...); \
static const bool value = (sizeof(test<T>(0)) == sizeof(yes)); \
typedef boost::mpl::bool_<value> type; \
}
FB_HAS_TYPE(iterator, has_type_iterator);
FB_HAS_TYPE(const_iterator, has_type_const_iterator);
FB_HAS_TYPE(key_type, has_type_key_type);
FB_HAS_TYPE(value_type, has_type_value_type);
FB_HAS_TYPE(mapped_type, has_type_mapped_type);
// FB_HAS_TYPE(reference, has_type_reference);
// FB_HAS_TYPE(const_reference, has_type_const_reference);
FB_HAS_TYPE(pointer, has_type_pointer);
FB_HAS_TYPE(difference_type, has_type_difference_type);
FB_HAS_TYPE(size_type, has_type_size_type);
#undef FB_HAS_TYPE
template<class C>
class is_container_impl
{
private:
struct mixin
{
void begin() const;
void end() const;
void size() const;
void max_size() const;
void empty() const;
void swap(char);
};
struct derivate : public C, public mixin {};
template<class U, U t> struct helper {};
template<class U> static no test_begin(helper<void (mixin::*)() const, &U::begin>*);
template<class U> static yes test_begin(...);
template<class U> static no test_end(helper<void (mixin::*)() const, &U::end>*);
template<class U> static yes test_end(...);
template<class U> static no test_size(helper<void (mixin::*)() const, &U::size>*);
template<class U> static yes test_size(...);
template<class U> static no test_max_size(helper<void (mixin::*)() const, &U::max_size>*);
template<class U> static yes test_max_size(...);
template<class U> static no test_empty(helper<void (mixin::*)() const, &U::empty>*);
template<class U> static yes test_empty(...);
template<class U> static no test_swap(helper<void (mixin::*)(char), &U::swap>*);
template<class U> static yes test_swap(...);
public:
static const bool has_memfun_begin = (sizeof(yes) == sizeof(test_begin <derivate>(0)));
static const bool has_memfun_end = (sizeof(yes) == sizeof(test_end <derivate>(0)));
static const bool has_memfun_size = (sizeof(yes) == sizeof(test_size <derivate>(0)));
static const bool has_memfun_max_size = (sizeof(yes) == sizeof(test_max_size<derivate>(0)));
static const bool has_memfun_empty = (sizeof(yes) == sizeof(test_empty <derivate>(0)));
static const bool has_memfun_swap = (sizeof(yes) == sizeof(test_swap <derivate>(0)));
static const bool value =
has_type_iterator<C>::value
&& has_type_const_iterator<C>::value
&& has_type_value_type<C>::value
// && has_type_reference<C>::value
// && has_type_const_reference<C>::value
&& has_type_pointer<C>::value
&& has_type_difference_type<C>::value
&& has_type_size_type<C>::value
&& has_memfun_begin
&& has_memfun_size
&& has_memfun_max_size
&& has_memfun_empty
&& has_memfun_swap;
typedef boost::mpl::bool_<value> type;
};
template<class C>
class is_assoc_impl
{
struct mixin
{
void erase(char);
void erase(char, char);
void clear();
void find(char) const;
void count(char) const;
void equal_range(char) const;
};
struct derivate : public C, public mixin {};
template<class U, U t> struct helper {};
template<class U> static no test_erase_1(helper<void (mixin::*)(char), &U::erase>*);
template<class U> static yes test_erase_1(...);
template<class U> static no test_erase_2(helper<void (mixin::*)(char, char), &U::erase>*);
template<class U> static yes test_erase_2(...);
template<class U> static no test_clear(helper<void (mixin::*)(), &U::clear>*);
template<class U> static yes test_clear(...);
template<class U> static no test_find(helper<void (mixin::*)(char) const, &U::find>*);
template<class U> static yes test_find(...);
template<class U> static no test_count(helper<void (mixin::*)(char) const, &U::count>*);
template<class U> static yes test_count(...);
template<class U> static no test_equal_range(helper<void (mixin::*)(char) const, &U::equal_range>*);
template<class U> static yes test_equal_range(...);
public:
static const bool has_memfun_erase_1 = (sizeof(yes) == sizeof(test_erase_1 <derivate>(0)));
static const bool has_memfun_erase_2 = (sizeof(yes) == sizeof(test_erase_2 <derivate>(0)));
static const bool has_memfun_clear = (sizeof(yes) == sizeof(test_clear <derivate>(0)));
static const bool has_memfun_find = (sizeof(yes) == sizeof(test_find <derivate>(0)));
static const bool has_memfun_count = (sizeof(yes) == sizeof(test_count <derivate>(0)));
static const bool has_memfun_equal_range = (sizeof(yes) == sizeof(test_equal_range<derivate>(0)));
static const bool value =
has_type_key_type<C>::value
&& has_memfun_erase_1
&& has_memfun_erase_2
&& has_memfun_clear
&& has_memfun_find
&& has_memfun_count
&& has_memfun_equal_range;
typedef boost::mpl::bool_<value> type;
};
template<bool has_mapped_type, class T>
struct check_pair_assoc_value_type
{
typedef typename T::key_type Key;
typedef typename T::mapped_type Mapped;
typedef typename T::value_type Value;
typedef std::pair<const Key, Mapped> Pair;
static const bool value = boost::is_same<Value, Pair>::value;
};
template<class T>
struct check_pair_assoc_value_type<false, T>
{
static const bool value = false;
};
template<class T>
class is_pair_assoc_impl
{
public:
static const bool has_mapped_type = has_type_mapped_type<T>::value;
static const bool value_type_is_pair =
check_pair_assoc_value_type<has_mapped_type, T>::value;
static const bool value = value_type_is_pair;
typedef boost::mpl::bool_<value> type;
};
typedef boost::mpl::vector
<
std::string,
std::wstring
> pseudo_container_types;
template<typename T>
struct plain_type {
typedef typename boost::remove_const<typename boost::remove_reference<T>::type>::type type;
};
template<class T>
struct is_pseudo_container
: boost::mpl::contains<pseudo_container_types, typename plain_type<T>::type>::type
{};
////////////////
// is_container
template<bool isClass, class T>
struct is_container_helper
: boost::mpl::and_<
boost::mpl::not_< is_pseudo_container<T> >,
typename is_container_impl<T>::type >::type
{};
template<class T>
struct is_container_helper<false, T>
: boost::mpl::false_
{};
template<class T>
struct is_container
: is_container_helper<boost::is_class<T>::value, T>
{};
//////////////////////
// is_assoc_container
template<bool isClass, class T>
struct is_assoc_container_helper
: boost::mpl::and_<
typename is_assoc_impl<T>::type,
is_container<T> >::type
{};
template<class T>
struct is_assoc_container_helper<false, T>
: boost::mpl::false_
{};
template<class T>
struct is_assoc_container
: is_assoc_container_helper<boost::is_class<T>::value, T>
{};
///////////////////////////
// is_pair_assoc_container
template<bool isClass, class T>
struct is_pair_assoc_container_helper
: boost::mpl::and_<
typename is_pair_assoc_impl<T>::type,
is_assoc_container<T> >::type
{};
template<class T>
struct is_pair_assoc_container_helper<false, T>
: boost::mpl::false_
{};
template<class T>
struct is_pair_assoc_container
: is_pair_assoc_container_helper<boost::is_class<T>::value, T>
{};
//////////////////////////
// is_non_assoc_container
template<bool isClass, class T>
struct is_non_assoc_container_helper
: boost::mpl::and_<
boost::mpl::not_<is_assoc_container<T> >,
is_container<T> >::type
{};
template<class T>
struct is_non_assoc_container_helper<false, T>
: boost::mpl::false_
{};
template<class T>
struct is_non_assoc_container
: is_non_assoc_container_helper<boost::is_class<T>::value, T>
{};
////////////////////////////////////////////////
// is number - we consider bool as a non-number
template<class T>
struct is_number
: boost::mpl::and_<
boost::is_arithmetic<T>,
boost::mpl::not_<
boost::is_same<T, bool>
>
>
{};
///////////////////////////////////////////////////////////////////////////
// enable_if helpers:
// T - the type to compare
// R - the return type
template<class T, typename R>
struct enable_for_numbers_impl
: boost::enable_if<is_number<T>, R>
{};
template<class T, typename R>
struct disable_for_numbers_impl
: boost::disable_if<is_number<T>, R>
{};
template<class T, typename R>
struct enable_for_containers_impl
: boost::enable_if<is_container<T>, R>
{};
template<class T, typename R>
struct disable_for_containers_impl
: boost::disable_if<is_container<T>, R>
{};
template<class T, typename R>
struct enable_for_containers_and_numbers_impl
: boost::enable_if<
boost::mpl::or_<
is_container<T>,
is_number<T>
>,
R
>
{};
template<class T, typename R>
struct disable_for_containers_and_numbers_impl
: boost::disable_if<
boost::mpl::or_<
is_container<T>,
is_number<T>
>,
R
>
{};
template<class T, typename R>
struct enable_for_assoc_containers_impl
: boost::enable_if<is_assoc_container<T>, R>
{};
template<class T, typename R>
struct disable_for_assoc_containers_impl
: boost::disable_if<is_assoc_container<T>, R>
{};
template<class T, typename R>
struct enable_for_pair_assoc_containers_impl
: boost::enable_if<is_pair_assoc_container<T>, R>
{};
template<class T, typename R>
struct disable_for_pair_assoc_containers_impl
: boost::disable_if<is_pair_assoc_container<T>, R>
{};
template<class T, typename R>
struct enable_for_non_assoc_containers_impl
: boost::enable_if<is_non_assoc_container<T>, R>
{};
template<class T, typename R>
struct disable_for_non_assoc_containers_impl
: boost::disable_if<is_non_assoc_container<T>, R>
{};
}; }; };
#endif