text: /*=============================================================================
      Copyright (c) 2007-2010 Hartmut Kaiser
      Copyright (c) Christopher Diggins 2005
      Copyright (c) Pablo Aguilar 2005
      Copyright (c) Kevlin Henney 2001
  
      Distributed under the Boost Software License, Version 1.0. (See accompanying
      file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  
      The class boost::spirit::hold_any is built based on the any class
      published here: http://www.codeproject.com/cpp/dynamic_typing.asp. It adds
      support for std streaming operator<<() and operator>>().
  ==============================================================================*/
  #if !defined(BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM)
  #define BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM
  
  #if defined(_MSC_VER)
  #pragma once
  #endif
  
  #include <boost/config.hpp>
  #include <boost/type_traits/remove_reference.hpp>
  #include <boost/type_traits/is_reference.hpp>
  #include <boost/throw_exception.hpp>
  #include <boost/static_assert.hpp>
  #include <boost/mpl/bool.hpp>
  #include <boost/assert.hpp>
  
  #include <stdexcept>
  #include <typeinfo>
  #include <algorithm>
  #include <iosfwd>
  
  ///////////////////////////////////////////////////////////////////////////////
  #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  # pragma warning(push)
  # pragma warning(disable: 4100)   // 'x': unreferenced formal parameter
  # pragma warning(disable: 4127)   // conditional expression is constant
  #endif
  
  ///////////////////////////////////////////////////////////////////////////////
  namespace boost { namespace spirit
  {
      struct bad_any_cast
        : std::bad_cast
      {
          bad_any_cast(std::type_info const& src, std::type_info const& dest)
            : from(src.name()), to(dest.name())
          {}
  
          virtual const char* what() const throw() { return "bad any cast"; }
  
          const char* from;
          const char* to;
      };
  
      namespace detail
      {
          // function pointer table
          struct fxn_ptr_table
          {
              std::type_info const& (*get_type)();
              void (*static_delete)(void**);
              void (*destruct)(void**);
              void (*clone)(void* const*, void**);
              void (*move)(void* const*, void**);
              std::istream& (*stream_in)(std::istream&, void**);
              std::ostream& (*stream_out)(std::ostream&, void* const*);
          };
  
          // static functions for small value-types
          template<typename Small>
          struct fxns;
  
          template<>
          struct fxns<mpl::true_>
          {
              template<typename T>
              struct type
              {
                  static std::type_info const& get_type()
                  {
                      return typeid(T);
                  }
                  static void static_delete(void** x)
                  {
                      reinterpret_cast<T*>(x)->~T();
                  }
                  static void destruct(void** x)
                  {
                      reinterpret_cast<T*>(x)->~T();
                  }
                  static void clone(void* const* src, void** dest)
                  {
                      new (dest) T(*reinterpret_cast<T const*>(src));
                  }
                  static void move(void* const* src, void** dest)
                  {
                      reinterpret_cast<T*>(dest)->~T();
                      *reinterpret_cast<T*>(dest) =
                          *reinterpret_cast<T const*>(src);
                  }
                  static std::istream& stream_in (std::istream& i, void** obj)
                  {
                      i >> *reinterpret_cast<T*>(obj);
                      return i;
                  }
                  static std::ostream& stream_out(std::ostream& o, void* const* obj)
                  {
                      o << *reinterpret_cast<T const*>(obj);
                      return o;
                  }
              };
          };
  
          // static functions for big value-types (bigger than a void*)
          template<>
          struct fxns<mpl::false_>
          {
              template<typename T>
              struct type
              {
                  static std::type_info const& get_type()
                  {
                      return typeid(T);
                  }
                  static void static_delete(void** x)
                  {
                      // destruct and free memory
                      delete (*reinterpret_cast<T**>(x));
                  }
                  static void destruct(void** x)
                  {
                      // destruct only, we'll reuse memory
                      (*reinterpret_cast<T**>(x))->~T();
                  }
                  static void clone(void* const* src, void** dest)
                  {
                      *dest = new T(**reinterpret_cast<T* const*>(src));
                  }
                  static void move(void* const* src, void** dest)
                  {
                      (*reinterpret_cast<T**>(dest))->~T();
                      **reinterpret_cast<T**>(dest) =
                          **reinterpret_cast<T* const*>(src);
                  }
                  static std::istream& stream_in(std::istream& i, void** obj)
                  {
                      i >> **reinterpret_cast<T**>(obj);
                      return i;
                  }
                  static std::ostream& stream_out(std::ostream& o, void* const* obj)
                  {
                      o << **reinterpret_cast<T* const*>(obj);
                      return o;
                  }
              };
          };
  
          template<typename T>
          struct get_table
          {
              typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
  
              static fxn_ptr_table* get()
              {
                  static fxn_ptr_table static_table =
                  {
                      fxns<is_small>::template type<T>::get_type,
                      fxns<is_small>::template type<T>::static_delete,
                      fxns<is_small>::template type<T>::destruct,
                      fxns<is_small>::template type<T>::clone,
                      fxns<is_small>::template type<T>::move,
                      fxns<is_small>::template type<T>::stream_in,
                      fxns<is_small>::template type<T>::stream_out
                  };
                  return &static_table;
              }
          };
  
          ///////////////////////////////////////////////////////////////////////
          struct empty {};
  
          inline std::istream&
          operator>> (std::istream& i, empty&)
          {
              // If this assertion fires you tried to insert from a std istream
              // into an empty hold_any instance. This simply can't work, because
              // there is no way to figure out what type to extract from the
              // stream.
              // The only way to make this work is to assign an arbitrary
              // value of the required type to the hold_any instance you want to
              // stream to. This assignment has to be executed before the actual
              // call to the operator>>().
              BOOST_ASSERT(false);
              return i;
          }
  
          inline std::ostream&
          operator<< (std::ostream& o, empty const&)
          {
              return o;
          }
      }
  
      ///////////////////////////////////////////////////////////////////////////
      class hold_any
      {
      public:
          // constructors
          template <typename T>
          hold_any(T const& x)
            : table(spirit::detail::get_table<T>::get()), object(0)
          {
              if (spirit::detail::get_table<T>::is_small::value)
                  new (&object) T(x);
              else
                  object = new T(x);
          }
  
          hold_any()
            : table(spirit::detail::get_table<spirit::detail::empty>::get()),
              object(0)
          {
          }
  
          hold_any(hold_any const& x)
            : table(spirit::detail::get_table<spirit::detail::empty>::get()),
              object(0)
          {
              assign(x);
          }
  
          ~hold_any()
          {
              table->static_delete(&object);
          }
  
          // assignment
          hold_any& assign(hold_any const& x)
          {
              if (&x != this) {
                  // are we copying between the same type?
                  if (table == x.table) {
                      // if so, we can avoid reallocation
                      table->move(&x.object, &object);
                  }
                  else {
                      reset();
                      x.table->clone(&x.object, &object);
                      table = x.table;
                  }
              }
              return *this;
          }
  
          template <typename T>
          hold_any& assign(T const& x)
          {
              // are we copying between the same type?
              spirit::detail::fxn_ptr_table* x_table =
                  spirit::detail::get_table<T>::get();
              if (table == x_table) {
              // if so, we can avoid deallocating and re-use memory
                  table->destruct(&object);    // first destruct the old content
                  if (spirit::detail::get_table<T>::is_small::value) {
                      // create copy on-top of object pointer itself
                      new (&object) T(x);
                  }
                  else {
                      // create copy on-top of old version
                      new (object) T(x);
                  }
              }
              else {
                  if (spirit::detail::get_table<T>::is_small::value) {
                      // create copy on-top of object pointer itself
                      table->destruct(&object); // first destruct the old content
                      new (&object) T(x);
                  }
                  else {
                      reset();                  // first delete the old content
                      object = new T(x);
                  }
                  table = x_table;      // update table pointer
              }
              return *this;
          }
  
          // assignment operator
          template <typename T>
          hold_any& operator=(T const& x)
          {
              return assign(x);
          }
  
          // utility functions
          hold_any& swap(hold_any& x)
          {
              std::swap(table, x.table);
              std::swap(object, x.object);
              return *this;
          }
  
          std::type_info const& type() const
          {
              return table->get_type();
          }
  
          template <typename T>
          T const& cast() const
          {
              if (type() != typeid(T))
                throw bad_any_cast(type(), typeid(T));
  
              return spirit::detail::get_table<T>::is_small::value ?
                  *reinterpret_cast<T const*>(&object) :
                  *reinterpret_cast<T const*>(object);
          }
  
  // implicit casting is disabled by default for compatibility with boost::any
  #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
          // automatic casting operator
          template <typename T>
          operator T const& () const { return cast<T>(); }
  #endif // implicit casting
  
          bool empty() const
          {
              return table == spirit::detail::get_table<spirit::detail::empty>::get();
          }
  
          void reset()
          {
              if (!empty())
              {
                  table->static_delete(&object);
                  table = spirit::detail::get_table<spirit::detail::empty>::get();
                  object = 0;
              }
          }
  
      // these functions have been added in the assumption that the embedded
      // type has a corresponding operator defined, which is completely safe
      // because spirit::hold_any is used only in contexts where these operators
      // do exist
          friend std::istream& operator>> (std::istream& i, hold_any& obj)
          {
              return obj.table->stream_in(i, &obj.object);
          }
  
          friend std::ostream& operator<< (std::ostream& o, hold_any const& obj)
          {
              return obj.table->stream_out(o, &obj.object);
          }
  
  #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
      private: // types
          template<typename T>
          friend T* any_cast(hold_any *);
  #else
      public: // types (public so any_cast can be non-friend)
  #endif
          // fields
          spirit::detail::fxn_ptr_table* table;
          void* object;
      };
  
      // boost::any-like casting
      template <typename T>
      inline T* any_cast (hold_any* operand)
      {
          if (operand && operand->type() == typeid(T)) {
              return spirit::detail::get_table<T>::is_small::value ?
                  reinterpret_cast<T*>(&operand->object) :
                  reinterpret_cast<T*>(operand->object);
          }
          return 0;
      }
  
      template <typename T>
      inline T const* any_cast(hold_any const* operand)
      {
          return any_cast<T>(const_cast<hold_any*>(operand));
      }
  
      template <typename T>
      T any_cast(hold_any& operand)
      {
          typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
  
  #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
          // If 'nonref' is still reference type, it means the user has not
          // specialized 'remove_reference'.
  
          // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
          // to generate specialization of remove_reference for your class
          // See type traits library documentation for details
          BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
  #endif
  
          nonref* result = any_cast<nonref>(&operand);
          if(!result)
              boost::throw_exception(bad_any_cast(operand.type(), typeid(T)));
          return *result;
      }
  
      template <typename T>
      T const& any_cast(hold_any const& operand)
      {
          typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
  
  #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
          // The comment in the above version of 'any_cast' explains when this
          // assert is fired and what to do.
          BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
  #endif
  
          return any_cast<nonref const&>(const_cast<hold_any &>(operand));
      }
  
  ///////////////////////////////////////////////////////////////////////////////
  }}    // namespace boost::spirit
  
  ///////////////////////////////////////////////////////////////////////////////
  #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  # pragma warning(pop)
  #endif
  
  #endif
  