stlab.adobe.com Adobe Systems Incorporated

poly.hpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2007 Adobe Systems Incorporated
00003     Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
00004     or a copy at http://stlab.adobe.com/licenses.html)
00005 */
00006 
00007 /*************************************************************************************************/
00008 
00009 #ifndef ADOBE_POLY_HPP
00010 #define ADOBE_POLY_HPP
00011 
00012 #include <adobe/config.hpp>
00013 
00014 
00015 #include <boost/type_traits/is_base_of.hpp>
00016 #include <boost/type_traits/remove_reference.hpp>
00017 #include <boost/type_traits/remove_pointer.hpp>
00018 #include <boost/utility/enable_if.hpp>
00019 #include <boost/mpl/or.hpp>
00020 #include <boost/mpl/if.hpp>
00021 #include <boost/mpl/bool.hpp>
00022 #include <boost/type_traits/has_nothrow_constructor.hpp>
00023 
00024 #include <adobe/move.hpp>
00025 #include <adobe/implementation/swap.hpp>
00026 #include <adobe/typeinfo.hpp>
00027 
00028 /*************************************************************************************************/
00029 
00030 namespace adobe {
00031 
00032 
00048 #if !defined(ADOBE_NO_DOCUMENTATION)
00049 
00050 template <typename T, typename U>
00051 struct is_base_derived_or_same : boost::mpl::or_<boost::is_base_of<T, U>,
00052                                                  boost::is_base_of<U, T>,
00053                                                  boost::is_same<T, U> > {};
00054 #endif
00055 // !defined(ADOBE_NO_DOCUMENTATION)
00056 
00057 /*************************************************************************************************/
00058 
00066 struct poly_copyable_interface {
00067     virtual poly_copyable_interface* clone(void*) const = 0;
00068     virtual poly_copyable_interface* move_clone(void*) = 0;
00069     virtual void* cast() = 0;
00070     virtual const void* cast() const = 0;
00071     virtual const std::type_info& type_info() const = 0;
00072 
00073     // Precondition of assignment: this->type_info() == x.type_info()
00074     virtual void assign(const poly_copyable_interface& x) = 0;
00075 
00076     // Precondition of exchange: this->type_info() == x.type_info()
00077     virtual void exchange(poly_copyable_interface& x) = 0;
00078 
00079     virtual ~poly_copyable_interface() {}
00080 };
00081 
00082 /*************************************************************************************************/
00083 
00084 #if !defined(ADOBE_NO_DOCUMENTATION)
00085 
00086 /*************************************************************************************************/
00087 
00088 namespace implementation {
00089 
00090 /*************************************************************************************************/
00091 
00092 template <typename ConcreteType, typename Interface>
00093 struct poly_state_remote : Interface
00094 {
00095     typedef ConcreteType value_type;
00096     typedef Interface    interface_type;
00097 
00098     const value_type& get() const { return *value_ptr_m; }
00099     value_type& get() { return *value_ptr_m; }
00100 
00101     poly_state_remote(move_from<poly_state_remote> x)
00102         : value_ptr_m(x.source.value_ptr_m){ x.source.value_ptr_m = NULL; }
00103 
00104     explicit poly_state_remote(value_type x)
00105         : value_ptr_m(::new value_type(adobe::move(x))) { }
00106 
00107     ~poly_state_remote()
00108     { delete value_ptr_m; }
00109 
00110     // Precondition : this->type_info() == x.type_info()
00111     void assign(const poly_copyable_interface& x)
00112     { *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m; }
00113 
00114     const std::type_info& type_info() const
00115     { return typeid(value_type); }
00116     const void* cast() const { return value_ptr_m; }
00117     void* cast() { return value_ptr_m; }
00118 
00119     // Precondition : this->type_info() == x.type_info()
00120     void exchange(poly_copyable_interface& x)
00121     { return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m); }
00122 
00123     // Precondition : this->type_info() == x.type_info()
00124     friend bool operator==(const poly_state_remote& x, const poly_state_remote& y)
00125     { return *x.value_ptr_m == *y.value_ptr_m; }
00126 
00127     value_type* value_ptr_m;
00128 };
00129 
00130 /*************************************************************************************************/
00131 
00132 template <typename ConcreteType, typename Interface>
00133 struct poly_state_local : Interface
00134 {
00135     typedef ConcreteType value_type;
00136     typedef Interface    interface_type;
00137 
00138     const value_type& get() const { return value_m; }
00139     value_type& get() { return value_m; }
00140 
00141     poly_state_local(move_from<poly_state_local> x)
00142         : value_m(adobe::move(x.source.value_m)){ }
00143 
00144     explicit poly_state_local(value_type x)
00145         : value_m(adobe::move(x)) { }
00146 
00147     // Precondition : this->type_info() == x.type_info()
00148     void assign(const poly_copyable_interface& x)
00149     { value_m = static_cast<const poly_state_local&>(x).value_m; }
00150 
00151     const std::type_info& type_info() const
00152     { return typeid(value_type); }
00153     const void* cast() const { return &value_m; }
00154     void* cast() { return &value_m; }
00155 
00156     // Precondition : this->type_info() == x.type_info()
00157     void exchange(poly_copyable_interface& x)
00158     { return std::swap(value_m, static_cast<poly_state_local&>(x).value_m); }
00159 
00160     // Precondition : this->type_info() == x.type_info()
00161     friend bool operator==(const poly_state_local& x, const poly_state_local& y)
00162     { return x.value_m == y.value_m; }
00163 
00164     value_type value_m;
00165 };
00166 
00167 
00168 /*************************************************************************************************/
00169 
00170 typedef double storage_t[2];
00171 
00172 template<typename T, int N=sizeof(storage_t)>
00173 struct is_small
00174 {
00175     enum { value = sizeof(T) <= N && (boost::has_nothrow_constructor<typename T::value_type>::value ||
00176                                       boost::is_same<std::string, typename T::value_type>::value) };
00177 
00178 };
00179 
00180 /*************************************************************************************************/
00181 
00182 template <typename F>
00183 struct poly_instance : F {
00184     typedef typename F::value_type value_type;
00185     typedef typename F::interface_type interface_type;
00186 
00187     poly_instance(const value_type& x): F(x){ }
00188     poly_instance(move_from<poly_instance> x) : F(move_from<F>(x.source)) { }
00189 
00190     poly_copyable_interface* clone(void* storage) const
00191     { return ::new (storage) poly_instance(this->get()); }
00192 
00193     poly_copyable_interface* move_clone(void* storage)
00194     { return ::new (storage) poly_instance(move_from<poly_instance>(*this)); }
00195 };
00196 
00197 /*************************************************************************************************/
00198 
00199 template <typename T>
00200 class has_equals {
00201     typedef bool (T::*E)(const T&) const;
00202     typedef char (&no_type)[1];
00203     typedef char (&yes_type)[2];
00204     template <E e> struct sfinae { typedef yes_type type; };
00205     template <class U>
00206     static typename sfinae<&U::equals>::type test(int);
00207     template <class U>
00208     static no_type test(...);
00209 public:
00210     enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
00211 };
00212 
00213 /*************************************************************************************************/
00214 
00215 } //namespace implementation
00216 
00217 /*************************************************************************************************/
00218 
00219 #endif
00220 //  !defined(ADOBE_NO_DOCUMENTATION)
00221 
00222 /*************************************************************************************************/
00223 
00231 template <typename ConcreteType, typename Interface>
00232 struct optimized_storage_type :
00233     boost::mpl::if_<implementation::is_small<implementation::poly_state_local<ConcreteType, Interface> >,
00234                     implementation::poly_state_local<ConcreteType, Interface>,
00235                     implementation::poly_state_remote<ConcreteType, Interface> > {
00236 };
00237 
00238 
00239 /*************************************************************************************************/
00240 
00252 template <typename I, template <typename> class Instance>
00253 struct poly_base {
00254 
00255     template <typename T, template <typename> class U>
00256     friend struct poly_base;
00257 
00258     typedef I interface_type;
00259 
00260     // Construct from value type
00261 
00262     template <typename T>
00263     explicit poly_base(T x,
00264         typename boost::disable_if<boost::is_base_of<poly_base, T> >::type* = 0)
00265     { ::new (storage()) implementation::poly_instance<Instance<T> >(adobe::move(x)); }
00266 
00267     // Construct from related interface (might throw on downcast)
00268     template <typename J, template <typename> class K>
00269     explicit poly_base(const poly_base<J, K>& x ,
00270         typename boost::enable_if<is_base_derived_or_same<I, J> >::type* dummy = 0)
00271     {
00272         if(boost::is_base_of<J, I>::value)
00273             dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
00274        x.interface_ref().clone(storage());
00275     }
00276 
00277     poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
00278 
00279     poly_base(move_from<poly_base> x) { x.source.interface_ref().move_clone(storage()); }
00280 
00281     friend inline void swap(poly_base& x, poly_base& y)
00282     {
00283         interface_type& a(x.interface_ref());
00284         interface_type& b(y.interface_ref());
00285 
00286         if (a.type_info() == b.type_info()) { a.exchange(b); return; }
00287 
00288         // x->tmp
00289         poly_base tmp(adobe::move(x));
00290         a.~interface_type();
00291 
00292         // y->x
00293         b.move_clone(x.storage());
00294         b.~interface_type();
00295 
00296         // tmp->y
00297         tmp.interface_ref().move_clone(y.storage());
00298     }
00299 
00300     poly_base& operator=(poly_base x)
00301     {
00302         interface_ref().~interface_type();
00303         x.interface_ref().move_clone(storage());
00304         return *this;
00305     }
00306     ~poly_base() { interface_ref().~interface_type(); }
00307 
00308     template <typename J, template <typename> class K>
00309     static bool is_dynamic_convertible_from(const poly_base<J, K>& x)
00310     {
00311         return dynamic_cast<const I*>(static_cast<const poly_copyable_interface*>(&x.interface_ref()));
00312     }
00313 
00314     template <typename J>
00315     bool is_dynamic_convertible_to() const
00316     {
00317         return dynamic_cast<const J*>(static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL;
00318     }
00319 
00320     const std::type_info& type_info() const
00321         { return interface_ref().type_info(); }
00322 
00323     template <typename T> const T& cast() const
00324     {
00325         if (type_info() != typeid(T))
00326             throw bad_cast(type_info(), typeid(T));
00327         return *static_cast<const T*>(interface_ref().cast());
00328     }
00329 
00330     template <typename T> T& cast()
00331     {
00332         if (type_info() != typeid(T))
00333             throw bad_cast(type_info(), typeid(T));
00334         return *static_cast<T*>(interface_ref().cast());
00335     }
00336 
00337     template <typename T> bool cast(T& x) const
00338     {
00339         if (type_info() != typeid(T))
00340             return false;
00341         x = cast<T>();
00342         return true;
00343     }
00344 
00345     template <typename T> poly_base& assign(const T& x)
00346     {
00347         if (type_info() == typeid(T))
00348             cast<T>() = x;
00349         else
00350         {
00351             poly_base tmp(x);
00352             swap(*this, tmp);
00353         }
00354         return *this;
00355     }
00356 
00357         // Assign from related (may throw if downcastisng)
00358     template <typename J, template <typename> class K>
00359     typename boost::enable_if<is_base_derived_or_same<I, J> >::type
00360     assign(const poly_base<J, K>& x)
00361     {
00362         if(boost::is_base_of<J, I>::value)
00363             dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); //make sure type safe
00364         interface_ref().~interface_type();
00365         x.interface_ref().clone(storage());
00366     }
00367 
00368     const interface_type* operator->() const
00369     { return &interface_ref(); }
00370 
00371     interface_type* operator->()
00372     { return &interface_ref(); }
00373 
00374     interface_type& interface_ref()
00375     { return *static_cast<interface_type*>(storage()); }
00376 
00377     const interface_type& interface_ref() const
00378     { return *static_cast<const interface_type *>(storage()); }
00379 
00380     void* storage() { return &data_m; }
00381     const void* storage() const { return &data_m; }
00382 
00383     implementation::storage_t data_m;
00384 
00385 };
00386 
00387 template <class J, template <typename> class K>
00388 inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
00389 operator==(const poly_base<J, K>& x, const poly_base<J, K>& y)
00390 { return x.interface_ref().equals(y.interface_ref()); }
00391 
00392 
00393 /*************************************************************************************************/
00394 
00405 template <class F>
00406 class poly : public F
00407 {
00408 public:
00414     template <typename T>
00415     explicit poly(const T& x) : F(x) {}
00416 
00417     poly(move_from<poly> x) : F(move_from<F>(x.source)) {}
00418 
00419     poly& operator=(poly x) { static_cast<F&>(*this) = adobe::move(static_cast<F&>(x)); return *this; }
00420 
00421     poly() : F() {}
00422 };
00423 
00424 /*************************************************************************************************/
00425 
00440 template <typename T, typename U>
00441 T poly_cast(poly<U>& x)
00442 {
00443     typedef typename boost::remove_reference<T>::type target_type;
00444     typedef typename target_type::interface_type target_interface_type;
00445     if(!x.template is_dynamic_convertible_to<target_interface_type>())
00446         throw bad_cast(typeid(poly<U>), typeid(T));
00447     return reinterpret_cast<T>(x);
00448 }
00449 
00450 /*************************************************************************************************/
00451 
00459 template <typename T, typename U>
00460 T poly_cast(const poly<U>& x)
00461 {
00462     typedef typename boost::remove_reference<T>::type target_type;
00463     typedef typename target_type::interface_type target_interface_type;
00464     if(!x.template is_dynamic_convertible_to<target_interface_type>())
00465         throw bad_cast(typeid(poly<U>), typeid(T));
00466     return reinterpret_cast<T>(x);
00467 }
00468 
00469 /*************************************************************************************************/
00470 
00486 template <typename T, typename U>
00487 T poly_cast(poly<U>* x)
00488 {
00489     typedef typename boost::remove_pointer<T>::type target_type;
00490     typedef typename target_type::interface_type target_interface_type;
00491     return x->template is_dynamic_convertible_to<target_interface_type>()
00492         ? reinterpret_cast<T>(x)
00493         : NULL;
00494 }
00495 
00496 /*************************************************************************************************/
00497 
00506 template <typename T, typename U>
00507 T poly_cast(const poly<U>* x)
00508 {
00509     typedef typename boost::remove_pointer<T>::type target_type;
00510     typedef typename target_type::interface_type target_interface_type;
00511     return x->template is_dynamic_convertible_to<target_interface_type>()
00512         ? reinterpret_cast<T>(x)
00513         : NULL;
00514 }
00515 
00516 /*************************************************************************************************/
00517 
00525 template <class T>
00526 inline bool operator!=(const poly<T>& x, const poly<T>& y)
00527 {
00528     return !(x == y);
00529 }
00530 
00531 
00533 
00534 /*************************************************************************************************/
00535 
00536 } // namespace adobe
00537 
00538 /*************************************************************************************************/
00539 
00540 #endif
00541 
00542 /*************************************************************************************************/

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