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