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     template <typename U>
00105     explicit poly_state_remote(const U& x, typename copy_sink<U, value_type>::type = 0)
00106         : value_ptr_m(::new value_type(x)) { }
00107     
00108     template <typename U>
00109     explicit poly_state_remote(U x, typename move_sink<U, value_type>::type = 0)
00110         : value_ptr_m(::new value_type(move(x))) { }
00111     
00112     ~poly_state_remote()
00113     { delete value_ptr_m; }
00114 
00115     // Precondition : this->type_info() == x.type_info()
00116     void assign(const poly_copyable_interface& x)
00117     { *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m; }
00118 
00119     const std::type_info& type_info() const
00120     { return typeid(value_type); }
00121     const void* cast() const { return value_ptr_m; }
00122     void* cast() { return value_ptr_m; }
00123 
00124     // Precondition : this->type_info() == x.type_info()
00125     void exchange(poly_copyable_interface& x)
00126     { return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m); }
00127 
00128     // Precondition : this->type_info() == x.type_info()
00129     friend bool operator==(const poly_state_remote& x, const poly_state_remote& y)
00130     { return *x.value_ptr_m == *y.value_ptr_m; }
00131 
00132     value_type* value_ptr_m;
00133 };
00134 
00135 /*************************************************************************************************/
00136 
00137 template <typename ConcreteType, typename Interface>
00138 struct poly_state_local : Interface
00139 {
00140     typedef ConcreteType value_type;
00141     typedef Interface    interface_type;
00142 
00143     const value_type& get() const { return value_m; }
00144     value_type& get() { return value_m; }
00145 
00146     poly_state_local(move_from<poly_state_local> x)
00147         : value_m(move(x.source.value_m)){ }
00148 
00149     template <typename U>
00150     explicit poly_state_local(const U& x, typename copy_sink<U, value_type>::type = 0)
00151         : value_m(x) { }
00152     
00153     template <typename U>
00154     explicit poly_state_local(U x, typename move_sink<U, value_type>::type = 0)
00155         : value_m(move(x)) { }
00156     
00157     // Precondition : this->type_info() == x.type_info()
00158     void assign(const poly_copyable_interface& x)
00159     { value_m = static_cast<const poly_state_local&>(x).value_m; }
00160 
00161     const std::type_info& type_info() const
00162     { return typeid(value_type); }
00163     const void* cast() const { return &value_m; }
00164     void* cast() { return &value_m; }
00165      
00166     // Precondition : this->type_info() == x.type_info()
00167     void exchange(poly_copyable_interface& x)
00168     { return std::swap(value_m, static_cast<poly_state_local&>(x).value_m); }
00169 
00170     // Precondition : this->type_info() == x.type_info()
00171     friend bool operator==(const poly_state_local& x, const poly_state_local& y)
00172     { return x.value_m == y.value_m; }
00173 
00174     value_type value_m;
00175 };
00176 
00177 
00178 /*************************************************************************************************/
00179 
00180 typedef double storage_t[2];
00181 
00182 template<typename T, int N=sizeof(storage_t)>
00183 struct is_small
00184 {
00185     enum { value = sizeof(T) <= N && (boost::has_nothrow_constructor<typename T::value_type>::value ||
00186                                       boost::is_same<std::string, typename T::value_type>::value) };
00187 
00188 };
00189 
00190 /*************************************************************************************************/
00191 
00192 template <typename F>
00193 struct poly_instance : F {
00194     typedef typename F::value_type value_type;
00195     typedef typename F::interface_type interface_type;
00196 
00197     poly_instance(const value_type& x): F(x){ }
00198     poly_instance(move_from<poly_instance> x) : F(move_from<F>(x.source)) { }
00199 
00200     poly_copyable_interface* clone(void* storage) const
00201     { return ::new (storage) poly_instance(this->get()); }
00202 
00203     poly_copyable_interface* move_clone(void* storage)
00204     { return ::new (storage) poly_instance(move_from<poly_instance>(*this)); }
00205 };
00206 
00207 /*************************************************************************************************/
00208 
00209 template <typename T> 
00210 class has_equals { 
00211     typedef bool (T::*E)(const T&) const; 
00212     typedef char (&no_type)[1]; 
00213     typedef char (&yes_type)[2]; 
00214     template <E e> struct sfinae { typedef yes_type type; }; 
00215     template <class U> 
00216     static typename sfinae<&U::equals>::type test(int); 
00217     template <class U> 
00218     static no_type test(...); 
00219 public: 
00220     enum {value = sizeof(test<T>(1)) == sizeof(yes_type)}; 
00221 }; 
00222 
00223 /*************************************************************************************************/
00224 
00225 } //namespace implementation
00226 
00227 /*************************************************************************************************/
00228 
00229 #endif
00230 //  !defined(ADOBE_NO_DOCUMENTATION)
00231 
00232 /*************************************************************************************************/
00233 
00241 template <typename ConcreteType, typename Interface>
00242 struct optimized_storage_type : 
00243     boost::mpl::if_<implementation::is_small<implementation::poly_state_local<ConcreteType, Interface> >,
00244                     implementation::poly_state_local<ConcreteType, Interface>,
00245                     implementation::poly_state_remote<ConcreteType, Interface> > {
00246 };
00247 
00248 
00249 /*************************************************************************************************/
00250 
00262 template <typename I, template <typename> class Instance>
00263 struct poly_base {
00264 
00265     template <typename T, template <typename> class U>
00266     friend struct poly_base;
00267 
00268     typedef I interface_type;
00269 
00270     // Construct from value type
00271     template <typename T>
00272     explicit poly_base(const T& x, 
00273         typename copy_sink<T>::type = 0, 
00274         typename boost::disable_if<boost::is_base_of<poly_base, T> >::type* = 0)
00275     { ::new (storage()) implementation::poly_instance<Instance<T> >(x); }
00276     
00277     template <typename T>
00278     explicit poly_base(T x, 
00279         typename move_sink<T>::type = 0,
00280         typename boost::disable_if<boost::is_base_of<poly_base, T> >::type* = 0)
00281     { ::new (storage()) implementation::poly_instance<Instance<T> >(move(x)); }
00282 
00283 
00284 
00285 
00286     // Construct from related interface (might throw on downcast)
00287     template <typename J, template <typename> class K> 
00288     explicit poly_base(const poly_base<J, K>& x , 
00289         typename boost::enable_if<is_base_derived_or_same<I, J> >::type* dummy = 0)
00290     {
00291         if(boost::is_base_of<J, I>::value)
00292             dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
00293        x.interface_ref().clone(storage());    
00294     }
00295 
00296     poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
00297 
00298     poly_base(move_from<poly_base> x) { x.source.interface_ref().move_clone(storage()); }
00299 
00300     friend inline void swap(poly_base& x, poly_base& y)
00301     {
00302         interface_type& a(x.interface_ref());
00303         interface_type& b(y.interface_ref());
00304     
00305         if (a.type_info() == b.type_info()) { a.exchange(b); return; }
00306 
00307         // x->tmp
00308         poly_base tmp(move(x));
00309         a.~interface_type();
00310         
00311         // y->x
00312         b.move_clone(x.storage());
00313         b.~interface_type();
00314         
00315         // tmp->y
00316         tmp.interface_ref().move_clone(y.storage());
00317     }
00318 
00319     poly_base& operator=(poly_base x)
00320     {
00321         interface_ref().~interface_type();
00322         x.interface_ref().move_clone(storage());
00323         return *this;
00324     }
00325     ~poly_base() { interface_ref().~interface_type(); }
00326 
00327     template <typename J, template <typename> class K>
00328     static bool is_dynamic_convertible_from(const poly_base<J, K>& x)
00329     { 
00330         return dynamic_cast<const I*>(static_cast<const poly_copyable_interface*>(&x.interface_ref())); 
00331     }
00332 
00333     template <typename J>
00334     bool is_dynamic_convertible_to() const
00335     { 
00336         return dynamic_cast<const J*>(static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL; 
00337     }   
00338 
00339     const std::type_info& type_info() const
00340         { return interface_ref().type_info(); }
00341 
00342     template <typename T> const T& cast() const
00343     {
00344         if (type_info() != typeid(T))
00345             throw bad_cast(type_info(), typeid(T));
00346         return *static_cast<const T*>(interface_ref().cast());
00347     }
00348 
00349     template <typename T> T& cast()
00350     {
00351         if (type_info() != typeid(T))
00352             throw bad_cast(type_info(), typeid(T));
00353         return *static_cast<T*>(interface_ref().cast());
00354     }
00355 
00356     template <typename T> bool cast(T& x) const
00357     {
00358         if (type_info() != typeid(T))
00359             return false;
00360         x = cast<T>();
00361         return true;
00362     }
00363 
00364     template <typename T> poly_base& assign(const T& x)
00365     {
00366         if (type_info() == typeid(T))
00367             cast<T>() = x;
00368         else
00369         {
00370             poly_base tmp(x);
00371             swap(*this, tmp);
00372         }
00373         return *this;
00374     }
00375 
00376         // Assign from related (may throw if downcastisng)
00377     template <typename J, template <typename> class K> 
00378     typename boost::enable_if<is_base_derived_or_same<I, J> >::type
00379     assign(const poly_base<J, K>& x)
00380     {
00381         if(boost::is_base_of<J, I>::value)
00382             dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); //make sure type safe
00383         interface_ref().~interface_type();
00384         x.interface_ref().clone(storage());      
00385     }
00386 
00387     const interface_type* operator->() const
00388     { return &interface_ref(); }
00389 
00390     interface_type* operator->()
00391     { return &interface_ref(); }
00392 
00393     interface_type& interface_ref() 
00394     { return *static_cast<interface_type*>(storage()); }
00395     
00396     const interface_type& interface_ref() const 
00397     { return *static_cast<const interface_type *>(storage()); }
00398 
00399     void* storage() { return &data_m; }
00400     const void* storage() const { return &data_m; }
00401     
00402     implementation::storage_t data_m;
00403 
00404 };
00405 
00406 template <class J, template <typename> class K>
00407 inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
00408 operator==(const poly_base<J, K>& x, const poly_base<J, K>& y)
00409 { return x.interface_ref().equals(y.interface_ref()); }
00410 
00411 
00412 /*************************************************************************************************/
00413 
00424 template <class F>   
00425 class poly : public F
00426 {
00427 public:  
00433     template <typename T>
00434     explicit poly(const T& x) : F(x) {}    
00435 
00436     poly(move_from<poly> x) : F(move_from<F>(x.source)) {}
00437     
00438     poly& operator=(poly x) { static_cast<F&>(*this) = move(static_cast<F&>(x)); return *this; }
00439 
00440     poly() : F() {}
00441 };
00442 
00443 /*************************************************************************************************/
00444 
00459 template <typename T, typename U>
00460 T poly_cast(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 
00478 template <typename T, typename U>
00479 T poly_cast(const poly<U>& x)
00480 { 
00481     typedef typename boost::remove_reference<T>::type target_type;
00482     typedef typename target_type::interface_type target_interface_type;
00483     if(!x.template is_dynamic_convertible_to<target_interface_type>())
00484         throw bad_cast(typeid(poly<U>), typeid(T));
00485     return reinterpret_cast<T>(x);
00486 }
00487 
00488 /*************************************************************************************************/
00489 
00505 template <typename T, typename U>
00506 T poly_cast(poly<U>* x)
00507 { 
00508     typedef typename boost::remove_pointer<T>::type target_type;
00509     typedef typename target_type::interface_type target_interface_type;
00510     return x->template is_dynamic_convertible_to<target_interface_type>()
00511         ? reinterpret_cast<T>(x)
00512         : NULL;
00513 }
00514 
00515 /*************************************************************************************************/
00516 
00525 template <typename T, typename U>
00526 T poly_cast(const poly<U>* x)
00527 { 
00528     typedef typename boost::remove_pointer<T>::type target_type;
00529     typedef typename target_type::interface_type target_interface_type;
00530     return x->template is_dynamic_convertible_to<target_interface_type>()
00531         ? reinterpret_cast<T>(x)
00532         : NULL;
00533 }
00534 
00535 /*************************************************************************************************/
00536 
00544 template <class T>
00545 inline bool operator!=(const poly<T>& x, const poly<T>& y)
00546 {
00547     return !(x == y);
00548 }
00549 
00550 
00552 
00553 /*************************************************************************************************/
00554 
00555 } // namespace adobe
00556 
00557 /*************************************************************************************************/
00558 
00559 #endif
00560 
00561 /*************************************************************************************************/

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