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 #ifndef NO_ASL_AI_CONCEPT_CHECK
00074     // Precondition of assignment: this->type_info() == x.type_info()
00075     virtual void assign(const poly_copyable_interface& x) = 0;
00076 #endif
00077 
00078     // Precondition of exchange: this->type_info() == x.type_info()
00079     virtual void exchange(poly_copyable_interface& x) = 0;
00080 
00081     virtual ~poly_copyable_interface() {}
00082 };
00083 
00084 /*************************************************************************************************/
00085 
00086 #if !defined(ADOBE_NO_DOCUMENTATION)
00087 
00088 /*************************************************************************************************/
00089 
00090 namespace implementation {
00091 
00092 /*************************************************************************************************/
00093 
00094 template <typename ConcreteType, typename Interface>
00095 struct poly_state_remote : Interface
00096 {
00097     typedef ConcreteType value_type;
00098     typedef Interface    interface_type;
00099 
00100     const value_type& get() const { return *value_ptr_m; }
00101     value_type& get() { return *value_ptr_m; }
00102 
00103     poly_state_remote(move_from<poly_state_remote> x)
00104         : value_ptr_m(x.source.value_ptr_m){ x.source.value_ptr_m = NULL; }
00105 
00106     explicit poly_state_remote(value_type x)
00107         : value_ptr_m(::new value_type(adobe::move(x))) { }
00108 
00109     ~poly_state_remote()
00110     { delete value_ptr_m; }
00111 
00112 #ifndef NO_ASL_AI_CONCEPT_CHECK
00113     // Precondition : this->type_info() == x.type_info()
00114     void assign(const poly_copyable_interface& x)
00115     { *value_ptr_m = *static_cast<const poly_state_remote&>(x).value_ptr_m; }
00116 #endif
00117 
00118     const std::type_info& type_info() const
00119     { return typeid(value_type); }
00120     const void* cast() const { return value_ptr_m; }
00121     void* cast() { return value_ptr_m; }
00122 
00123     // Precondition : this->type_info() == x.type_info()
00124     void exchange(poly_copyable_interface& x)
00125     { return std::swap(value_ptr_m, static_cast<poly_state_remote&>(x).value_ptr_m); }
00126 
00127     // Precondition : this->type_info() == x.type_info()
00128     friend bool operator==(const poly_state_remote& x, const poly_state_remote& y)
00129     { return *x.value_ptr_m == *y.value_ptr_m; }
00130 
00131     value_type* value_ptr_m;
00132 };
00133 
00134 /*************************************************************************************************/
00135 
00136 template <typename ConcreteType, typename Interface>
00137 struct poly_state_local : Interface
00138 {
00139     typedef ConcreteType value_type;
00140     typedef Interface    interface_type;
00141 
00142     const value_type& get() const { return value_m; }
00143     value_type& get() { return value_m; }
00144 
00145     poly_state_local(move_from<poly_state_local> x)
00146         : value_m(adobe::move(x.source.value_m)){ }
00147 
00148     explicit poly_state_local(value_type x)
00149         : value_m(adobe::move(x)) { }
00150 
00151 #ifndef NO_ASL_AI_CONCEPT_CHECK
00152     // Precondition : this->type_info() == x.type_info()
00153     void assign(const poly_copyable_interface& x)
00154     { value_m = static_cast<const poly_state_local&>(x).value_m; }
00155 #endif
00156 
00157     const std::type_info& type_info() const
00158     { return typeid(value_type); }
00159     const void* cast() const { return &value_m; }
00160     void* cast() { return &value_m; }
00161 
00162     // Precondition : this->type_info() == x.type_info()
00163     void exchange(poly_copyable_interface& x)
00164     { return std::swap(value_m, static_cast<poly_state_local&>(x).value_m); }
00165 
00166     // Precondition : this->type_info() == x.type_info()
00167     friend bool operator==(const poly_state_local& x, const poly_state_local& y)
00168     { return x.value_m == y.value_m; }
00169 
00170     value_type value_m;
00171 };
00172 
00173 
00174 /*************************************************************************************************/
00175 
00176 typedef double storage_t[2];
00177 
00178 template<typename T, int N=sizeof(storage_t)>
00179 struct is_small
00180 {
00181     enum { value = sizeof(T) <= N && (boost::has_nothrow_constructor<typename T::value_type>::value ||
00182                                       boost::is_same<std::string, typename T::value_type>::value) };
00183 
00184 };
00185 
00186 /*************************************************************************************************/
00187 
00188 template <typename F>
00189 struct poly_instance : F {
00190     typedef typename F::value_type value_type;
00191     typedef typename F::interface_type interface_type;
00192 
00193     poly_instance(const value_type& x): F(x){ }
00194     poly_instance(move_from<poly_instance> x) : F(move_from<F>(x.source)) { }
00195 
00196     poly_copyable_interface* clone(void* storage) const
00197     { return ::new (storage) poly_instance(this->get()); }
00198 
00199     poly_copyable_interface* move_clone(void* storage)
00200     { return ::new (storage) poly_instance(move_from<poly_instance>(*this)); }
00201 };
00202 
00203 /*************************************************************************************************/
00204 
00205 template <typename T>
00206 class has_equals {
00207     typedef bool (T::*E)(const T&) const;
00208     typedef char (&no_type)[1];
00209     typedef char (&yes_type)[2];
00210     template <E e> struct sfinae { typedef yes_type type; };
00211     template <class U>
00212     static typename sfinae<&U::equals>::type test(int);
00213     template <class U>
00214     static no_type test(...);
00215 public:
00216     enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
00217 };
00218 
00219 /*************************************************************************************************/
00220 
00221 } //namespace implementation
00222 
00223 /*************************************************************************************************/
00224 
00225 #endif
00226 //  !defined(ADOBE_NO_DOCUMENTATION)
00227 
00228 /*************************************************************************************************/
00229 
00237 template <typename ConcreteType, typename Interface>
00238 struct optimized_storage_type :
00239     boost::mpl::if_<implementation::is_small<implementation::poly_state_local<ConcreteType, Interface> >,
00240                     implementation::poly_state_local<ConcreteType, Interface>,
00241                     implementation::poly_state_remote<ConcreteType, Interface> > {
00242 };
00243 
00244 
00245 /*************************************************************************************************/
00246 
00258 template <typename I, template <typename> class Instance>
00259 struct poly_base {
00260 
00261     template <typename T, template <typename> class U>
00262     friend struct poly_base;
00263 
00264     typedef I interface_type;
00265 
00266     // Construct from value type
00267 
00268     template <typename T>
00269     explicit poly_base(T x,
00270         typename boost::disable_if<boost::is_base_of<poly_base, T> >::type* = 0)
00271     { ::new (storage()) implementation::poly_instance<Instance<T> >(adobe::move(x)); }
00272 
00273     // Construct from related interface (might throw on downcast)
00274     template <typename J, template <typename> class K>
00275     explicit poly_base(const poly_base<J, K>& x ,
00276         typename boost::enable_if<is_base_derived_or_same<I, J> >::type* dummy = 0)
00277     {
00278         if(boost::is_base_of<J, I>::value)
00279             dynamic_cast<const I&>(static_cast<const poly_copyable_interface&>(x.interface_ref()));
00280        x.interface_ref().clone(storage());
00281     }
00282 
00283     poly_base(const poly_base& x) { x.interface_ref().clone(storage()); }
00284 
00285     poly_base(move_from<poly_base> x) { x.source.interface_ref().move_clone(storage()); }
00286 
00287     friend inline void swap(poly_base& x, poly_base& y)
00288     {
00289         interface_type& a(x.interface_ref());
00290         interface_type& b(y.interface_ref());
00291 
00292         if (a.type_info() == b.type_info()) { a.exchange(b); return; }
00293 
00294         // x->tmp
00295         poly_base tmp(adobe::move(x));
00296         a.~interface_type();
00297 
00298         // y->x
00299         b.move_clone(x.storage());
00300         b.~interface_type();
00301 
00302         // tmp->y
00303         tmp.interface_ref().move_clone(y.storage());
00304     }
00305 
00306     poly_base& operator=(poly_base x)
00307     {
00308         interface_ref().~interface_type();
00309         x.interface_ref().move_clone(storage());
00310         return *this;
00311     }
00312     ~poly_base() { interface_ref().~interface_type(); }
00313 
00314     template <typename J, template <typename> class K>
00315     static bool is_dynamic_convertible_from(const poly_base<J, K>& x)
00316     {
00317         return dynamic_cast<const I*>(static_cast<const poly_copyable_interface*>(&x.interface_ref()));
00318     }
00319 
00320     template <typename J>
00321     bool is_dynamic_convertible_to() const
00322     {
00323         return dynamic_cast<const J*>(static_cast<const poly_copyable_interface*>(&interface_ref())) != NULL;
00324     }
00325 
00326     const std::type_info& type_info() const
00327         { return interface_ref().type_info(); }
00328 
00329     template <typename T> const T& cast() const
00330     {
00331         if (type_info() != typeid(T))
00332             throw bad_cast(type_info(), typeid(T));
00333         return *static_cast<const T*>(interface_ref().cast());
00334     }
00335 
00336     template <typename T> T& cast()
00337     {
00338         if (type_info() != typeid(T))
00339             throw bad_cast(type_info(), typeid(T));
00340         return *static_cast<T*>(interface_ref().cast());
00341     }
00342 
00343     template <typename T> bool cast(T& x) const
00344     {
00345         if (type_info() != typeid(T))
00346             return false;
00347         x = cast<T>();
00348         return true;
00349     }
00350 
00351 #ifndef NO_ASL_AI_CONCEPT_CHECK
00352     template <typename T> poly_base& assign(const T& x)
00353     {
00354         if (type_info() == typeid(T))
00355             cast<T>() = x;
00356         else
00357         {
00358             poly_base tmp(x);
00359             swap(*this, tmp);
00360         }
00361         return *this;
00362     }
00363 
00364         // Assign from related (may throw if downcastisng)
00365     template <typename J, template <typename> class K>
00366     typename boost::enable_if<is_base_derived_or_same<I, J> >::type
00367     assign(const poly_base<J, K>& x)
00368     {
00369         if(boost::is_base_of<J, I>::value)
00370             dynamic_cast<I&>(static_cast<J&>(*x.interface_ptr())); //make sure type safe
00371         interface_ref().~interface_type();
00372         x.interface_ref().clone(storage());
00373     }
00374 #endif
00375 
00376     const interface_type* operator->() const
00377     { return &interface_ref(); }
00378 
00379     interface_type* operator->()
00380     { return &interface_ref(); }
00381 
00382     interface_type& interface_ref()
00383     { return *static_cast<interface_type*>(storage()); }
00384 
00385     const interface_type& interface_ref() const
00386     { return *static_cast<const interface_type *>(storage()); }
00387 
00388     void* storage() { return &data_m; }
00389     const void* storage() const { return &data_m; }
00390 
00391     implementation::storage_t data_m;
00392 
00393 };
00394 
00395 template <class J, template <typename> class K>
00396 inline typename boost::enable_if<implementation::has_equals<J>, bool>::type
00397 operator==(const poly_base<J, K>& x, const poly_base<J, K>& y)
00398 { return x.interface_ref().equals(y.interface_ref()); }
00399 
00400 
00401 /*************************************************************************************************/
00402 
00413 template <class F>
00414 class poly : public F
00415 {
00416 public:
00422     template <typename T>
00423     explicit poly(const T& x) : F(x) {}
00424 
00425     poly(move_from<poly> x) : F(move_from<F>(x.source)) {}
00426 
00427     poly& operator=(poly x) { static_cast<F&>(*this) = adobe::move(static_cast<F&>(x)); return *this; }
00428 
00429     poly() : F() {}
00430 };
00431 
00432 /*************************************************************************************************/
00433 
00448 template <typename T, typename U>
00449 T poly_cast(poly<U>& x)
00450 {
00451     typedef typename boost::remove_reference<T>::type target_type;
00452     typedef typename target_type::interface_type target_interface_type;
00453     if(!x.template is_dynamic_convertible_to<target_interface_type>())
00454         throw bad_cast(typeid(poly<U>), typeid(T));
00455     return reinterpret_cast<T>(x);
00456 }
00457 
00458 /*************************************************************************************************/
00459 
00467 template <typename T, typename U>
00468 T poly_cast(const poly<U>& x)
00469 {
00470     typedef typename boost::remove_reference<T>::type target_type;
00471     typedef typename target_type::interface_type target_interface_type;
00472     if(!x.template is_dynamic_convertible_to<target_interface_type>())
00473         throw bad_cast(typeid(poly<U>), typeid(T));
00474     return reinterpret_cast<T>(x);
00475 }
00476 
00477 /*************************************************************************************************/
00478 
00494 template <typename T, typename U>
00495 T poly_cast(poly<U>* x)
00496 {
00497     typedef typename boost::remove_pointer<T>::type target_type;
00498     typedef typename target_type::interface_type target_interface_type;
00499     return x->template is_dynamic_convertible_to<target_interface_type>()
00500         ? reinterpret_cast<T>(x)
00501         : NULL;
00502 }
00503 
00504 /*************************************************************************************************/
00505 
00514 template <typename T, typename U>
00515 T poly_cast(const poly<U>* x)
00516 {
00517     typedef typename boost::remove_pointer<T>::type target_type;
00518     typedef typename target_type::interface_type target_interface_type;
00519     return x->template is_dynamic_convertible_to<target_interface_type>()
00520         ? reinterpret_cast<T>(x)
00521         : NULL;
00522 }
00523 
00524 /*************************************************************************************************/
00525 
00533 template <class T>
00534 inline bool operator!=(const poly<T>& x, const poly<T>& y)
00535 {
00536     return !(x == y);
00537 }
00538 
00539 
00541 
00542 /*************************************************************************************************/
00543 
00544 } // namespace adobe
00545 
00546 /*************************************************************************************************/
00547 
00548 #endif
00549 
00550 /*************************************************************************************************/

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