stlab.adobe.com Adobe Systems Incorporated
poly.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2005-2007 Adobe Systems Incorporated
3  Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
4  or a copy at http://stlab.adobe.com/licenses.html)
5 */
6 
7 /*************************************************************************************************/
8 
9 #ifndef ADOBE_POLY_HPP
10 #define ADOBE_POLY_HPP
11 
12 #include <adobe/config.hpp>
13 
14 
15 #include <boost/type_traits/is_base_of.hpp>
16 #include <boost/type_traits/remove_reference.hpp>
17 #include <boost/type_traits/remove_pointer.hpp>
18 #include <boost/utility/enable_if.hpp>
19 #include <boost/mpl/or.hpp>
20 #include <boost/mpl/if.hpp>
21 #include <boost/mpl/bool.hpp>
22 #include <boost/type_traits/has_nothrow_constructor.hpp>
23 
24 #include <adobe/move.hpp>
25 #include <adobe/implementation/swap.hpp>
26 #include <adobe/typeinfo.hpp>
27 
28 /*************************************************************************************************/
29 
30 namespace adobe {
31 
32 
48 #if !defined(ADOBE_NO_DOCUMENTATION)
49 
50 template <typename T, typename U>
51 struct is_base_derived_or_same : boost::mpl::or_<boost::is_base_of<T, U>,
52  boost::is_base_of<U, T>,
53  boost::is_same<T, U> > {};
54 #endif
55 // !defined(ADOBE_NO_DOCUMENTATION)
56 
57 /*************************************************************************************************/
58 
67  virtual poly_copyable_interface* clone(void*) const = 0;
68  virtual poly_copyable_interface* move_clone(void*) = 0;
69  virtual void* cast() = 0;
70  virtual const void* cast() const = 0;
71  virtual const std::type_info& type_info() const = 0;
72 
73 #ifndef NO_ASL_AI_CONCEPT_CHECK
74  // Precondition of assignment: this->type_info() == x.type_info()
75  virtual void assign(const poly_copyable_interface& x) = 0;
76 #endif
77 
78  // Precondition of exchange: this->type_info() == x.type_info()
79  virtual void exchange(poly_copyable_interface& x) = 0;
80 
82 };
83 
84 /*************************************************************************************************/
85 
86 #if !defined(ADOBE_NO_DOCUMENTATION)
87 
88 /*************************************************************************************************/
89 
90 namespace implementation {
91 
92 /*************************************************************************************************/
93 
94 template <typename ConcreteType, typename Interface>
95 struct poly_state_remote : Interface
96 {
97  typedef ConcreteType value_type;
98  typedef Interface interface_type;
99 
100  const value_type& get() const { return *value_ptr_m; }
101  value_type& get() { return *value_ptr_m; }
102 
103  poly_state_remote(move_from<poly_state_remote> x)
104  : value_ptr_m(x.source.value_ptr_m){ x.source.value_ptr_m = NULL; }
105 
106  explicit poly_state_remote(value_type x)
107  : value_ptr_m(::new value_type(adobe::move(x))) { }
108 
109  ~poly_state_remote()
110  { delete value_ptr_m; }
111 
112 #ifndef NO_ASL_AI_CONCEPT_CHECK
113  // Precondition : this->type_info() == x.type_info()
114  void assign(const poly_copyable_interface& x)
115  { *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m; }
116 #endif
117 
118  const std::type_info& type_info() const
119  { return typeid(value_type); }
120  const void* cast() const { return value_ptr_m; }
121  void* cast() { return value_ptr_m; }
122 
123  // Precondition : this->type_info() == x.type_info()
124  void exchange(poly_copyable_interface& x)
125  { return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m); }
126 
127  // Precondition : this->type_info() == x.type_info()
128  friend bool operator==(const poly_state_remote& x, const poly_state_remote& y)
129  { return *x.value_ptr_m == *y.value_ptr_m; }
130 
131  value_type* value_ptr_m;
132 };
133 
134 /*************************************************************************************************/
135 
136 template <typename ConcreteType, typename Interface>
137 struct poly_state_local : Interface
138 {
139  typedef ConcreteType value_type;
140  typedef Interface interface_type;
141 
142  const value_type& get() const { return value_m; }
143  value_type& get() { return value_m; }
144 
145  poly_state_local(move_from<poly_state_local> x)
146  : value_m(adobe::move(x.source.value_m)){ }
147 
148  explicit poly_state_local(value_type x)
149  : value_m(adobe::move(x)) { }
150 
151 #ifndef NO_ASL_AI_CONCEPT_CHECK
152  // Precondition : this->type_info() == x.type_info()
153  void assign(const poly_copyable_interface& x)
154  { value_m = static_cast<const poly_state_local&>(x).value_m; }
155 #endif
156 
157  const std::type_info& type_info() const
158  { return typeid(value_type); }
159  const void* cast() const { return &value_m; }
160  void* cast() { return &value_m; }
161 
162  // Precondition : this->type_info() == x.type_info()
163  void exchange(poly_copyable_interface& x)
164  { return std::swap(value_m, static_cast<poly_state_local&>(x).value_m); }
165 
166  // Precondition : this->type_info() == x.type_info()
167  friend bool operator==(const poly_state_local& x, const poly_state_local& y)
168  { return x.value_m == y.value_m; }
169 
170  value_type value_m;
171 };
172 
173 
174 /*************************************************************************************************/
175 
176 typedef double storage_t[2];
177 
178 template<typename T, int N=sizeof(storage_t)>
179 struct is_small
180 {
181  enum { value = sizeof(T) <= N && (boost::has_nothrow_constructor<typename T::value_type>::value ||
182  boost::is_same<std::string, typename T::value_type>::value) };
183 
184 };
185 
186 /*************************************************************************************************/
187 
188 template <typename F>
189 struct poly_instance : F {
190  typedef typename F::value_type value_type;
191  typedef typename F::interface_type interface_type;
192 
193  poly_instance(const value_type& x): F(x){ }
194  poly_instance(move_from<poly_instance> x) : F(move_from<F>(x.source)) { }
195 
196  poly_copyable_interface* clone(void* storage) const
197  { return ::new (storage) poly_instance(this->get()); }
198 
199  poly_copyable_interface* move_clone(void* storage)
200  { return ::new (storage) poly_instance(move_from<poly_instance>(*this)); }
201 };
202 
203 /*************************************************************************************************/
204 
205 template <typename T>
206 class has_equals {
207  typedef bool (T::*E)(const T&) const;
208  typedef char (&no_type)[1];
209  typedef char (&yes_type)[2];
210  template <E e> struct sfinae { typedef yes_type type; };
211  template <class U>
212  static typename sfinae<&U::equals>::type test(int);
213  template <class U>
214  static no_type test(...);
215 public:
216  enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
217 };
218 
219 /*************************************************************************************************/
220 
221 } //namespace implementation
222 
223 /*************************************************************************************************/
224 
225 #endif
226 // !defined(ADOBE_NO_DOCUMENTATION)
227 
228 /*************************************************************************************************/
229 
237 template <typename ConcreteType, typename Interface>
239  boost::mpl::if_<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 /*************************************************************************************************/
246 
258 template <typename I, template <typename> class Instance>
259 struct poly_base {
260 
261  template <typename T, template <typename> class U>
262  friend struct poly_base;
263 
264  typedef I interface_type;
265 
266  // Construct from value type
267 
268  template <typename T>
269  explicit poly_base(T x,
270  typename boost::disable_if<boost::is_base_of<poly_base, T> >::type* = 0)
271  { ::new (storage()) implementation::poly_instance<Instance<T> >(adobe::move(x)); }
272 
273  // Construct from related interface (might throw on downcast)
274  template <typename J, template <typename> class K>
275  explicit poly_base(const poly_base<J, K>& x ,
276  typename boost::enable_if<is_base_derived_or_same<I, J> >::type* dummy = 0)
277  {
278  if(boost::is_base_of<J, I>::value)
279  dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
280  x.interface_ref().clone(storage());
281  }
282 
283  poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
284 
285  poly_base(move_from<poly_base> x) { x.source.interface_ref().move_clone(storage()); }
286 
287  friend inline void swap(poly_base& x, poly_base& y)
288  {
289  interface_type& a(x.interface_ref());
290  interface_type& b(y.interface_ref());
291 
292  if (a.type_info() == b.type_info()) { a.exchange(b); return; }
293 
294  // x->tmp
295  poly_base tmp(adobe::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  {
308  interface_ref().~interface_type();
309  x.interface_ref().move_clone(storage());
310  return *this;
311  }
312  ~poly_base() { interface_ref().~interface_type(); }
313 
314  template <typename J, template <typename> class K>
316  {
317  return dynamic_cast<const I*>(static_cast<const poly_copyable_interface*>(&x.interface_ref()));
318  }
319 
320  template <typename J>
322  {
323  return dynamic_cast<const J*>(static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL;
324  }
325 
326  const std::type_info& type_info() const
327  { return interface_ref().type_info(); }
328 
329  template <typename T> const T& cast() const
330  {
331  if (type_info() != typeid(T))
332  throw bad_cast(type_info(), typeid(T));
333  return *static_cast<const T*>(interface_ref().cast());
334  }
335 
336  template <typename T> T& cast()
337  {
338  if (type_info() != typeid(T))
339  throw bad_cast(type_info(), typeid(T));
340  return *static_cast<T*>(interface_ref().cast());
341  }
342 
343  template <typename T> bool cast(T& x) const
344  {
345  if (type_info() != typeid(T))
346  return false;
347  x = cast<T>();
348  return true;
349  }
350 
351 #ifndef NO_ASL_AI_CONCEPT_CHECK
352  template <typename T> poly_base& assign(const T& x)
353  {
354  if (type_info() == typeid(T))
355  cast<T>() = x;
356  else
357  {
358  poly_base tmp(x);
359  swap(*this, tmp);
360  }
361  return *this;
362  }
363 
364  // Assign from related (may throw if downcastisng)
365  template <typename J, template <typename> class K>
366  typename boost::enable_if<is_base_derived_or_same<I, J> >::type
368  {
369  if(boost::is_base_of<J, I>::value)
370  dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); //make sure type safe
371  interface_ref().~interface_type();
372  x.interface_ref().clone(storage());
373  }
374 #endif
375 
376  const interface_type* operator->() const
377  { return &interface_ref(); }
378 
379  interface_type* operator->()
380  { return &interface_ref(); }
381 
382  interface_type& interface_ref()
383  { return *static_cast<interface_type*>(storage()); }
384 
385  const interface_type& interface_ref() const
386  { return *static_cast<const interface_type *>(storage()); }
387 
388  void* storage() { return &data_m; }
389  const void* storage() const { return &data_m; }
390 
391  implementation::storage_t data_m;
392 
393 };
394 
395 template <class J, template <typename> class K>
396 inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
398 { return x.interface_ref().equals(y.interface_ref()); }
399 
400 
401 /*************************************************************************************************/
402 
413 template <class F>
414 class poly : public F
415 {
416 public:
422  template <typename T>
423  explicit poly(const T& x) : F(x) {}
424 
425  poly(move_from<poly> x) : F(move_from<F>(x.source)) {}
426 
427  poly& operator=(poly x) { static_cast<F&>(*this) = adobe::move(static_cast<F&>(x)); return *this; }
428 
429  poly() : F() {}
430 };
431 
432 /*************************************************************************************************/
433 
448 template <typename T, typename U>
450 {
451  typedef typename boost::remove_reference<T>::type target_type;
452  typedef typename target_type::interface_type target_interface_type;
453  if(!x.template is_dynamic_convertible_to<target_interface_type>())
454  throw bad_cast(typeid(poly<U>), typeid(T));
455  return reinterpret_cast<T>(x);
456 }
457 
458 /*************************************************************************************************/
459 
467 template <typename T, typename U>
468 T poly_cast(const poly<U>& x)
469 {
470  typedef typename boost::remove_reference<T>::type target_type;
471  typedef typename target_type::interface_type target_interface_type;
472  if(!x.template is_dynamic_convertible_to<target_interface_type>())
473  throw bad_cast(typeid(poly<U>), typeid(T));
474  return reinterpret_cast<T>(x);
475 }
476 
477 /*************************************************************************************************/
478 
494 template <typename T, typename U>
496 {
497  typedef typename boost::remove_pointer<T>::type target_type;
498  typedef typename target_type::interface_type target_interface_type;
499  return x->template is_dynamic_convertible_to<target_interface_type>()
500  ? reinterpret_cast<T>(x)
501  : NULL;
502 }
503 
504 /*************************************************************************************************/
505 
514 template <typename T, typename U>
515 T poly_cast(const poly<U>* x)
516 {
517  typedef typename boost::remove_pointer<T>::type target_type;
518  typedef typename target_type::interface_type target_interface_type;
519  return x->template is_dynamic_convertible_to<target_interface_type>()
520  ? reinterpret_cast<T>(x)
521  : NULL;
522 }
523 
524 /*************************************************************************************************/
525 
533 template <class T>
534 inline bool operator!=(const poly<T>& x, const poly<T>& y)
535 {
536  return !(x == y);
537 }
538 
539 
541 
542 /*************************************************************************************************/
543 
544 } // namespace adobe
545 
546 /*************************************************************************************************/
547 
548 #endif
549 
550 /*************************************************************************************************/
interface_type & interface_ref()
Definition: poly.hpp:382
poly_base & assign(const T &x)
Definition: poly.hpp:352
poly & operator=(poly x)
Definition: poly.hpp:427
virtual ~poly_copyable_interface()
Definition: poly.hpp:81
move_from is used for move_ctors.
Definition: move.hpp:306
void swap(adobe::lex_stream_t &, adobe::lex_stream_t &)
Definition: lex_stream.hpp:68
void * storage()
Definition: poly.hpp:388
poly(move_from< poly > x)
Definition: poly.hpp:425
friend void swap(poly_base &x, poly_base &y)
Definition: poly.hpp:287
bool operator==(const circular_queue< T > &x, const circular_queue< T > &y)
bool operator!=(const forest< T > &x, const forest< T > &y)
Definition: forest.hpp:719
bool cast(T &x) const
Definition: poly.hpp:343
poly_base(const poly_base &x)
Definition: poly.hpp:283
boost::enable_if< is_base_derived_or_same< I, J > >::type assign(const poly_base< J, K > &x)
Definition: poly.hpp:367
An exception class thrown during ASL failures to cast.
Definition: typeinfo.hpp:379
Authors of a Concept representative F, intended as a template parameter to adobe::poly, will inherit from adobe::poly_base. The first template parameter for adobe::poly_base provides the virtual interface for the concept representative. The second template parameter for adobe::poly_base must inherit from the Concept interface representative. The author&#39;s third duty is to provide forwarding functions in a their Concept representative. See the placeable_concept.hpp header file for details.
Definition: poly.hpp:259
const std::type_info & type_info() const
Definition: poly.hpp:326
static bool is_dynamic_convertible_from(const poly_base< J, K > &x)
Definition: poly.hpp:315
adobe::poly<foo> will be a runtime polymorphic value type wrapper modelling a concept represented by ...
Definition: poly.hpp:414
poly_base(move_from< poly_base > x)
Definition: poly.hpp:285
Abstract interface providing signatures needed to implement "handle" objects modeling a Value (Copyab...
Definition: poly.hpp:66
poly_base & operator=(poly_base x)
Definition: poly.hpp:306
poly(const T &x)
Definition: poly.hpp:423
const void * storage() const
Definition: poly.hpp:389
void swap(circular_queue< T > &, circular_queue< T > &)
const interface_type * operator->() const
Definition: poly.hpp:376
const interface_type & interface_ref() const
Definition: poly.hpp:385
bool is_dynamic_convertible_to() const
Definition: poly.hpp:321
Authors of adobe::poly concept representatives must derive their instance class from this...
Definition: poly.hpp:238
poly_base(T x, typename boost::disable_if< boost::is_base_of< poly_base, T > >::type *=0)
Definition: poly.hpp:269
const T & cast() const
Definition: poly.hpp:329
implementation::storage_t data_m
Definition: poly.hpp:391
poly_base(const poly_base< J, K > &x, typename boost::enable_if< is_base_derived_or_same< I, J > >::type *dummy=0)
Definition: poly.hpp:275
interface_type * operator->()
Definition: poly.hpp:379

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google