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 /*************************************************************************************************/ |