SAGA Adaptor CPI v.1.0
|
00001 // Copyright (c) 2007-2009 Hartmut Kaiser 00002 // Copyright (c) Christopher Diggins 2005 00003 // Copyright (c) Pablo Aguilar 2005 00004 // Copyright (c) Kevlin Henney 2001 00005 // 00006 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00007 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00008 // 00009 // The class saga::detail::hold_any is built based on the any class 00010 // published here: http://www.codeproject.com/cpp/dynamic_typing.asp. 00011 00012 #if !defined(SAGA_HOLD_ANY_DEC_01_2007_0133PM) 00013 #define SAGA_HOLD_ANY_DEC_01_2007_0133PM 00014 00015 #include <boost/config.hpp> 00016 #include <boost/type_traits/remove_reference.hpp> 00017 #include <boost/type_traits/is_reference.hpp> 00018 #include <boost/throw_exception.hpp> 00019 #include <boost/static_assert.hpp> 00020 #include <boost/mpl/bool.hpp> 00021 #include <boost/assert.hpp> 00022 #include <boost/static_assert.hpp> 00023 #include <boost/type_traits/is_const.hpp> 00024 00025 #include <stdexcept> 00026 #include <typeinfo> 00027 #include <algorithm> 00028 00031 00032 namespace saga { namespace detail 00033 { 00034 struct bad_any_cast 00035 : std::bad_cast 00036 { 00037 bad_any_cast(std::type_info const& src, std::type_info const& dest) 00038 : from(src.name()), to(dest.name()) 00039 {} 00040 00041 virtual const char* what() const throw() { return "bad any cast"; } 00042 00043 const char* from; 00044 const char* to; 00045 }; 00046 00048 namespace internals 00049 { 00050 // function pointer table 00051 struct fxn_ptr_table 00052 { 00053 std::type_info const& (*get_type)(); 00054 void (*static_delete)(void**); 00055 void (*destruct)(void**); 00056 void (*clone)(void* const*, void**); 00057 void (*move)(void* const*, void**); 00058 }; 00059 00060 // static functions for small value-types 00061 template<typename Small> 00062 struct fxns; 00063 00064 template<> 00065 struct fxns<boost::mpl::true_> 00066 { 00067 template<typename T> 00068 struct type 00069 { 00070 static std::type_info const& get_type() 00071 { 00072 return typeid(T); 00073 } 00074 static void static_delete(void** x) 00075 { 00076 reinterpret_cast<T*>(x)->~T(); 00077 } 00078 static void destruct(void** x) 00079 { 00080 reinterpret_cast<T*>(x)->~T(); 00081 } 00082 static void clone(void* const* src, void** dest) 00083 { 00084 new (dest) T(*reinterpret_cast<T const*>(src)); 00085 } 00086 static void move(void* const* src, void** dest) 00087 { 00088 reinterpret_cast<T*>(dest)->~T(); 00089 *reinterpret_cast<T*>(dest) = 00090 *reinterpret_cast<T const*>(src); 00091 } 00092 }; 00093 }; 00094 00095 // static functions for big value-types (bigger than a void*) 00096 template<> 00097 struct fxns<boost::mpl::false_> 00098 { 00099 template<typename T> 00100 struct type 00101 { 00102 static std::type_info const& get_type() 00103 { 00104 return typeid(T); 00105 } 00106 static void static_delete(void** x) 00107 { 00108 // destruct and free memory 00109 delete (*reinterpret_cast<T**>(x)); 00110 } 00111 static void destruct(void** x) 00112 { 00113 // destruct only, we'll reuse memory 00114 (*reinterpret_cast<T**>(x))->~T(); 00115 } 00116 static void clone(void* const* src, void** dest) 00117 { 00118 *dest = new T(**reinterpret_cast<T* const*>(src)); 00119 } 00120 static void move(void* const* src, void** dest) 00121 { 00122 (*reinterpret_cast<T**>(dest))->~T(); 00123 **reinterpret_cast<T**>(dest) = 00124 **reinterpret_cast<T* const*>(src); 00125 } 00126 }; 00127 }; 00128 00129 template<typename T> 00130 struct get_table 00131 { 00132 typedef boost::mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small; 00133 00134 static fxn_ptr_table* get() 00135 { 00136 static fxn_ptr_table static_table = 00137 { 00138 fxns<is_small>::template type<T>::get_type, 00139 fxns<is_small>::template type<T>::static_delete, 00140 fxns<is_small>::template type<T>::destruct, 00141 fxns<is_small>::template type<T>::clone, 00142 fxns<is_small>::template type<T>::move 00143 }; 00144 return &static_table; 00145 } 00146 }; 00147 00149 struct empty {}; 00150 00151 } 00153 00155 // We need to be able to default construct any type stored in a hold_any 00156 // Some of the saga API objects do have a default constructor doing more 00157 // than just creating an empty API (facade object), which is evil. So we 00158 // use the create_default template. This template is specialized for those 00159 // picky types elsewhere. 00160 template <typename T> 00161 struct create_default 00162 { 00163 static T* call() { return new T; } 00164 template <typename T_> static void call(T_* obj) { new (obj) T; } 00165 }; 00166 00168 class hold_any 00169 { 00170 public: 00171 // constructors 00172 template <typename T> 00173 hold_any(T const& x) 00174 : table(saga::detail::internals::get_table<T>::get()), object(0) 00175 { 00176 if (saga::detail::internals::get_table<T>::is_small::value) 00177 new (&object) T(x); 00178 else 00179 object = new T(x); 00180 } 00181 00182 hold_any() 00183 : table(saga::detail::internals::get_table<saga::detail::internals::empty>::get()), 00184 object(0) 00185 { 00186 } 00187 00188 hold_any(hold_any const& x) 00189 : table(saga::detail::internals::get_table<saga::detail::internals::empty>::get()), 00190 object(0) 00191 { 00192 assign(x); 00193 } 00194 00195 ~hold_any() 00196 { 00197 table->static_delete(&object); 00198 } 00199 00200 // assignment 00201 hold_any& assign(hold_any const& x) 00202 { 00203 if (&x != this) { 00204 // are we copying between the same type? 00205 if (table == x.table) { 00206 // if so, we can avoid reallocation 00207 table->move(&x.object, &object); 00208 } 00209 else { 00210 reset(); 00211 x.table->clone(&x.object, &object); 00212 table = x.table; 00213 } 00214 } 00215 return *this; 00216 } 00217 00218 template <typename T> 00219 hold_any& assign(T const& x) 00220 { 00221 // are we copying between the same type? 00222 saga::detail::internals::fxn_ptr_table* x_table = 00223 saga::detail::internals::get_table<T>::get(); 00224 if (table == x_table) { 00225 // if so, we can avoid deallocating and re-use memory 00226 table->destruct(&object); // first destruct the old content 00227 if (saga::detail::internals::get_table<T>::is_small::value) { 00228 // create copy on-top of object pointer itself 00229 new (&object) T(x); 00230 } 00231 else { 00232 // create copy on-top of old version 00233 new (object) T(x); 00234 } 00235 } 00236 else { 00237 if (saga::detail::internals::get_table<T>::is_small::value) { 00238 // create copy on-top of object pointer itself 00239 table->destruct(&object); // first destruct the old content 00240 new (&object) T(x); 00241 } 00242 else { 00243 reset(); // first delete the old content 00244 object = new T(x); 00245 } 00246 table = x_table; // update table pointer 00247 } 00248 return *this; 00249 } 00250 00251 template <typename T> 00252 hold_any& init() 00253 { 00254 // are we copying between the same type? 00255 saga::detail::internals::fxn_ptr_table* x_table = 00256 saga::detail::internals::get_table<T>::get(); 00257 if (table == x_table) { 00258 // if so, we can avoid deallocating and re-use memory 00259 table->destruct(&object); // first destruct the old content 00260 if (saga::detail::internals::get_table<T>::is_small::value) { 00261 // create copy on-top of object pointer itself 00262 create_default<T>::call(&object); 00263 } 00264 else { 00265 // create copy on-top of old version 00266 create_default<T>::call(object); 00267 } 00268 } 00269 else { 00270 if (saga::detail::internals::get_table<T>::is_small::value) { 00271 // create copy on-top of object pointer itself 00272 table->destruct(&object); // first destruct the old content 00273 create_default<T>::call(&object); 00274 } 00275 else { 00276 reset(); // first delete the old content 00277 object = create_default<T>::call(); 00278 } 00279 table = x_table; // update table pointer 00280 } 00281 return *this; 00282 } 00283 00284 // assignment operator 00285 template <typename T> 00286 hold_any& operator=(T const& x) 00287 { 00288 return assign(x); 00289 } 00290 00291 // utility functions 00292 hold_any& swap(hold_any& x) 00293 { 00294 std::swap(table, x.table); 00295 std::swap(object, x.object); 00296 return *this; 00297 } 00298 00299 std::type_info const& type() const 00300 { 00301 return table->get_type(); 00302 } 00303 00304 template <typename T> 00305 T const& cast() const 00306 { 00307 if (type() != typeid(T)) 00308 throw bad_any_cast(type(), typeid(T)); 00309 00310 return saga::detail::internals::get_table<T>::is_small::value ? 00311 *reinterpret_cast<T const*>(&object) : 00312 *reinterpret_cast<T const*>(object); 00313 } 00314 00315 // implicit casting is disabled by default for compatibility with boost::any 00316 #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING 00317 // automatic casting operator 00318 template <typename T> 00319 operator T const& () const { return cast<T>(); } 00320 #endif // implicit casting 00321 00322 bool empty() const 00323 { 00324 return 0 == object; 00325 } 00326 00327 void reset() 00328 { 00329 if (!empty()) 00330 { 00331 table->static_delete(&object); 00332 table = saga::detail::internals::get_table<saga::detail::internals::empty>::get(); 00333 object = 0; 00334 } 00335 } 00336 00337 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 00338 private: // types 00339 template<typename T> 00340 friend T* any_cast(hold_any *); 00341 template<typename T> 00342 friend T* any_cast(hold_any *, boost::mpl::true_); 00343 template<typename T> 00344 friend T* any_cast(hold_any *, boost::mpl::false_); 00345 #else 00346 public: // types (public so any_cast can be non-friend) 00347 #endif 00348 // fields 00349 saga::detail::internals::fxn_ptr_table* table; 00350 void* object; 00351 }; 00352 00353 // boost::any-like casting 00354 template <typename T> 00355 inline T* any_cast (hold_any* operand, boost::mpl::true_) 00356 { 00357 if (operand && operand->type() == typeid(T)) { 00358 BOOST_STATIC_ASSERT(sizeof(std::size_t) >= sizeof(void*)); 00359 return saga::detail::internals::get_table<T>::is_small::value ? 00360 reinterpret_cast<T*>( 00361 reinterpret_cast<std::size_t>(&operand->object)) : 00362 reinterpret_cast<T*>(operand->object); 00363 } 00364 return 0; 00365 } 00366 00367 template <typename T> 00368 inline T* any_cast (hold_any* operand, boost::mpl::false_) 00369 { 00370 if (operand) { 00371 if (operand->empty()) 00372 operand->init<T>(); 00373 00374 if (operand->type() == typeid(T)) { 00375 BOOST_STATIC_ASSERT(sizeof(std::size_t) >= sizeof(void*)); 00376 return saga::detail::internals::get_table<T>::is_small::value ? 00377 reinterpret_cast<T*>( 00378 reinterpret_cast<std::size_t>(&operand->object)) : 00379 reinterpret_cast<T*>(operand->object); 00380 } 00381 } 00382 return 0; 00383 } 00384 00385 template <typename T> 00386 inline T* any_cast (hold_any* operand) 00387 { 00388 return any_cast<T>(operand, boost::mpl::bool_<boost::is_const<T>::value>()); 00389 } 00390 00391 template <typename T> 00392 inline T const* any_cast(hold_any const* operand) 00393 { 00394 return any_cast<T>(const_cast<hold_any*>(operand)); 00395 } 00396 00397 template <typename T> 00398 T any_cast(hold_any& operand) 00399 { 00400 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref; 00401 00402 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION 00403 // If 'nonref' is still reference type, it means the user has not 00404 // specialized 'remove_reference'. 00405 00406 // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro 00407 // to generate specialization of remove_reference for your class 00408 // See type traits library documentation for details 00409 BOOST_STATIC_ASSERT(!is_reference<nonref>::value); 00410 #endif 00411 00412 nonref* result = any_cast<nonref>(&operand); 00413 if(!result) 00414 boost::throw_exception(bad_any_cast(operand.type(), typeid(T))); 00415 return *result; 00416 } 00417 00418 template <typename T> 00419 T const& any_cast(hold_any const& operand) 00420 { 00421 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref; 00422 00423 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION 00424 // The comment in the above version of 'any_cast' explains when this 00425 // assert is fired and what to do. 00426 BOOST_STATIC_ASSERT(!is_reference<nonref>::value); 00427 #endif 00428 00429 return any_cast<nonref const&>(const_cast<hold_any &>(operand)); 00430 } 00431 00432 }} 00433 00435 00436 #endif 00437