- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- Search for |

# hold_any.hpp

Go to the documentation of this file.

    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