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