]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.TypeErasure library |
2 | // | |
3 | // Copyright 2011 Steven Watanabe | |
4 | // | |
5 | // Distributed under the Boost Software License Version 1.0. (See | |
6 | // accompanying file LICENSE_1_0.txt or copy at | |
7 | // http://www.boost.org/LICENSE_1_0.txt) | |
8 | // | |
9 | // $Id$ | |
10 | ||
11 | #ifndef BOOST_TYPE_ERASURE_OPERATORS_HPP_INCLUDED | |
12 | #define BOOST_TYPE_ERASURE_OPERATORS_HPP_INCLUDED | |
13 | ||
14 | #include <iosfwd> | |
15 | #include <boost/utility/enable_if.hpp> | |
16 | #include <boost/type_erasure/detail/const.hpp> | |
17 | #include <boost/type_erasure/call.hpp> | |
18 | #include <boost/type_erasure/concept_interface.hpp> | |
19 | #include <boost/type_erasure/placeholder.hpp> | |
20 | #include <boost/type_erasure/concept_of.hpp> | |
21 | #include <boost/type_erasure/derived.hpp> | |
22 | #include <boost/type_erasure/rebind_any.hpp> | |
23 | #include <boost/type_erasure/param.hpp> | |
24 | #include <boost/type_erasure/check_match.hpp> | |
25 | #include <boost/type_erasure/relaxed.hpp> | |
26 | #include <boost/type_erasure/typeid_of.hpp> | |
27 | ||
28 | namespace boost { | |
29 | namespace type_erasure { | |
30 | ||
31 | template<class Concept, class Placeholder> | |
32 | class any; | |
33 | ||
34 | /** INTERNAL ONLY */ | |
35 | #define BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(name, op) \ | |
36 | template<class T = _self> \ | |
37 | struct name \ | |
38 | { \ | |
39 | static void apply(T& arg) { op arg; } \ | |
40 | }; \ | |
41 | \ | |
42 | template<class T, class Base> \ | |
43 | struct concept_interface<name<T>, Base, T, \ | |
44 | typename ::boost::enable_if< \ | |
45 | detail::should_be_non_const<T, Base> \ | |
46 | >::type \ | |
47 | > : Base \ | |
48 | { \ | |
49 | typedef typename ::boost::type_erasure::derived<Base>::type _derived; \ | |
50 | _derived& operator op() \ | |
51 | { \ | |
52 | ::boost::type_erasure::call(name<T>(), *this); \ | |
53 | return static_cast<_derived&>(*this); \ | |
54 | } \ | |
55 | typename ::boost::type_erasure::rebind_any<Base, T>::type operator op(int) \ | |
56 | { \ | |
57 | typename ::boost::type_erasure::rebind_any<Base, T>::type result( \ | |
58 | static_cast<_derived&>(*this)); \ | |
59 | ::boost::type_erasure::call(name<T>(), *this); \ | |
60 | return result; \ | |
61 | } \ | |
62 | }; \ | |
63 | \ | |
64 | template<class T, class Base> \ | |
65 | struct concept_interface<name<T>, Base, T, \ | |
66 | typename ::boost::enable_if< \ | |
67 | detail::should_be_const<T, Base> \ | |
68 | >::type \ | |
69 | > : Base \ | |
70 | { \ | |
71 | typedef typename ::boost::type_erasure::derived<Base>::type _derived; \ | |
72 | const _derived& operator op() const \ | |
73 | { \ | |
74 | ::boost::type_erasure::call(name<T>(), *this); \ | |
75 | return static_cast<const _derived&>(*this); \ | |
76 | } \ | |
77 | typename ::boost::type_erasure::rebind_any<Base, T>::type operator op(int) const \ | |
78 | { \ | |
79 | typename ::boost::type_erasure::rebind_any<Base, T>::type result( \ | |
80 | static_cast<const _derived&>(*this)); \ | |
81 | ::boost::type_erasure::call(name<T>(), *this); \ | |
82 | return result; \ | |
83 | } \ | |
84 | }; | |
85 | ||
86 | /** | |
87 | * The @ref incrementable concept allow pre and | |
88 | * post increment on an @ref any. The contained | |
89 | * type must provide a pre-increment operator. | |
90 | */ | |
91 | BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(incrementable, ++) | |
92 | /** | |
93 | * The @ref decrementable concept allow pre and | |
94 | * post decrement on an @ref any. The contained | |
95 | * type must provide a pre-decrement operator. | |
96 | */ | |
97 | BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR(decrementable, --) | |
98 | ||
99 | #undef BOOST_TYPE_ERASURE_UNARY_INPLACE_OPERATOR | |
100 | ||
101 | /** INTERNAL ONLY */ | |
102 | #define BOOST_TYPE_ERASURE_UNARY_OPERATOR(name, op) \ | |
103 | template<class T = _self, class R = T> \ | |
104 | struct name \ | |
105 | { \ | |
106 | static R apply(const T& arg) { return op arg; } \ | |
107 | }; \ | |
108 | \ | |
109 | template<class T, class R, class Base> \ | |
110 | struct concept_interface<name<T, R>, Base, T> : Base \ | |
111 | { \ | |
112 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator op() const \ | |
113 | { \ | |
114 | return ::boost::type_erasure::call(name<T, R>(), *this); \ | |
115 | } \ | |
116 | }; | |
117 | ||
118 | /** | |
119 | * The @ref complementable concept allow use of the bitwise | |
120 | * complement operator on an @ref any. | |
121 | */ | |
122 | BOOST_TYPE_ERASURE_UNARY_OPERATOR(complementable, ~) | |
123 | /** | |
124 | * The @ref negatable concept allow use of the unary | |
125 | * minus operator on an @ref any. | |
126 | */ | |
127 | BOOST_TYPE_ERASURE_UNARY_OPERATOR(negatable, -) | |
128 | ||
129 | #undef BOOST_TYPE_ERASURE_UNARY_OPERATOR | |
130 | ||
131 | template<class R, class T = _self> | |
132 | struct dereferenceable | |
133 | { | |
134 | static R apply(const T& arg) { return *arg; } | |
135 | }; | |
136 | ||
137 | /// \cond show_operators | |
138 | ||
139 | template<class R, class T, class Base> | |
140 | struct concept_interface<dereferenceable<R, T>, Base, T> : Base | |
141 | { | |
142 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator*() const | |
143 | { | |
144 | return ::boost::type_erasure::call(dereferenceable<R, T>(), *this); | |
145 | } | |
146 | }; | |
147 | ||
148 | /// \endcond | |
149 | ||
150 | /** INTERNAL ONLY */ | |
151 | #define BOOST_TYPE_ERASURE_BINARY_OPERATOR(name, op) \ | |
152 | template<class T = _self, class U = T, class R = T> \ | |
153 | struct name \ | |
154 | { \ | |
155 | static R apply(const T& lhs, const U& rhs) { return lhs op rhs; } \ | |
156 | }; \ | |
157 | \ | |
158 | template<class T, class U, class R, class Base> \ | |
159 | struct concept_interface<name<T, U, R>, Base, T> : Base \ | |
160 | { \ | |
161 | friend typename rebind_any<Base, R>::type \ | |
162 | operator op(const typename derived<Base>::type& lhs, \ | |
163 | typename as_param<Base, const U&>::type rhs) \ | |
164 | { \ | |
165 | return ::boost::type_erasure::call(name<T, U, R>(), lhs, rhs); \ | |
166 | } \ | |
167 | }; \ | |
168 | \ | |
169 | template<class T, class U, class R, class Base> \ | |
170 | struct concept_interface< \ | |
171 | name<T, U, R>, \ | |
172 | Base, \ | |
173 | U, \ | |
174 | typename ::boost::disable_if< \ | |
175 | ::boost::type_erasure::is_placeholder<T> >::type \ | |
176 | > : Base \ | |
177 | { \ | |
178 | friend typename rebind_any<Base, R>::type \ | |
179 | operator op(const T& lhs, \ | |
180 | const typename derived<Base>::type& rhs) \ | |
181 | { \ | |
182 | return ::boost::type_erasure::call(name<T, U, R>(), lhs, rhs); \ | |
183 | } \ | |
184 | }; | |
185 | ||
186 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(addable, +) | |
187 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(subtractable, -) | |
188 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(multipliable, *) | |
189 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(dividable, /) | |
190 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(modable, %) | |
191 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(left_shiftable, <<) | |
192 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(right_shiftable, >>) | |
193 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitandable, &) | |
194 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitorable, |) | |
195 | BOOST_TYPE_ERASURE_BINARY_OPERATOR(bitxorable, ^) | |
196 | ||
197 | #undef BOOST_TYPE_ERASURE_BINARY_OPERATOR | |
198 | ||
199 | /** INTERNAL ONLY */ | |
200 | #define BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(name, op) \ | |
201 | template<class T = _self, class U = T> \ | |
202 | struct name \ | |
203 | { \ | |
204 | static void apply(T& lhs, const U& rhs) { lhs op rhs; } \ | |
205 | }; \ | |
206 | \ | |
207 | template<class T, class U, class Base> \ | |
208 | struct concept_interface<name<T, U>, Base, T, \ | |
209 | typename ::boost::disable_if< \ | |
210 | ::boost::is_same< \ | |
211 | typename ::boost::type_erasure::placeholder_of<Base>::type, \ | |
212 | const T& \ | |
213 | > \ | |
214 | >::type \ | |
215 | > : Base \ | |
216 | { \ | |
217 | friend typename detail::non_const_this_param<Base>::type& \ | |
218 | operator op(typename detail::non_const_this_param<Base>::type& lhs, \ | |
219 | typename as_param<Base, const U&>::type rhs) \ | |
220 | { \ | |
221 | ::boost::type_erasure::call(name<T, U>(),lhs, rhs); \ | |
222 | return lhs; \ | |
223 | } \ | |
224 | }; \ | |
225 | \ | |
226 | template<class T, class U, class Base> \ | |
227 | struct concept_interface< \ | |
228 | name<T, U>, \ | |
229 | Base, \ | |
230 | U, \ | |
231 | typename ::boost::disable_if< \ | |
232 | ::boost::type_erasure::is_placeholder<T> >::type \ | |
233 | > : Base \ | |
234 | { \ | |
235 | friend T& \ | |
236 | operator op(T& lhs, const typename derived<Base>::type& rhs) \ | |
237 | { \ | |
238 | ::boost::type_erasure::call(name<T, U>(),lhs, rhs); \ | |
239 | return lhs; \ | |
240 | } \ | |
241 | }; | |
242 | ||
243 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(add_assignable, +=) | |
244 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(subtract_assignable, -=) | |
245 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(multiply_assignable, *=) | |
246 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(divide_assignable, /=) | |
247 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(mod_assignable, %=) | |
248 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(left_shift_assignable, <<=) | |
249 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(right_shift_assignable, >>=) | |
250 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitand_assignable, &=) | |
251 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitor_assignable, |=) | |
252 | BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR(bitxor_assignable, ^=) | |
253 | ||
254 | #undef BOOST_TYPE_ERASURE_ASSIGNMENT_OPERATOR | |
255 | ||
256 | template<class T = _self, class U = T> | |
257 | struct equality_comparable | |
258 | { | |
259 | static bool apply(const T& lhs, const U& rhs) { return lhs == rhs; } | |
260 | }; | |
261 | ||
262 | /// \cond show_operators | |
263 | ||
264 | template<class T, class U, class Base> | |
265 | struct concept_interface<equality_comparable<T, U>, Base, T> : Base | |
266 | { | |
267 | friend bool operator==(const typename derived<Base>::type& lhs, | |
268 | typename as_param<Base, const U&>::type rhs) | |
269 | { | |
270 | if(::boost::type_erasure::check_match(equality_comparable<T, U>(), lhs, rhs)) { | |
271 | return ::boost::type_erasure::unchecked_call(equality_comparable<T, U>(), lhs, rhs); | |
272 | } else { | |
273 | return false; | |
274 | } | |
275 | } | |
276 | friend bool operator!=(const typename derived<Base>::type& lhs, | |
277 | typename as_param<Base, const U&>::type rhs) | |
278 | { | |
279 | return !(lhs == rhs); | |
280 | } | |
281 | }; | |
282 | ||
283 | template<class T, class U, class Base> | |
284 | struct concept_interface< | |
285 | equality_comparable<T, U>, | |
286 | Base, | |
287 | U, | |
288 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<T> >::type | |
289 | > : Base | |
290 | { | |
291 | friend bool operator==(const T& lhs, const typename derived<Base>::type& rhs) | |
292 | { | |
293 | return ::boost::type_erasure::call(equality_comparable<T, U>(), lhs, rhs); | |
294 | } | |
295 | friend bool operator!=(const T& lhs, const typename derived<Base>::type& rhs) | |
296 | { | |
297 | return !(lhs == rhs); | |
298 | } | |
299 | }; | |
300 | ||
301 | /// \endcond | |
302 | ||
303 | template<class T = _self, class U = T> | |
304 | struct less_than_comparable | |
305 | { | |
306 | static bool apply(const T& lhs, const U& rhs) { return lhs < rhs; } | |
307 | }; | |
308 | ||
309 | namespace detail { | |
310 | ||
311 | template<class F, class T, class U> | |
312 | bool less_impl(const F& f, const T& lhs, const U& rhs, ::boost::mpl::true_) | |
313 | { | |
314 | if(::boost::type_erasure::check_match(f, lhs, rhs)) { | |
315 | return ::boost::type_erasure::unchecked_call(f, lhs, rhs); | |
316 | } else { | |
317 | return ::boost::type_erasure::typeid_of( | |
318 | static_cast<const typename derived<T>::type&>(lhs) | |
319 | ).before( | |
320 | ::boost::type_erasure::typeid_of( | |
321 | static_cast<const typename derived<U>::type&>(rhs) | |
322 | ) | |
323 | ) != false; | |
324 | } | |
325 | } | |
326 | ||
327 | template<class F, class T, class U> | |
328 | bool less_impl(const F& f, const T& lhs, const U& rhs, ::boost::mpl::false_) | |
329 | { | |
330 | return ::boost::type_erasure::call(f, lhs, rhs); | |
331 | } | |
332 | ||
333 | } | |
334 | ||
335 | /// \cond show_operators | |
336 | ||
337 | template<class T, class Base> | |
338 | struct concept_interface<less_than_comparable<T, T>, Base, T> : Base | |
339 | { | |
340 | friend bool operator<(const typename derived<Base>::type& lhs, | |
341 | typename as_param<Base, const T&>::type rhs) | |
342 | { | |
343 | return ::boost::type_erasure::detail::less_impl( | |
344 | less_than_comparable<T, T>(), | |
345 | lhs, rhs, | |
346 | ::boost::type_erasure::is_relaxed< | |
347 | typename ::boost::type_erasure::concept_of<Base>::type>()); | |
348 | } | |
349 | friend bool operator>=(const typename derived<Base>::type& lhs, | |
350 | typename as_param<Base, const T&>::type rhs) | |
351 | { | |
352 | return !(lhs < rhs); | |
353 | } | |
354 | friend bool operator>(typename as_param<Base, const T&>::type lhs, | |
355 | const typename derived<Base>::type& rhs) | |
356 | { | |
357 | return rhs < lhs; | |
358 | } | |
359 | friend bool operator<=(typename as_param<Base, const T&>::type lhs, | |
360 | const typename derived<Base>::type& rhs) | |
361 | { | |
362 | return !(rhs < lhs); | |
363 | } | |
364 | }; | |
365 | ||
366 | template<class T, class U, class Base> | |
367 | struct concept_interface<less_than_comparable<T, U>, Base, T> : Base | |
368 | { | |
369 | friend bool operator<(const typename derived<Base>::type& lhs, | |
370 | typename as_param<Base, const U&>::type rhs) | |
371 | { | |
372 | return ::boost::type_erasure::call(less_than_comparable<T, U>(), lhs, rhs); | |
373 | } | |
374 | friend bool operator>=(const typename derived<Base>::type& lhs, | |
375 | typename as_param<Base, const U&>::type rhs) | |
376 | { | |
377 | return !(lhs < rhs); | |
378 | } | |
379 | friend bool operator>(typename as_param<Base, const U&>::type lhs, | |
380 | const typename derived<Base>::type& rhs) | |
381 | { | |
382 | return rhs < lhs; | |
383 | } | |
384 | friend bool operator<=(typename as_param<Base, const U&>::type lhs, | |
385 | const typename derived<Base>::type& rhs) | |
386 | { | |
387 | return !(rhs < lhs); | |
388 | } | |
389 | }; | |
390 | ||
391 | template<class T, class U, class Base> | |
392 | struct concept_interface< | |
393 | less_than_comparable<T, U>, | |
394 | Base, | |
395 | U, | |
396 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<T> >::type | |
397 | > : Base | |
398 | { | |
399 | friend bool operator<(const T& lhs, const typename derived<Base>::type& rhs) | |
400 | { | |
401 | return ::boost::type_erasure::call(less_than_comparable<T, U>(), lhs, rhs); | |
402 | } | |
403 | friend bool operator>=(const T& lhs, const typename derived<Base>::type& rhs) | |
404 | { | |
405 | return !(lhs < rhs); | |
406 | } | |
407 | friend bool operator>(const typename derived<Base>::type& lhs, const T& rhs) | |
408 | { | |
409 | return rhs < lhs; | |
410 | } | |
411 | friend bool operator<=(const typename derived<Base>::type& lhs, const T& rhs) | |
412 | { | |
413 | return !(rhs < lhs); | |
414 | } | |
415 | }; | |
416 | ||
417 | /// \endcond | |
418 | ||
419 | template<class R, class T = _self, class N = std::ptrdiff_t> | |
420 | struct subscriptable | |
421 | { | |
422 | static R apply(T& arg, const N& index) { return arg[index]; } | |
423 | }; | |
424 | ||
425 | /// \cond show_operators | |
426 | ||
427 | template<class R, class T, class N, class Base> | |
428 | struct concept_interface<subscriptable<R, T, N>, Base, typename ::boost::remove_const<T>::type, | |
429 | typename ::boost::enable_if< | |
430 | ::boost::type_erasure::detail::should_be_non_const<T, Base> | |
431 | >::type | |
432 | > : Base | |
433 | { | |
434 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator[]( | |
435 | typename ::boost::type_erasure::as_param<Base, const N&>::type index) | |
436 | { | |
437 | return ::boost::type_erasure::call(subscriptable<R, T, N>(), *this, index); | |
438 | } | |
439 | }; | |
440 | ||
441 | template<class R, class T, class N, class Base> | |
442 | struct concept_interface<subscriptable<R, T, N>, Base, typename ::boost::remove_const<T>::type, | |
443 | typename ::boost::enable_if< | |
444 | ::boost::type_erasure::detail::should_be_const<T, Base> | |
445 | >::type | |
446 | > : Base | |
447 | { | |
448 | typename ::boost::type_erasure::rebind_any<Base, R>::type operator[]( | |
449 | typename ::boost::type_erasure::as_param<Base, const N&>::type index) const | |
450 | { | |
451 | return ::boost::type_erasure::call(subscriptable<R, const T, N>(), *this, index); | |
452 | } | |
453 | }; | |
454 | ||
455 | /// \endcond | |
456 | ||
457 | /** | |
458 | * The @ref ostreamable concept allows an @ref any to be | |
459 | * written to a @c std::ostream. | |
460 | */ | |
461 | template<class Os = std::ostream, class T = _self> | |
462 | struct ostreamable | |
463 | { | |
464 | static void apply(Os& out, const T& arg) { out << arg; } | |
465 | }; | |
466 | ||
467 | /// \cond show_operators | |
468 | ||
469 | template<class Base, class Os, class T> | |
470 | struct concept_interface<ostreamable<Os, T>, Base, Os> : Base | |
471 | { | |
472 | friend typename detail::non_const_this_param<Base>::type& | |
473 | operator<<(typename detail::non_const_this_param<Base>::type& lhs, | |
474 | typename ::boost::type_erasure::as_param<Base, const T&>::type rhs) | |
475 | { | |
476 | ::boost::type_erasure::call(ostreamable<Os, T>(), lhs, rhs); | |
477 | return lhs; | |
478 | } | |
479 | }; | |
480 | ||
481 | template<class Base, class Os, class T> | |
482 | struct concept_interface< | |
483 | ostreamable<Os, T>, | |
484 | Base, | |
485 | T, | |
486 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<Os> >::type | |
487 | > : Base | |
488 | { | |
489 | friend Os& | |
490 | operator<<(Os& lhs, | |
491 | const typename ::boost::type_erasure::derived<Base>::type& rhs) | |
492 | { | |
493 | ::boost::type_erasure::call(ostreamable<Os, T>(), lhs, rhs); | |
494 | return lhs; | |
495 | } | |
496 | }; | |
497 | ||
498 | /// \endcond | |
499 | ||
500 | /** | |
501 | * The @ref istreamable concept allows an @ref any to be | |
502 | * read from a @c std::istream. | |
503 | */ | |
504 | template<class Is = std::istream, class T = _self> | |
505 | struct istreamable | |
506 | { | |
507 | static void apply(Is& out, T& arg) { out >> arg; } | |
508 | }; | |
509 | ||
510 | /// \cond show_operators | |
511 | ||
512 | ||
513 | template<class Base, class Is, class T> | |
514 | struct concept_interface<istreamable<Is, T>, Base, Is> : Base | |
515 | { | |
516 | friend typename detail::non_const_this_param<Base>::type& | |
517 | operator>>(typename detail::non_const_this_param<Base>::type& lhs, | |
518 | typename ::boost::type_erasure::as_param<Base, T&>::type rhs) | |
519 | { | |
520 | ::boost::type_erasure::call(istreamable<Is, T>(), lhs, rhs); | |
521 | return lhs; | |
522 | } | |
523 | }; | |
524 | ||
525 | template<class Base, class Is, class T> | |
526 | struct concept_interface< | |
527 | istreamable<Is, T>, | |
528 | Base, | |
529 | T, | |
530 | typename ::boost::disable_if< ::boost::type_erasure::is_placeholder<Is> >::type | |
531 | > : Base | |
532 | { | |
533 | friend Is& | |
534 | operator>>(Is& lhs, | |
535 | typename ::boost::type_erasure::derived<Base>::type& rhs) | |
536 | { | |
537 | ::boost::type_erasure::call(istreamable<Is, T>(), lhs, rhs); | |
538 | return lhs; | |
539 | } | |
540 | }; | |
541 | ||
542 | /// \endcond | |
543 | ||
544 | } | |
545 | } | |
546 | ||
547 | #endif |