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 class hold_any
00156 {
00157 public:
00158
00159 template <typename T>
00160 hold_any(T const& x)
00161 : table(detail::internals::get_table<T>::get()), object(0)
00162 {
00163 if (detail::internals::get_table<T>::is_small::value)
00164 new (&object) T(x);
00165 else
00166 object = new T(x);
00167 }
00168
00169 hold_any()
00170 : table(detail::internals::get_table<detail::internals::empty>::get()),
00171 object(0)
00172 {
00173 }
00174
00175 hold_any(hold_any const& x)
00176 : table(detail::internals::get_table<detail::internals::empty>::get()),
00177 object(0)
00178 {
00179 assign(x);
00180 }
00181
00182 ~hold_any()
00183 {
00184 table->static_delete(&object);
00185 }
00186
00187
00188 hold_any& assign(hold_any const& x)
00189 {
00190 if (&x != this) {
00191
00192 if (table == x.table) {
00193
00194 table->move(&x.object, &object);
00195 }
00196 else {
00197 reset();
00198 x.table->clone(&x.object, &object);
00199 table = x.table;
00200 }
00201 }
00202 return *this;
00203 }
00204
00205 template <typename T>
00206 hold_any& assign(T const& x)
00207 {
00208
00209 detail::internals::fxn_ptr_table* x_table =
00210 detail::internals::get_table<T>::get();
00211 if (table == x_table) {
00212
00213 table->destruct(&object);
00214 if (detail::internals::get_table<T>::is_small::value) {
00215
00216 new (&object) T(x);
00217 }
00218 else {
00219
00220 new (object) T(x);
00221 }
00222 }
00223 else {
00224 if (detail::internals::get_table<T>::is_small::value) {
00225
00226 table->destruct(&object);
00227 new (&object) T(x);
00228 }
00229 else {
00230 reset();
00231 object = new T(x);
00232 }
00233 table = x_table;
00234 }
00235 return *this;
00236 }
00237
00238 template <typename T>
00239 hold_any& init()
00240 {
00241
00242 detail::internals::fxn_ptr_table* x_table =
00243 detail::internals::get_table<T>::get();
00244 if (table == x_table) {
00245
00246 table->destruct(&object);
00247 if (detail::internals::get_table<T>::is_small::value) {
00248
00249 new (&object) T;
00250 }
00251 else {
00252
00253 new (object) T;
00254 }
00255 }
00256 else {
00257 if (detail::internals::get_table<T>::is_small::value) {
00258
00259 table->destruct(&object);
00260 new (&object) T;
00261 }
00262 else {
00263 reset();
00264 object = new T;
00265 }
00266 table = x_table;
00267 }
00268 return *this;
00269 }
00270
00271
00272 template <typename T>
00273 hold_any& operator=(T const& x)
00274 {
00275 return assign(x);
00276 }
00277
00278
00279 hold_any& swap(hold_any& x)
00280 {
00281 std::swap(table, x.table);
00282 std::swap(object, x.object);
00283 return *this;
00284 }
00285
00286 std::type_info const& type() const
00287 {
00288 return table->get_type();
00289 }
00290
00291 template <typename T>
00292 T const& cast() const
00293 {
00294 if (type() != typeid(T))
00295 throw bad_any_cast(type(), typeid(T));
00296
00297 return detail::internals::get_table<T>::is_small::value ?
00298 *reinterpret_cast<T const*>(&object) :
00299 *reinterpret_cast<T const*>(object);
00300 }
00301
00302
00303 #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
00304
00305 template <typename T>
00306 operator T const& () const { return cast<T>(); }
00307 #endif // implicit casting
00308
00309 bool empty() const
00310 {
00311 return 0 == object;
00312 }
00313
00314 void reset()
00315 {
00316 if (!empty())
00317 {
00318 table->static_delete(&object);
00319 table = detail::internals::get_table<detail::internals::empty>::get();
00320 object = 0;
00321 }
00322 }
00323
00324 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
00325 private:
00326 template<typename T>
00327 friend T* any_cast(hold_any *);
00328 template<typename T>
00329 friend T* any_cast(hold_any *, boost::mpl::true_);
00330 template<typename T>
00331 friend T* any_cast(hold_any *, boost::mpl::false_);
00332 #else
00333 public:
00334 #endif
00335
00336 detail::internals::fxn_ptr_table* table;
00337 void* object;
00338 };
00339
00340
00341 template <typename T>
00342 inline T* any_cast (hold_any* operand, boost::mpl::true_)
00343 {
00344 if (operand && operand->type() == typeid(T)) {
00345 BOOST_STATIC_ASSERT(sizeof(std::size_t) >= sizeof(void*));
00346 return detail::internals::get_table<T>::is_small::value ?
00347 reinterpret_cast<T*>(
00348 reinterpret_cast<std::size_t>(&operand->object)) :
00349 reinterpret_cast<T*>(operand->object);
00350 }
00351 return 0;
00352 }
00353
00354 template <typename T>
00355 inline T* any_cast (hold_any* operand, boost::mpl::false_)
00356 {
00357 if (operand) {
00358 if (operand->empty())
00359 operand->init<T>();
00360
00361 if (operand->type() == typeid(T)) {
00362 BOOST_STATIC_ASSERT(sizeof(std::size_t) >= sizeof(void*));
00363 return detail::internals::get_table<T>::is_small::value ?
00364 reinterpret_cast<T*>(
00365 reinterpret_cast<std::size_t>(&operand->object)) :
00366 reinterpret_cast<T*>(operand->object);
00367 }
00368 }
00369 return 0;
00370 }
00371
00372 template <typename T>
00373 inline T* any_cast (hold_any* operand)
00374 {
00375 return any_cast<T>(operand, boost::mpl::bool_<boost::is_const<T>::value>());
00376 }
00377
00378 template <typename T>
00379 inline T const* any_cast(hold_any const* operand)
00380 {
00381 return any_cast<T>(const_cast<hold_any*>(operand));
00382 }
00383
00384 template <typename T>
00385 T any_cast(hold_any& operand)
00386 {
00387 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref;
00388
00389 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
00390
00391
00392
00393
00394
00395
00396 BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
00397 #endif
00398
00399 nonref* result = any_cast<nonref>(&operand);
00400 if(!result)
00401 boost::throw_exception(bad_any_cast(operand.type(), typeid(T)));
00402 return *result;
00403 }
00404
00405 template <typename T>
00406 T const& any_cast(hold_any const& operand)
00407 {
00408 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type nonref;
00409
00410 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
00411
00412
00413 BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
00414 #endif
00415
00416 return any_cast<nonref const&>(const_cast<hold_any &>(operand));
00417 }
00418
00419 }}
00420
00422
00423 #endif
00424