Adobe Source Libraries 1.49.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 <boost/mpl/bool.hpp>
14#include <boost/mpl/if.hpp>
15#include <boost/mpl/or.hpp>
16#include <boost/utility/enable_if.hpp>
17
18#include <adobe/implementation/swap.hpp>
19#include <adobe/typeinfo.hpp>
20
21#include <type_traits>
22
23/**************************************************************************************************/
24
25namespace adobe {
26
27
32
41
42
43#if !defined(ADOBE_NO_DOCUMENTATION)
44
45template <typename T, typename U>
47 : boost::mpl::or_<std::is_base_of<T, U>, std::is_base_of<U, T>, std::is_same<T, U>> {};
48#endif
49// !defined(ADOBE_NO_DOCUMENTATION)
50
51/**************************************************************************************************/
52
60
62 virtual poly_copyable_interface* clone(void*) const = 0;
64 virtual void* cast() = 0;
65 virtual const void* cast() const = 0;
66 virtual const std::type_info& type_info() const = 0;
67
68 // Precondition of assignment: this->type_info() == x.type_info()
69 virtual void assign(const poly_copyable_interface& x) = 0;
70
71 // Precondition of exchange: this->type_info() == x.type_info()
72 virtual void exchange(poly_copyable_interface& x) = 0;
73
75};
76
77/**************************************************************************************************/
78
79#if !defined(ADOBE_NO_DOCUMENTATION)
80
81/**************************************************************************************************/
82
83namespace implementation {
84
85/**************************************************************************************************/
86
87template <typename ConcreteType, typename Interface>
88struct poly_state_remote : Interface {
89 typedef ConcreteType value_type;
90 typedef Interface interface_type;
91
92 const value_type& get() const { return *value_ptr_m; }
93 value_type& get() { return *value_ptr_m; }
94
95 poly_state_remote(poly_state_remote&& x) : value_ptr_m(x.value_ptr_m) {
96 x.value_ptr_m = nullptr;
97 }
98
99 explicit poly_state_remote(value_type x) : value_ptr_m(::new value_type(std::move(x))) {}
100
101 ~poly_state_remote() { delete value_ptr_m; }
102
103 // Precondition : this->type_info() == x.type_info()
104 void assign(const poly_copyable_interface& x) {
105 *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m;
106 }
107
108 const std::type_info& type_info() const { return typeid(value_type); }
109 const void* cast() const { return value_ptr_m; }
110 void* cast() { return value_ptr_m; }
111
112 // Precondition : this->type_info() == x.type_info()
113 void exchange(poly_copyable_interface& x) {
114 return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m);
115 }
116
117 // Precondition : x.type_info() == y.type_info()
118 friend bool operator==(const poly_state_remote& x, const poly_state_remote& y) {
119 return *x.value_ptr_m == *y.value_ptr_m;
120 }
121
122 value_type* value_ptr_m;
123};
124
125/**************************************************************************************************/
126
127template <typename ConcreteType, typename Interface>
128struct poly_state_local : Interface {
129 typedef ConcreteType value_type;
130 typedef Interface interface_type;
131
132 const value_type& get() const { return value_m; }
133 value_type& get() { return value_m; }
134
135 poly_state_local(poly_state_local&& x) noexcept : value_m(std::move(x.value_m)) {}
136
137 explicit poly_state_local(value_type x) : value_m(std::move(x)) {}
138
139 // Precondition : this->type_info() == x.type_info()
140 void assign(const poly_copyable_interface& x) {
141 value_m = static_cast<const poly_state_local&>(x).value_m;
142 }
143
144 const std::type_info& type_info() const { return typeid(value_type); }
145 const void* cast() const { return &value_m; }
146 void* cast() { return &value_m; }
147
148 // Precondition : this->type_info() == x.type_info()
149 void exchange(poly_copyable_interface& x) {
150 return std::swap(value_m, static_cast<poly_state_local&>(x).value_m);
151 }
152
153 // Precondition : x.type_info() == y.type_info()
154 friend bool operator==(const poly_state_local& x, const poly_state_local& y) {
155 return x.value_m == y.value_m;
156 }
157
158 value_type value_m;
159};
160
161
162/**************************************************************************************************/
163
164typedef double storage_t[2];
165
166template <typename T, int N = sizeof(storage_t)>
167struct is_small {
168 enum {
169 value = sizeof(T) <= N && (std::is_nothrow_constructible<typename T::value_type>::value ||
170 std::is_same<std::string, typename T::value_type>::value)
171 };
172};
173
174/**************************************************************************************************/
175
176template <typename F>
177struct poly_instance : F {
178 typedef typename F::value_type value_type;
179 typedef typename F::interface_type interface_type;
180
181 poly_instance(const value_type& x) : F(x) {}
182 poly_instance(poly_instance&& x) : F(std::move(x)) {}
183
184 poly_copyable_interface* clone(void* storage) const {
185 return ::new (storage) poly_instance(this->get());
186 }
187
188 poly_copyable_interface* move_clone(void* storage) {
189 return ::new (storage) poly_instance(std::move(*this));
190 }
191};
192
193/**************************************************************************************************/
194
195template <typename T>
196class has_equals {
197 typedef bool (T::*E)(const T&) const;
198 typedef char (&no_type)[1];
199 typedef char (&yes_type)[2];
200 template <E e>
201 struct sfinae {
202 typedef yes_type type;
203 };
204 template <class U>
205 static typename sfinae<&U::equals>::type test(int);
206 template <class U>
207 static no_type test(...);
208
209public:
210 enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
211};
212
213/**************************************************************************************************/
214
215} // namespace implementation
216
217/**************************************************************************************************/
218
219#endif
220// !defined(ADOBE_NO_DOCUMENTATION)
221
222/**************************************************************************************************/
223
232
233template <typename ConcreteType, typename Interface>
235 : boost::mpl::if_<
236 implementation::is_small<implementation::poly_state_local<ConcreteType, Interface>>,
237 implementation::poly_state_local<ConcreteType, Interface>,
238 implementation::poly_state_remote<ConcreteType, Interface>> {};
239
240
241/**************************************************************************************************/
242
253
254template <typename I, template <typename> class Instance>
255struct poly_base {
256
257 template <typename T, template <typename> class U>
258 friend struct poly_base;
259
260 typedef I interface_type;
261
262 // Construct from value type
263
264 template <typename T>
265 explicit poly_base(T x, typename boost::disable_if<std::is_base_of<poly_base, T>>::type* = 0) {
266 ::new (storage()) implementation::poly_instance<Instance<T>>(std::move(x));
267 }
268
269 // Construct from related interface (might throw on downcast)
270 template <typename J, template <typename> class K>
271 explicit poly_base(const poly_base<J, K>& x,
272 typename boost::enable_if<is_base_derived_or_same<I, J>>::type* = 0) {
273 if (std::is_base_of<J, I>::value)
274 dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
275 x.interface_ref().clone(storage());
276 }
277
278 poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
279
280 poly_base(poly_base&& x) { x.interface_ref().move_clone(storage()); }
281
282 friend inline void swap(poly_base& x, poly_base& y) {
285
286 if (a.type_info() == b.type_info()) {
287 a.exchange(b);
288 return;
289 }
290
291 // x->tmp
292 poly_base tmp(std::move(x));
293 a.~interface_type();
294
295 // y->x
296 b.move_clone(x.storage());
297 b.~interface_type();
298
299 // tmp->y
300 tmp.interface_ref().move_clone(y.storage());
301 }
302
304 interface_ref().~interface_type();
305 x.interface_ref().move_clone(storage());
306 return *this;
307 }
308 ~poly_base() { interface_ref().~interface_type(); }
309
310 template <typename J, template <typename> class K>
312 return dynamic_cast<const I*>(
313 static_cast<const poly_copyable_interface*>(&x.interface_ref()));
314 }
315
316 template <typename J>
318 return dynamic_cast<const J*>(
319 static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL;
320 }
321
322 const std::type_info& type_info() const { return interface_ref().type_info(); }
323
324 template <typename T>
325 const T& cast() const {
326 if (type_info() != typeid(T))
327 throw bad_cast(type_info(), typeid(T));
328 return *static_cast<const T*>(interface_ref().cast());
329 }
330
331 template <typename T>
332 T& cast() {
333 if (type_info() != typeid(T))
334 throw bad_cast(type_info(), typeid(T));
335 return *static_cast<T*>(interface_ref().cast());
336 }
337
338 template <typename T>
339 bool cast(T& x) const {
340 if (type_info() != typeid(T))
341 return false;
342 x = cast<T>();
343 return true;
344 }
345
346 template <typename T>
347 poly_base& assign(const T& x) {
348 if (type_info() == typeid(T))
349 cast<T>() = x;
350 else {
351 poly_base tmp(x);
352 swap(*this, tmp);
353 }
354 return *this;
355 }
356
357 // Assign from related (may throw if downcastisng)
358 template <typename J, template <typename> class K>
359 typename boost::enable_if<is_base_derived_or_same<I, J>>::type
361 if (std::is_base_of<J, I>::value)
362 dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); // make sure type safe
363 interface_ref().~interface_type();
364 x.interface_ref().clone(storage());
365 }
366
367 const interface_type* operator->() const { return &interface_ref(); }
368
370
371 interface_type& interface_ref() { return *static_cast<interface_type*>(storage()); }
372
374 return *static_cast<const interface_type*>(storage());
375 }
376
377 void* storage() { return &data_m; }
378 const void* storage() const { return &data_m; }
379
380 implementation::storage_t data_m;
381};
382
383template <class J, template <typename> class K>
384inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
386 return x.interface_ref().equals(y.interface_ref());
387}
388
389
390/**************************************************************************************************/
391
401
402template <class F>
403class poly : public F {
404public:
410 template <typename T>
411 explicit poly(const T& x) : F(x) {}
412
413 poly(poly&& x) : F(std::move(x)) {}
414 poly(const poly&) = default;
415
417 static_cast<F&>(*this) = std::move(static_cast<F&>(x));
418 return *this;
419 }
420
421 poly() : F() {}
422};
423
424/**************************************************************************************************/
425
440template <typename T, typename U>
442 typedef typename boost::remove_reference<T>::type target_type;
443 typedef typename target_type::interface_type target_interface_type;
444 if (!x.template is_dynamic_convertible_to<target_interface_type>())
445 throw bad_cast(typeid(poly<U>), typeid(T));
446 return reinterpret_cast<T>(x);
447}
448
449/**************************************************************************************************/
450
457
458template <typename T, typename U>
459T poly_cast(const poly<U>& x) {
460 typedef typename boost::remove_reference<T>::type target_type;
461 typedef typename target_type::interface_type target_interface_type;
462 if (!x.template is_dynamic_convertible_to<target_interface_type>())
463 throw bad_cast(typeid(poly<U>), typeid(T));
464 return reinterpret_cast<T>(x);
465}
466
467/**************************************************************************************************/
468
483
484template <typename T, typename U>
486 typedef typename std::remove_pointer<T>::type target_type;
487 typedef typename target_type::interface_type target_interface_type;
488 return x->template is_dynamic_convertible_to<target_interface_type>() ? reinterpret_cast<T>(x)
489 : NULL;
490}
491
492/**************************************************************************************************/
493
500
501
502template <typename T, typename U>
503T poly_cast(const poly<U>* x) {
504 typedef typename std::remove_pointer<T>::type target_type;
505 typedef typename target_type::interface_type target_interface_type;
506 return x->template is_dynamic_convertible_to<target_interface_type>() ? reinterpret_cast<T>(x)
507 : NULL;
508}
509
510/**************************************************************************************************/
511
518
519template <class T>
520inline bool operator!=(const poly<T>& x, const poly<T>& y) {
521 return !(x == y);
522}
523
524
526
527/**************************************************************************************************/
528
529} // namespace adobe
530
531/**************************************************************************************************/
532
533#endif
534
535/**************************************************************************************************/
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:403
poly(poly &&x)
Definition poly.hpp:413
poly(const T &x)
Definition poly.hpp:411
poly(const poly &)=default
poly & operator=(poly x)
Definition poly.hpp:416
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:238
Authors of a Concept representative F, intended as a template parameter to poly, will inherit from po...
Definition poly.hpp:255
bool is_dynamic_convertible_to() const
Definition poly.hpp:317
poly_base(const poly_base &x)
Definition poly.hpp:278
bool cast(T &x) const
Definition poly.hpp:339
poly_base(const poly_base< J, K > &x, typename boost::enable_if< is_base_derived_or_same< I, J > >::type *=0)
Definition poly.hpp:271
poly_base(T x, typename boost::disable_if< std::is_base_of< poly_base, T > >::type *=0)
Definition poly.hpp:265
const interface_type * operator->() const
Definition poly.hpp:367
const std::type_info & type_info() const
Definition poly.hpp:322
const void * storage() const
Definition poly.hpp:378
boost::enable_if< is_base_derived_or_same< I, J > >::type assign(const poly_base< J, K > &x)
Definition poly.hpp:360
poly_base(poly_base &&x)
Definition poly.hpp:280
friend struct poly_base
Definition poly.hpp:258
poly_base & operator=(poly_base x)
Definition poly.hpp:303
interface_type * operator->()
Definition poly.hpp:369
poly_base & assign(const T &x)
Definition poly.hpp:347
void * storage()
Definition poly.hpp:377
const T & cast() const
Definition poly.hpp:325
const interface_type & interface_ref() const
Definition poly.hpp:373
interface_type & interface_ref()
Definition poly.hpp:371
static bool is_dynamic_convertible_from(const poly_base< J, K > &x)
Definition poly.hpp:311
friend void swap(poly_base &x, poly_base &y)
Definition poly.hpp:282
Abstract interface providing signatures needed to implement "handle" objects modeling a Value (Copyab...
Definition poly.hpp:61
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:74
virtual poly_copyable_interface * move_clone(void *)=0
virtual const std::type_info & type_info() const =0