Adobe Source Libraries 2.0.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
poly.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_POLY_HPP
9#define ADOBE_POLY_HPP
10
11#include <adobe/config.hpp>
12
13#include <string>
14#include <type_traits>
15#include <typeinfo>
16#include <utility>
17
18#include <boost/mpl/bool.hpp>
19#include <boost/mpl/if.hpp>
20#include <boost/mpl/or.hpp>
21#include <boost/utility/enable_if.hpp>
22
23#include <adobe/implementation/swap.hpp>
24#include <adobe/typeinfo.hpp>
25
26/**************************************************************************************************/
27
28namespace adobe {
29
30
35
44
45
46#if !defined(ADOBE_NO_DOCUMENTATION)
47
48template <typename T, typename U>
50 : boost::mpl::or_<std::is_base_of<T, U>, std::is_base_of<U, T>, std::is_same<T, U>> {};
51#endif
52// !defined(ADOBE_NO_DOCUMENTATION)
53
54/**************************************************************************************************/
55
63
65 virtual poly_copyable_interface* clone(void*) const = 0;
67 virtual void* cast() = 0;
68 virtual const void* cast() const = 0;
69 virtual const std::type_info& type_info() const = 0;
70
71 // Precondition of assignment: this->type_info() == x.type_info()
72 virtual void assign(const poly_copyable_interface& x) = 0;
73
74 // Precondition of exchange: this->type_info() == x.type_info()
75 virtual void exchange(poly_copyable_interface& x) = 0;
76
78};
79
80/**************************************************************************************************/
81
82#if !defined(ADOBE_NO_DOCUMENTATION)
83
84/**************************************************************************************************/
85
86namespace implementation {
87
88/**************************************************************************************************/
89
90template <typename ConcreteType, typename Interface>
91struct poly_state_remote : Interface {
92 typedef ConcreteType value_type;
93 typedef Interface interface_type;
94
95 const value_type& get() const { return *value_ptr_m; }
96 value_type& get() { return *value_ptr_m; }
97
98 poly_state_remote(poly_state_remote&& x) : value_ptr_m(x.value_ptr_m) {
99 x.value_ptr_m = nullptr;
100 }
101
102 explicit poly_state_remote(value_type x) : value_ptr_m(::new value_type(std::move(x))) {}
103
104 ~poly_state_remote() { delete value_ptr_m; }
105
106 // Precondition : this->type_info() == x.type_info()
107 void assign(const poly_copyable_interface& x) {
108 *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m;
109 }
110
111 const std::type_info& type_info() const { return typeid(value_type); }
112 const void* cast() const { return value_ptr_m; }
113 void* cast() { return value_ptr_m; }
114
115 // Precondition : this->type_info() == x.type_info()
116 void exchange(poly_copyable_interface& x) {
117 return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m);
118 }
119
120 // Precondition : x.type_info() == y.type_info()
121 friend bool operator==(const poly_state_remote& x, const poly_state_remote& y) {
122 return *x.value_ptr_m == *y.value_ptr_m;
123 }
124
125 value_type* value_ptr_m;
126};
127
128/**************************************************************************************************/
129
130template <typename ConcreteType, typename Interface>
131struct poly_state_local : Interface {
132 typedef ConcreteType value_type;
133 typedef Interface interface_type;
134
135 const value_type& get() const { return value_m; }
136 value_type& get() { return value_m; }
137
138 poly_state_local(poly_state_local&& x) noexcept : value_m(std::move(x.value_m)) {}
139
140 explicit poly_state_local(value_type x) : value_m(std::move(x)) {}
141
142 // Precondition : this->type_info() == x.type_info()
143 void assign(const poly_copyable_interface& x) {
144 value_m = static_cast<const poly_state_local&>(x).value_m;
145 }
146
147 const std::type_info& type_info() const { return typeid(value_type); }
148 const void* cast() const { return &value_m; }
149 void* cast() { return &value_m; }
150
151 // Precondition : this->type_info() == x.type_info()
152 void exchange(poly_copyable_interface& x) {
153 return std::swap(value_m, static_cast<poly_state_local&>(x).value_m);
154 }
155
156 // Precondition : x.type_info() == y.type_info()
157 friend bool operator==(const poly_state_local& x, const poly_state_local& y) {
158 return x.value_m == y.value_m;
159 }
160
161 value_type value_m;
162};
163
164
165/**************************************************************************************************/
166
167typedef double storage_t[2];
168
169template <typename T, int N = sizeof(storage_t)>
170struct is_small {
171 enum {
172 value = sizeof(T) <= N && (std::is_nothrow_constructible<typename T::value_type>::value ||
173 std::is_same<std::string, typename T::value_type>::value)
174 };
175};
176
177/**************************************************************************************************/
178
179template <typename F>
180struct poly_instance : F {
181 typedef typename F::value_type value_type;
182 typedef typename F::interface_type interface_type;
183
184 poly_instance(const value_type& x) : F(x) {}
185 poly_instance(poly_instance&& x) : F(std::move(x)) {}
186
187 poly_copyable_interface* clone(void* storage) const {
188 return ::new (storage) poly_instance(this->get());
189 }
190
191 poly_copyable_interface* move_clone(void* storage) {
192 return ::new (storage) poly_instance(std::move(*this));
193 }
194};
195
196/**************************************************************************************************/
197
198template <typename T>
199class has_equals {
200 typedef bool (T::*E)(const T&) const;
201 typedef char (&no_type)[1];
202 typedef char (&yes_type)[2];
203 template <E e>
204 struct sfinae {
205 typedef yes_type type;
206 };
207 template <class U>
208 static typename sfinae<&U::equals>::type test(int);
209 template <class U>
210 static no_type test(...);
211
212public:
213 enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
214};
215
216/**************************************************************************************************/
217
218} // namespace implementation
219
220/**************************************************************************************************/
221
222#endif
223// !defined(ADOBE_NO_DOCUMENTATION)
224
225/**************************************************************************************************/
226
235
236template <typename ConcreteType, typename Interface>
238 : boost::mpl::if_<
239 implementation::is_small<implementation::poly_state_local<ConcreteType, Interface>>,
240 implementation::poly_state_local<ConcreteType, Interface>,
241 implementation::poly_state_remote<ConcreteType, Interface>> {};
242
243
244/**************************************************************************************************/
245
256
257template <typename I, template <typename> class Instance>
258struct poly_base {
259
260 template <typename T, template <typename> class U>
261 friend struct poly_base;
262
263 typedef I interface_type;
264
265 // Construct from value type
266
267 template <typename T>
268 explicit poly_base(T x, typename boost::disable_if<std::is_base_of<poly_base, T>>::type* = 0) {
269 ::new (storage()) implementation::poly_instance<Instance<T>>(std::move(x));
270 }
271
272 // Construct from related interface (might throw on downcast)
273 template <typename J, template <typename> class K>
274 explicit poly_base(const poly_base<J, K>& x,
275 typename boost::enable_if<is_base_derived_or_same<I, J>>::type* = 0) {
276 if (std::is_base_of<J, I>::value)
277 dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
278 x.interface_ref().clone(storage());
279 }
280
281 poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
282
283 poly_base(poly_base&& x) { x.interface_ref().move_clone(storage()); }
284
285 friend inline void swap(poly_base& x, poly_base& y) {
288
289 if (a.type_info() == b.type_info()) {
290 a.exchange(b);
291 return;
292 }
293
294 // x->tmp
295 poly_base tmp(std::move(x));
296 a.~interface_type();
297
298 // y->x
299 b.move_clone(x.storage());
300 b.~interface_type();
301
302 // tmp->y
303 tmp.interface_ref().move_clone(y.storage());
304 }
305
307 interface_ref().~interface_type();
308 x.interface_ref().move_clone(storage());
309 return *this;
310 }
311 ~poly_base() { interface_ref().~interface_type(); }
312
313 template <typename J, template <typename> class K>
315 return dynamic_cast<const I*>(
316 static_cast<const poly_copyable_interface*>(&x.interface_ref()));
317 }
318
319 template <typename J>
321 return dynamic_cast<const J*>(
322 static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL;
323 }
324
325 const std::type_info& type_info() const { return interface_ref().type_info(); }
326
327 template <typename T>
328 const T& cast() const {
329 if (type_info() != typeid(T))
330 throw bad_cast(type_info(), typeid(T));
331 return *static_cast<const T*>(interface_ref().cast());
332 }
333
334 template <typename T>
335 T& cast() {
336 if (type_info() != typeid(T))
337 throw bad_cast(type_info(), typeid(T));
338 return *static_cast<T*>(interface_ref().cast());
339 }
340
341 template <typename T>
342 bool cast(T& x) const {
343 if (type_info() != typeid(T))
344 return false;
345 x = cast<T>();
346 return true;
347 }
348
349 template <typename T>
350 poly_base& assign(const T& x) {
351 if (type_info() == typeid(T))
352 cast<T>() = x;
353 else {
354 poly_base tmp(x);
355 swap(*this, tmp);
356 }
357 return *this;
358 }
359
360 // Assign from related (may throw if downcastisng)
361 template <typename J, template <typename> class K>
362 typename boost::enable_if<is_base_derived_or_same<I, J>>::type
364 if (std::is_base_of<J, I>::value)
365 dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); // make sure type safe
366 interface_ref().~interface_type();
367 x.interface_ref().clone(storage());
368 }
369
370 const interface_type* operator->() const { return &interface_ref(); }
371
373
374 interface_type& interface_ref() { return *static_cast<interface_type*>(storage()); }
375
377 return *static_cast<const interface_type*>(storage());
378 }
379
380 void* storage() { return &data_m; }
381 const void* storage() const { return &data_m; }
382
383 implementation::storage_t data_m;
384};
385
386template <class J, template <typename> class K>
387inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
389 return x.interface_ref().equals(y.interface_ref());
390}
391
392
393/**************************************************************************************************/
394
404
405template <class F>
406class poly : public F {
407public:
413 template <typename T>
414 explicit poly(const T& x) : F(x) {}
415
416 poly(poly&& x) : F(std::move(x)) {}
417 poly(const poly&) = default;
418
420 static_cast<F&>(*this) = std::move(static_cast<F&>(x));
421 return *this;
422 }
423
424 poly() : F() {}
425};
426
427/**************************************************************************************************/
428
443template <typename T, typename U>
445 typedef typename std::remove_reference<T>::type target_type;
446 typedef typename target_type::interface_type target_interface_type;
447 if (!x.template is_dynamic_convertible_to<target_interface_type>())
448 throw adobe::bad_cast(typeid(poly<U>), typeid(T));
449 return reinterpret_cast<T>(x);
450}
451
452/**************************************************************************************************/
453
460
461template <typename T, typename U>
462T poly_cast(const poly<U>& x) {
463 typedef typename std::remove_reference<T>::type target_type;
464 typedef typename target_type::interface_type target_interface_type;
465 if (!x.template is_dynamic_convertible_to<target_interface_type>())
466 throw adobe::bad_cast(typeid(poly<U>), typeid(T));
467 return reinterpret_cast<T>(x);
468}
469
470/**************************************************************************************************/
471
486
487template <typename T, typename U>
489 typedef typename std::remove_pointer<T>::type target_type;
490 typedef typename target_type::interface_type target_interface_type;
491 return x->template is_dynamic_convertible_to<target_interface_type>() ? reinterpret_cast<T>(x)
492 : NULL;
493}
494
495/**************************************************************************************************/
496
503
504
505template <typename T, typename U>
506T poly_cast(const poly<U>* x) {
507 typedef typename std::remove_pointer<T>::type target_type;
508 typedef typename target_type::interface_type target_interface_type;
509 return x->template is_dynamic_convertible_to<target_interface_type>() ? reinterpret_cast<T>(x)
510 : NULL;
511}
512
513/**************************************************************************************************/
514
521
522template <class T>
523inline bool operator!=(const poly<T>& x, const poly<T>& y) {
524 return !(x == y);
525}
526
527
529
530/**************************************************************************************************/
531
532} // namespace adobe
533
534/**************************************************************************************************/
535
536#endif
537
538/**************************************************************************************************/
An exception class thrown during ASL failures to cast.
Definition typeinfo.hpp:33
poly<foo> will be a runtime polymorphic value type wrapper modelling a concept represented by foo
Definition poly.hpp:406
poly(poly &&x)
Definition poly.hpp:416
poly(const T &x)
Definition poly.hpp:414
poly(const poly &)=default
poly & operator=(poly x)
Definition poly.hpp:419
bool operator==(const any_regular_t &x, const any_regular_t &y)
bool operator!=(const forest< T > &x, const forest< T > &y)
Definition forest.hpp:722
STL namespace.
void swap(adobe::extents_t::slice_t &x, adobe::extents_t::slice_t &y) BOOST_NOEXCEPT
Definition extents.hpp:120
Authors of poly concept representatives must derive their instance class from this....
Definition poly.hpp:241
Authors of a Concept representative F, intended as a template parameter to poly, will inherit from po...
Definition poly.hpp:258
bool is_dynamic_convertible_to() const
Definition poly.hpp:320
poly_base(const poly_base &x)
Definition poly.hpp:281
bool cast(T &x) const
Definition poly.hpp:342
poly_base(const poly_base< J, K > &x, typename boost::enable_if< is_base_derived_or_same< I, J > >::type *=0)
Definition poly.hpp:274
poly_base(T x, typename boost::disable_if< std::is_base_of< poly_base, T > >::type *=0)
Definition poly.hpp:268
const interface_type * operator->() const
Definition poly.hpp:370
const std::type_info & type_info() const
Definition poly.hpp:325
const void * storage() const
Definition poly.hpp:381
boost::enable_if< is_base_derived_or_same< I, J > >::type assign(const poly_base< J, K > &x)
Definition poly.hpp:363
poly_base(poly_base &&x)
Definition poly.hpp:283
friend struct poly_base
Definition poly.hpp:261
poly_base & operator=(poly_base x)
Definition poly.hpp:306
interface_type * operator->()
Definition poly.hpp:372
poly_base & assign(const T &x)
Definition poly.hpp:350
void * storage()
Definition poly.hpp:380
const T & cast() const
Definition poly.hpp:328
const interface_type & interface_ref() const
Definition poly.hpp:376
interface_type & interface_ref()
Definition poly.hpp:374
static bool is_dynamic_convertible_from(const poly_base< J, K > &x)
Definition poly.hpp:314
friend void swap(poly_base &x, poly_base &y)
Definition poly.hpp:285
Abstract interface providing signatures needed to implement "handle" objects modeling a Value (Copyab...
Definition poly.hpp:64
virtual poly_copyable_interface * clone(void *) const =0
virtual const void * cast() const =0
virtual void assign(const poly_copyable_interface &x)=0
virtual void exchange(poly_copyable_interface &x)=0
virtual ~poly_copyable_interface()
Definition poly.hpp:77
virtual poly_copyable_interface * move_clone(void *)=0
virtual const std::type_info & type_info() const =0