Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:47:51

0001 /*=============================================================================
0002     Copyright (c) 2007-2011 Hartmut Kaiser
0003     Copyright (c) Christopher Diggins 2005
0004     Copyright (c) Pablo Aguilar 2005
0005     Copyright (c) Kevlin Henney 2001
0006 
0007     Distributed under the Boost Software License, Version 1.0. (See accompanying
0008     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010     The class boost::spirit::hold_any is built based on the any class
0011     published here: http://www.codeproject.com/cpp/dynamic_typing.asp. It adds
0012     support for std streaming operator<<() and operator>>().
0013 ==============================================================================*/
0014 #if !defined(BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM)
0015 #define BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM
0016 
0017 #if defined(_MSC_VER)
0018 #pragma once
0019 #endif
0020 
0021 #include <boost/config.hpp>
0022 #include <boost/type_traits/remove_reference.hpp>
0023 #include <boost/type_traits/is_reference.hpp>
0024 #include <boost/throw_exception.hpp>
0025 #include <boost/static_assert.hpp>
0026 #include <boost/mpl/bool.hpp>
0027 #include <boost/assert.hpp>
0028 #include <boost/core/typeinfo.hpp>
0029 
0030 #include <algorithm>
0031 #include <iosfwd>
0032 #include <stdexcept>
0033 #include <typeinfo>
0034 
0035 ///////////////////////////////////////////////////////////////////////////////
0036 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0037 # pragma warning(push)
0038 # pragma warning(disable: 4100)   // 'x': unreferenced formal parameter
0039 # pragma warning(disable: 4127)   // conditional expression is constant
0040 #endif
0041 
0042 ///////////////////////////////////////////////////////////////////////////////
0043 namespace boost { namespace spirit
0044 {
0045     struct bad_any_cast
0046       : std::bad_cast
0047     {
0048         bad_any_cast(boost::core::typeinfo const& src, boost::core::typeinfo const& dest)
0049           : from(src.name()), to(dest.name())
0050         {}
0051 
0052         const char* what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE
0053         { 
0054             return "bad any cast";
0055         }
0056 
0057         const char* from;
0058         const char* to;
0059     };
0060 
0061     namespace detail
0062     {
0063         // function pointer table
0064         template <typename Char>
0065         struct fxn_ptr_table
0066         {
0067             boost::core::typeinfo const& (*get_type)();
0068             void (*static_delete)(void**);
0069             void (*destruct)(void**);
0070             void (*clone)(void* const*, void**);
0071             void (*move)(void* const*, void**);
0072             std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**);
0073             std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, void* const*);
0074         };
0075 
0076         // static functions for small value-types
0077         template <typename Small>
0078         struct fxns;
0079 
0080         template <>
0081         struct fxns<mpl::true_>
0082         {
0083             template<typename T, typename Char>
0084             struct type
0085             {
0086                 static boost::core::typeinfo const& get_type()
0087                 {
0088                     return BOOST_CORE_TYPEID(T);
0089                 }
0090                 static void static_delete(void** x)
0091                 {
0092                     reinterpret_cast<T*>(x)->~T();
0093                 }
0094                 static void destruct(void** x)
0095                 {
0096                     reinterpret_cast<T*>(x)->~T();
0097                 }
0098                 static void clone(void* const* src, void** dest)
0099                 {
0100                     new (dest) T(*reinterpret_cast<T const*>(src));
0101                 }
0102                 static void move(void* const* src, void** dest)
0103                 {
0104                     *reinterpret_cast<T*>(dest) =
0105                         *reinterpret_cast<T const*>(src);
0106                 }
0107                 static std::basic_istream<Char>&
0108                 stream_in (std::basic_istream<Char>& i, void** obj)
0109                 {
0110                     i >> *reinterpret_cast<T*>(obj);
0111                     return i;
0112                 }
0113                 static std::basic_ostream<Char>&
0114                 stream_out(std::basic_ostream<Char>& o, void* const* obj)
0115                 {
0116                     o << *reinterpret_cast<T const*>(obj);
0117                     return o;
0118                 }
0119             };
0120         };
0121 
0122         // static functions for big value-types (bigger than a void*)
0123         template <>
0124         struct fxns<mpl::false_>
0125         {
0126             template<typename T, typename Char>
0127             struct type
0128             {
0129                 static boost::core::typeinfo const& get_type()
0130                 {
0131                     return BOOST_CORE_TYPEID(T);
0132                 }
0133                 static void static_delete(void** x)
0134                 {
0135                     // destruct and free memory
0136                     delete static_cast<T*>(*x);
0137                 }
0138                 static void destruct(void** x)
0139                 {
0140                     // destruct only, we'll reuse memory
0141                     static_cast<T*>(*x)->~T();
0142                 }
0143                 static void clone(void* const* src, void** dest)
0144                 {
0145                     *dest = new T(*static_cast<T const*>(*src));
0146                 }
0147                 static void move(void* const* src, void** dest)
0148                 {
0149                     *static_cast<T*>(*dest) =
0150                         *static_cast<T const*>(*src);
0151                 }
0152                 static std::basic_istream<Char>&
0153                 stream_in(std::basic_istream<Char>& i, void** obj)
0154                 {
0155                     i >> *static_cast<T*>(*obj);
0156                     return i;
0157                 }
0158                 static std::basic_ostream<Char>&
0159                 stream_out(std::basic_ostream<Char>& o, void* const* obj)
0160                 {
0161                     o << *static_cast<T const*>(*obj);
0162                     return o;
0163                 }
0164             };
0165         };
0166 
0167         template <typename T>
0168         struct get_table
0169         {
0170             typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
0171 
0172             template <typename Char>
0173             static fxn_ptr_table<Char>* get()
0174             {
0175                 static fxn_ptr_table<Char> static_table =
0176                 {
0177                     fxns<is_small>::template type<T, Char>::get_type,
0178                     fxns<is_small>::template type<T, Char>::static_delete,
0179                     fxns<is_small>::template type<T, Char>::destruct,
0180                     fxns<is_small>::template type<T, Char>::clone,
0181                     fxns<is_small>::template type<T, Char>::move,
0182                     fxns<is_small>::template type<T, Char>::stream_in,
0183                     fxns<is_small>::template type<T, Char>::stream_out
0184                 };
0185                 return &static_table;
0186             }
0187         };
0188 
0189         ///////////////////////////////////////////////////////////////////////
0190         struct empty {};
0191 
0192         template <typename Char>
0193         inline std::basic_istream<Char>&
0194         operator>> (std::basic_istream<Char>& i, empty&)
0195         {
0196             // If this assertion fires you tried to insert from a std istream
0197             // into an empty hold_any instance. This simply can't work, because
0198             // there is no way to figure out what type to extract from the
0199             // stream.
0200             // The only way to make this work is to assign an arbitrary
0201             // value of the required type to the hold_any instance you want to
0202             // stream to. This assignment has to be executed before the actual
0203             // call to the operator>>().
0204             BOOST_ASSERT(false &&
0205                 "Tried to insert from a std istream into an empty "
0206                 "hold_any instance");
0207             return i;
0208         }
0209 
0210         template <typename Char>
0211         inline std::basic_ostream<Char>&
0212         operator<< (std::basic_ostream<Char>& o, empty const&)
0213         {
0214             return o;
0215         }
0216     }
0217 
0218     ///////////////////////////////////////////////////////////////////////////
0219     template <typename Char>
0220     class basic_hold_any
0221     {
0222     public:
0223         // constructors
0224         template <typename T>
0225         explicit basic_hold_any(T const& x)
0226           : table(spirit::detail::get_table<T>::template get<Char>()), object(0)
0227         {
0228             new_object(object, x,
0229                 typename spirit::detail::get_table<T>::is_small());
0230         }
0231 
0232         basic_hold_any()
0233           : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
0234             object(0)
0235         {
0236         }
0237 
0238         basic_hold_any(basic_hold_any const& x)
0239           : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
0240             object(0)
0241         {
0242             assign(x);
0243         }
0244 
0245         ~basic_hold_any()
0246         {
0247             table->static_delete(&object);
0248         }
0249 
0250         // assignment
0251         basic_hold_any& assign(basic_hold_any const& x)
0252         {
0253             if (&x != this) {
0254                 // are we copying between the same type?
0255                 if (table == x.table) {
0256                     // if so, we can avoid reallocation
0257                     table->move(&x.object, &object);
0258                 }
0259                 else {
0260                     reset();
0261                     x.table->clone(&x.object, &object);
0262                     table = x.table;
0263                 }
0264             }
0265             return *this;
0266         }
0267 
0268         template <typename T>
0269         basic_hold_any& assign(T const& x)
0270         {
0271             // are we copying between the same type?
0272             spirit::detail::fxn_ptr_table<Char>* x_table =
0273                 spirit::detail::get_table<T>::template get<Char>();
0274             if (table == x_table) {
0275             // if so, we can avoid deallocating and re-use memory
0276                 table->destruct(&object);    // first destruct the old content
0277                 if (spirit::detail::get_table<T>::is_small::value) {
0278                     // create copy on-top of object pointer itself
0279                     new (&object) T(x);
0280                 }
0281                 else {
0282                     // create copy on-top of old version
0283                     new (object) T(x);
0284                 }
0285             }
0286             else {
0287                 if (spirit::detail::get_table<T>::is_small::value) {
0288                     // create copy on-top of object pointer itself
0289                     table->destruct(&object); // first destruct the old content
0290                     new (&object) T(x);
0291                 }
0292                 else {
0293                     reset();                  // first delete the old content
0294                     object = new T(x);
0295                 }
0296                 table = x_table;      // update table pointer
0297             }
0298             return *this;
0299         }
0300 
0301         template <typename T>
0302         static void new_object(void*& object, T const& x, mpl::true_)
0303         {
0304             new (&object) T(x);
0305         }
0306 
0307         template <typename T>
0308         static void new_object(void*& object, T const& x, mpl::false_)
0309         {
0310             object = new T(x);
0311         }
0312 
0313         // assignment operator
0314 #ifdef BOOST_HAS_RVALUE_REFS
0315         template <typename T>
0316         basic_hold_any& operator=(T&& x)
0317         {
0318             return assign(std::forward<T>(x));
0319         }
0320 #else
0321         template <typename T>
0322         basic_hold_any& operator=(T& x)
0323         {
0324             return assign(x);
0325         }
0326 
0327         template <typename T>
0328         basic_hold_any& operator=(T const& x)
0329         {
0330             return assign(x);
0331         }
0332 #endif
0333         // copy assignment operator
0334         basic_hold_any& operator=(basic_hold_any const& x)
0335         {
0336             return assign(x);
0337         }
0338 
0339         // utility functions
0340         basic_hold_any& swap(basic_hold_any& x)
0341         {
0342             std::swap(table, x.table);
0343             std::swap(object, x.object);
0344             return *this;
0345         }
0346 
0347         boost::core::typeinfo const& type() const
0348         {
0349             return table->get_type();
0350         }
0351 
0352         template <typename T>
0353         T const& cast() const
0354         {
0355             if (type() != BOOST_CORE_TYPEID(T))
0356               throw bad_any_cast(type(), BOOST_CORE_TYPEID(T));
0357 
0358             return spirit::detail::get_table<T>::is_small::value ?
0359                 *reinterpret_cast<T const*>(&object) :
0360                 *reinterpret_cast<T const*>(object);
0361         }
0362 
0363 // implicit casting is disabled by default for compatibility with boost::any
0364 #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
0365         // automatic casting operator
0366         template <typename T>
0367         operator T const& () const { return cast<T>(); }
0368 #endif // implicit casting
0369 
0370         bool empty() const
0371         {
0372             return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
0373         }
0374 
0375         void reset()
0376         {
0377             if (!empty())
0378             {
0379                 table->static_delete(&object);
0380                 table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
0381                 object = 0;
0382             }
0383         }
0384 
0385     // these functions have been added in the assumption that the embedded
0386     // type has a corresponding operator defined, which is completely safe
0387     // because spirit::hold_any is used only in contexts where these operators
0388     // do exist
0389         template <typename Char_>
0390         friend inline std::basic_istream<Char_>&
0391         operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
0392         {
0393             return obj.table->stream_in(i, &obj.object);
0394         }
0395 
0396         template <typename Char_>
0397         friend inline std::basic_ostream<Char_>&
0398         operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
0399         {
0400             return obj.table->stream_out(o, &obj.object);
0401         }
0402 
0403 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
0404     private: // types
0405         template <typename T, typename Char_>
0406         friend T* any_cast(basic_hold_any<Char_> *);
0407 #else
0408     public: // types (public so any_cast can be non-friend)
0409 #endif
0410         // fields
0411         spirit::detail::fxn_ptr_table<Char>* table;
0412         void* object;
0413     };
0414 
0415     // boost::any-like casting
0416     template <typename T, typename Char>
0417     inline T* any_cast (basic_hold_any<Char>* operand)
0418     {
0419         if (operand && operand->type() == BOOST_CORE_TYPEID(T)) {
0420             return spirit::detail::get_table<T>::is_small::value ?
0421                 reinterpret_cast<T*>(&operand->object) :
0422                 reinterpret_cast<T*>(operand->object);
0423         }
0424         return 0;
0425     }
0426 
0427     template <typename T, typename Char>
0428     inline T const* any_cast(basic_hold_any<Char> const* operand)
0429     {
0430         return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
0431     }
0432 
0433     template <typename T, typename Char>
0434     T any_cast(basic_hold_any<Char>& operand)
0435     {
0436         typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
0437 
0438 
0439         nonref* result = any_cast<nonref>(&operand);
0440         if(!result)
0441             boost::throw_exception(bad_any_cast(operand.type(), BOOST_CORE_TYPEID(T)));
0442         return *result;
0443     }
0444 
0445     template <typename T, typename Char>
0446     T const& any_cast(basic_hold_any<Char> const& operand)
0447     {
0448         typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
0449 
0450 
0451         return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
0452     }
0453 
0454     ///////////////////////////////////////////////////////////////////////////////
0455     // backwards compatibility
0456     typedef basic_hold_any<char> hold_any;
0457     typedef basic_hold_any<wchar_t> whold_any;
0458 
0459     namespace traits
0460     {
0461         template <typename T>
0462         struct is_hold_any : mpl::false_ {};
0463 
0464         template <typename Char>
0465         struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
0466     }
0467 
0468 }}    // namespace boost::spirit
0469 
0470 ///////////////////////////////////////////////////////////////////////////////
0471 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0472 # pragma warning(pop)
0473 #endif
0474 
0475 #endif