PageRenderTime 88ms CodeModel.GetById 16ms app.highlight 60ms RepoModel.GetById 4ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/spirit/home/support/detail/hold_any.hpp

http://hadesmem.googlecode.com/
C++ Header | 459 lines | 352 code | 48 blank | 59 comment | 22 complexity | feda23fab9d3f5380eac00f92cbbc68e MD5 | raw file
  1/*=============================================================================
  2    Copyright (c) 2007-2011 Hartmut Kaiser
  3    Copyright (c) Christopher Diggins 2005
  4    Copyright (c) Pablo Aguilar 2005
  5    Copyright (c) Kevlin Henney 2001
  6
  7    Distributed under the Boost Software License, Version 1.0. (See accompanying
  8    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9
 10    The class boost::spirit::hold_any is built based on the any class
 11    published here: http://www.codeproject.com/cpp/dynamic_typing.asp. It adds
 12    support for std streaming operator<<() and operator>>().
 13==============================================================================*/
 14#if !defined(BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM)
 15#define BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM
 16
 17#if defined(_MSC_VER)
 18#pragma once
 19#endif
 20
 21#include <boost/config.hpp>
 22#include <boost/type_traits/remove_reference.hpp>
 23#include <boost/type_traits/is_reference.hpp>
 24#include <boost/throw_exception.hpp>
 25#include <boost/static_assert.hpp>
 26#include <boost/mpl/bool.hpp>
 27#include <boost/assert.hpp>
 28#include <boost/detail/sp_typeinfo.hpp>
 29
 30#include <stdexcept>
 31#include <typeinfo>
 32#include <algorithm>
 33#include <iosfwd>
 34
 35///////////////////////////////////////////////////////////////////////////////
 36#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
 37# pragma warning(push)
 38# pragma warning(disable: 4100)   // 'x': unreferenced formal parameter
 39# pragma warning(disable: 4127)   // conditional expression is constant
 40#endif
 41
 42///////////////////////////////////////////////////////////////////////////////
 43namespace boost { namespace spirit
 44{
 45    struct bad_any_cast
 46      : std::bad_cast
 47    {
 48        bad_any_cast(boost::detail::sp_typeinfo const& src, boost::detail::sp_typeinfo const& dest)
 49          : from(src.name()), to(dest.name())
 50        {}
 51
 52        virtual const char* what() const throw() { return "bad any cast"; }
 53
 54        const char* from;
 55        const char* to;
 56    };
 57
 58    namespace detail
 59    {
 60        // function pointer table
 61        template <typename Char>
 62        struct fxn_ptr_table
 63        {
 64            boost::detail::sp_typeinfo const& (*get_type)();
 65            void (*static_delete)(void**);
 66            void (*destruct)(void**);
 67            void (*clone)(void* const*, void**);
 68            void (*move)(void* const*, void**);
 69            std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**);
 70            std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, void* const*);
 71        };
 72
 73        // static functions for small value-types
 74        template <typename Small>
 75        struct fxns;
 76
 77        template <>
 78        struct fxns<mpl::true_>
 79        {
 80            template<typename T, typename Char>
 81            struct type
 82            {
 83                static boost::detail::sp_typeinfo const& get_type()
 84                {
 85                    return BOOST_SP_TYPEID(T);
 86                }
 87                static void static_delete(void** x)
 88                {
 89                    reinterpret_cast<T*>(x)->~T();
 90                }
 91                static void destruct(void** x)
 92                {
 93                    reinterpret_cast<T*>(x)->~T();
 94                }
 95                static void clone(void* const* src, void** dest)
 96                {
 97                    new (dest) T(*reinterpret_cast<T const*>(src));
 98                }
 99                static void move(void* const* src, void** dest)
100                {
101                    reinterpret_cast<T*>(dest)->~T();
102                    *reinterpret_cast<T*>(dest) =
103                        *reinterpret_cast<T const*>(src);
104                }
105                static std::basic_istream<Char>& 
106                stream_in (std::basic_istream<Char>& i, void** obj)
107                {
108                    i >> *reinterpret_cast<T*>(obj);
109                    return i;
110                }
111                static std::basic_ostream<Char>& 
112                stream_out(std::basic_ostream<Char>& o, void* const* obj)
113                {
114                    o << *reinterpret_cast<T const*>(obj);
115                    return o;
116                }
117            };
118        };
119
120        // static functions for big value-types (bigger than a void*)
121        template <>
122        struct fxns<mpl::false_>
123        {
124            template<typename T, typename Char>
125            struct type
126            {
127                static boost::detail::sp_typeinfo const& get_type()
128                {
129                    return BOOST_SP_TYPEID(T);
130                }
131                static void static_delete(void** x)
132                {
133                    // destruct and free memory
134                    delete (*reinterpret_cast<T**>(x));
135                }
136                static void destruct(void** x)
137                {
138                    // destruct only, we'll reuse memory
139                    (*reinterpret_cast<T**>(x))->~T();
140                }
141                static void clone(void* const* src, void** dest)
142                {
143                    *dest = new T(**reinterpret_cast<T* const*>(src));
144                }
145                static void move(void* const* src, void** dest)
146                {
147                    (*reinterpret_cast<T**>(dest))->~T();
148                    **reinterpret_cast<T**>(dest) =
149                        **reinterpret_cast<T* const*>(src);
150                }
151                static std::basic_istream<Char>& 
152                stream_in(std::basic_istream<Char>& i, void** obj)
153                {
154                    i >> **reinterpret_cast<T**>(obj);
155                    return i;
156                }
157                static std::basic_ostream<Char>& 
158                stream_out(std::basic_ostream<Char>& o, void* const* obj)
159                {
160                    o << **reinterpret_cast<T* const*>(obj);
161                    return o;
162                }
163            };
164        };
165
166        template <typename T>
167        struct get_table
168        {
169            typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
170
171            template <typename Char>
172            static fxn_ptr_table<Char>* get()
173            {
174                static fxn_ptr_table<Char> static_table =
175                {
176                    fxns<is_small>::template type<T, Char>::get_type,
177                    fxns<is_small>::template type<T, Char>::static_delete,
178                    fxns<is_small>::template type<T, Char>::destruct,
179                    fxns<is_small>::template type<T, Char>::clone,
180                    fxns<is_small>::template type<T, Char>::move,
181                    fxns<is_small>::template type<T, Char>::stream_in,
182                    fxns<is_small>::template type<T, Char>::stream_out
183                };
184                return &static_table;
185            }
186        };
187
188        ///////////////////////////////////////////////////////////////////////
189        struct empty {};
190
191        template <typename Char>
192        inline std::basic_istream<Char>&
193        operator>> (std::basic_istream<Char>& i, empty&)
194        {
195            // If this assertion fires you tried to insert from a std istream
196            // into an empty hold_any instance. This simply can't work, because
197            // there is no way to figure out what type to extract from the
198            // stream.
199            // The only way to make this work is to assign an arbitrary
200            // value of the required type to the hold_any instance you want to
201            // stream to. This assignment has to be executed before the actual
202            // call to the operator>>().
203            BOOST_ASSERT(false && 
204                "Tried to insert from a std istream into an empty "
205                "hold_any instance");
206            return i;
207        }
208
209        template <typename Char>
210        inline std::basic_ostream<Char>&
211        operator<< (std::basic_ostream<Char>& o, empty const&)
212        {
213            return o;
214        }
215    }
216
217    ///////////////////////////////////////////////////////////////////////////
218    template <typename Char>
219    class basic_hold_any
220    {
221    public:
222        // constructors
223        template <typename T>
224        explicit basic_hold_any(T const& x)
225          : table(spirit::detail::get_table<T>::template get<Char>()), object(0)
226        {
227            if (spirit::detail::get_table<T>::is_small::value)
228                new (&object) T(x);
229            else
230                object = new T(x);
231        }
232
233        basic_hold_any()
234          : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
235            object(0)
236        {
237        }
238
239        basic_hold_any(basic_hold_any const& x)
240          : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
241            object(0)
242        {
243            assign(x);
244        }
245
246        ~basic_hold_any()
247        {
248            table->static_delete(&object);
249        }
250
251        // assignment
252        basic_hold_any& assign(basic_hold_any const& x)
253        {
254            if (&x != this) {
255                // are we copying between the same type?
256                if (table == x.table) {
257                    // if so, we can avoid reallocation
258                    table->move(&x.object, &object);
259                }
260                else {
261                    reset();
262                    x.table->clone(&x.object, &object);
263                    table = x.table;
264                }
265            }
266            return *this;
267        }
268
269        template <typename T>
270        basic_hold_any& assign(T const& x)
271        {
272            // are we copying between the same type?
273            spirit::detail::fxn_ptr_table<Char>* x_table =
274                spirit::detail::get_table<T>::template get<Char>();
275            if (table == x_table) {
276            // if so, we can avoid deallocating and re-use memory
277                table->destruct(&object);    // first destruct the old content
278                if (spirit::detail::get_table<T>::is_small::value) {
279                    // create copy on-top of object pointer itself
280                    new (&object) T(x);
281                }
282                else {
283                    // create copy on-top of old version
284                    new (object) T(x);
285                }
286            }
287            else {
288                if (spirit::detail::get_table<T>::is_small::value) {
289                    // create copy on-top of object pointer itself
290                    table->destruct(&object); // first destruct the old content
291                    new (&object) T(x);
292                }
293                else {
294                    reset();                  // first delete the old content
295                    object = new T(x);
296                }
297                table = x_table;      // update table pointer
298            }
299            return *this;
300        }
301
302        // assignment operator
303        template <typename T>
304        basic_hold_any& operator=(T const& x)
305        {
306            return assign(x);
307        }
308
309        // utility functions
310        basic_hold_any& swap(basic_hold_any& x)
311        {
312            std::swap(table, x.table);
313            std::swap(object, x.object);
314            return *this;
315        }
316
317        boost::detail::sp_typeinfo const& type() const
318        {
319            return table->get_type();
320        }
321
322        template <typename T>
323        T const& cast() const
324        {
325            if (type() != BOOST_SP_TYPEID(T))
326              throw bad_any_cast(type(), BOOST_SP_TYPEID(T));
327
328            return spirit::detail::get_table<T>::is_small::value ?
329                *reinterpret_cast<T const*>(&object) :
330                *reinterpret_cast<T const*>(object);
331        }
332
333// implicit casting is disabled by default for compatibility with boost::any
334#ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
335        // automatic casting operator
336        template <typename T>
337        operator T const& () const { return cast<T>(); }
338#endif // implicit casting
339
340        bool empty() const
341        {
342            return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
343        }
344
345        void reset()
346        {
347            if (!empty())
348            {
349                table->static_delete(&object);
350                table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
351                object = 0;
352            }
353        }
354
355    // these functions have been added in the assumption that the embedded
356    // type has a corresponding operator defined, which is completely safe
357    // because spirit::hold_any is used only in contexts where these operators
358    // do exist
359        template <typename Char_>
360        friend inline std::basic_istream<Char_>& 
361        operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
362        {
363            return obj.table->stream_in(i, &obj.object);
364        }
365
366        template <typename Char_>
367        friend inline std::basic_ostream<Char_>& 
368        operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
369        {
370            return obj.table->stream_out(o, &obj.object);
371        }
372
373#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
374    private: // types
375        template <typename T, typename Char_>
376        friend T* any_cast(basic_hold_any<Char_> *);
377#else
378    public: // types (public so any_cast can be non-friend)
379#endif
380        // fields
381        spirit::detail::fxn_ptr_table<Char>* table;
382        void* object;
383    };
384
385    // boost::any-like casting
386    template <typename T, typename Char>
387    inline T* any_cast (basic_hold_any<Char>* operand)
388    {
389        if (operand && operand->type() == BOOST_SP_TYPEID(T)) {
390            return spirit::detail::get_table<T>::is_small::value ?
391                reinterpret_cast<T*>(&operand->object) :
392                reinterpret_cast<T*>(operand->object);
393        }
394        return 0;
395    }
396
397    template <typename T, typename Char>
398    inline T const* any_cast(basic_hold_any<Char> const* operand)
399    {
400        return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
401    }
402
403    template <typename T, typename Char>
404    T any_cast(basic_hold_any<Char>& operand)
405    {
406        typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
407
408#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
409        // If 'nonref' is still reference type, it means the user has not
410        // specialized 'remove_reference'.
411
412        // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
413        // to generate specialization of remove_reference for your class
414        // See type traits library documentation for details
415        BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
416#endif
417
418        nonref* result = any_cast<nonref>(&operand);
419        if(!result)
420            boost::throw_exception(bad_any_cast(operand.type(), BOOST_SP_TYPEID(T)));
421        return *result;
422    }
423
424    template <typename T, typename Char>
425    T const& any_cast(basic_hold_any<Char> const& operand)
426    {
427        typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
428
429#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
430        // The comment in the above version of 'any_cast' explains when this
431        // assert is fired and what to do.
432        BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
433#endif
434
435        return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
436    }
437
438    ///////////////////////////////////////////////////////////////////////////////
439    // backwards compatibility
440    typedef basic_hold_any<char> hold_any;
441    typedef basic_hold_any<wchar_t> whold_any;
442
443    namespace traits
444    {
445        template <typename T>
446        struct is_hold_any : mpl::false_ {};
447
448        template <typename Char>
449        struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
450    }
451
452}}    // namespace boost::spirit
453
454///////////////////////////////////////////////////////////////////////////////
455#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
456# pragma warning(pop)
457#endif
458
459#endif