00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
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
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
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
00109 delete (*reinterpret_cast<T**>(x));
00110 }
00111 static void destruct(void** x)
00112 {
00113
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
00156
00157
00158
00159
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
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
00201 hold_any& assign(hold_any const& x)
00202 {
00203 if (&x != this) {
00204
00205 if (table == x.table) {
00206
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
00222 saga::detail::internals::fxn_ptr_table* x_table =
00223 saga::detail::internals::get_table<T>::get();
00224 if (table == x_table) {
00225
00226 table->destruct(&object);
00227 if (saga::detail::internals::get_table<T>::is_small::value) {
00228
00229 new (&object) T(x);
00230 }
00231 else {
00232
00233 new (object) T(x);
00234 }
00235 }
00236 else {
00237 if (saga::detail::internals::get_table<T>::is_small::value) {
00238
00239 table->destruct(&object);
00240 new (&object) T(x);
00241 }
00242 else {
00243 reset();
00244 object = new T(x);
00245 }
00246 table = x_table;
00247 }
00248 return *this;
00249 }
00250
00251 template <typename T>
00252 hold_any& init()
00253 {
00254
00255 saga::detail::internals::fxn_ptr_table* x_table =
00256 saga::detail::internals::get_table<T>::get();
00257 if (table == x_table) {
00258
00259 table->destruct(&object);
00260 if (saga::detail::internals::get_table<T>::is_small::value) {
00261
00262 create_default<T>::call(&object);
00263 }
00264 else {
00265
00266 create_default<T>::call(object);
00267 }
00268 }
00269 else {
00270 if (saga::detail::internals::get_table<T>::is_small::value) {
00271
00272 table->destruct(&object);
00273 create_default<T>::call(&object);
00274 }
00275 else {
00276 reset();
00277 object = create_default<T>::call();
00278 }
00279 table = x_table;
00280 }
00281 return *this;
00282 }
00283
00284
00285 template <typename T>
00286 hold_any& operator=(T const& x)
00287 {
00288 return assign(x);
00289 }
00290
00291
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
00316 #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
00317
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:
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:
00347 #endif
00348
00349 saga::detail::internals::fxn_ptr_table* table;
00350 void* object;
00351 };
00352
00353
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
00404
00405
00406
00407
00408
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
00425
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