/usr/include/boost/spirit/home/support/detail
Edit: /usr/include/boost/spirit/home/support/detail/hold_any.hpp (15808B)
/*=============================================================================
Copyright (c) 2007-2011 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
///////////////////////////////////////////////////////////////////////////////
#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(boost::core::typeinfo const& src, boost::core::typeinfo const& dest)
: from(src.name()), to(dest.name())
{}
const char* what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE
{
return "bad any cast";
}
const char* from;
const char* to;
};
namespace detail
{
// function pointer table
template
struct fxn_ptr_table
{
boost::core::typeinfo const& (*get_type)();
void (*static_delete)(void**);
void (*destruct)(void**);
void (*clone)(void* const*, void**);
void (*move)(void* const*, void**);
std::basic_istream& (*stream_in)(std::basic_istream&, void**);
std::basic_ostream& (*stream_out)(std::basic_ostream&, void* const*);
};
// static functions for small value-types
template
struct fxns;
template <>
struct fxns
{
template
struct type
{
static boost::core::typeinfo const& get_type()
{
return BOOST_CORE_TYPEID(T);
}
static void static_delete(void** x)
{
reinterpret_cast(x)->~T();
}
static void destruct(void** x)
{
reinterpret_cast(x)->~T();
}
static void clone(void* const* src, void** dest)
{
new (dest) T(*reinterpret_cast(src));
}
static void move(void* const* src, void** dest)
{
*reinterpret_cast(dest) =
*reinterpret_cast(src);
}
static std::basic_istream&
stream_in (std::basic_istream& i, void** obj)
{
i >> *reinterpret_cast(obj);
return i;
}
static std::basic_ostream&
stream_out(std::basic_ostream& o, void* const* obj)
{
o << *reinterpret_cast(obj);
return o;
}
};
};
// static functions for big value-types (bigger than a void*)
template <>
struct fxns
{
template
struct type
{
static boost::core::typeinfo const& get_type()
{
return BOOST_CORE_TYPEID(T);
}
static void static_delete(void** x)
{
// destruct and free memory
delete (*reinterpret_cast(x));
}
static void destruct(void** x)
{
// destruct only, we'll reuse memory
(*reinterpret_cast(x))->~T();
}
static void clone(void* const* src, void** dest)
{
*dest = new T(**reinterpret_cast(src));
}
static void move(void* const* src, void** dest)
{
**reinterpret_cast(dest) =
**reinterpret_cast(src);
}
static std::basic_istream&
stream_in(std::basic_istream& i, void** obj)
{
i >> **reinterpret_cast(obj);
return i;
}
static std::basic_ostream&
stream_out(std::basic_ostream& o, void* const* obj)
{
o << **reinterpret_cast(obj);
return o;
}
};
};
template
struct get_table
{
typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
template
static fxn_ptr_table* get()
{
static fxn_ptr_table static_table =
{
fxns::template type::get_type,
fxns::template type::static_delete,
fxns::template type::destruct,
fxns::template type::clone,
fxns::template type::move,
fxns::template type::stream_in,
fxns::template type::stream_out
};
return &static_table;
}
};
///////////////////////////////////////////////////////////////////////
struct empty {};
template
inline std::basic_istream&
operator>> (std::basic_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 &&
"Tried to insert from a std istream into an empty "
"hold_any instance");
return i;
}
template
inline std::basic_ostream&
operator<< (std::basic_ostream& o, empty const&)
{
return o;
}
}
///////////////////////////////////////////////////////////////////////////
template
class basic_hold_any
{
public:
// constructors
template
explicit basic_hold_any(T const& x)
: table(spirit::detail::get_table::template get()), object(0)
{
new_object(object, x,
typename spirit::detail::get_table::is_small());
}
basic_hold_any()
: table(spirit::detail::get_table::template get()),
object(0)
{
}
basic_hold_any(basic_hold_any const& x)
: table(spirit::detail::get_table::template get()),
object(0)
{
assign(x);
}
~basic_hold_any()
{
table->static_delete(&object);
}
// assignment
basic_hold_any& assign(basic_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
basic_hold_any& assign(T const& x)
{
// are we copying between the same type?
spirit::detail::fxn_ptr_table* x_table =
spirit::detail::get_table::template 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::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::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;
}
template
static void new_object(void*& object, T const& x, mpl::true_)
{
new (&object) T(x);
}
template
static void new_object(void*& object, T const& x, mpl::false_)
{
object = new T(x);
}
// assignment operator
#ifdef BOOST_HAS_RVALUE_REFS
template
basic_hold_any& operator=(T&& x)
{
return assign(std::forward(x));
}
#else
template
basic_hold_any& operator=(T& x)
{
return assign(x);
}
template
basic_hold_any& operator=(T const& x)
{
return assign(x);
}
#endif
// copy assignment operator
basic_hold_any& operator=(basic_hold_any const& x)
{
return assign(x);
}
// utility functions
basic_hold_any& swap(basic_hold_any& x)
{
std::swap(table, x.table);
std::swap(object, x.object);
return *this;
}
boost::core::typeinfo const& type() const
{
return table->get_type();
}
template
T const& cast() const
{
if (type() != BOOST_CORE_TYPEID(T))
throw bad_any_cast(type(), BOOST_CORE_TYPEID(T));
return spirit::detail::get_table::is_small::value ?
*reinterpret_cast(&object) :
*reinterpret_cast(object);
}
// implicit casting is disabled by default for compatibility with boost::any
#ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
// automatic casting operator
template
operator T const& () const { return cast(); }
#endif // implicit casting
bool empty() const
{
return table == spirit::detail::get_table::template get();
}
void reset()
{
if (!empty())
{
table->static_delete(&object);
table = spirit::detail::get_table::template 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
template
friend inline std::basic_istream&
operator>> (std::basic_istream& i, basic_hold_any& obj)
{
return obj.table->stream_in(i, &obj.object);
}
template
friend inline std::basic_ostream&
operator<< (std::basic_ostream& o, basic_hold_any const& obj)
{
return obj.table->stream_out(o, &obj.object);
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private: // types
template
friend T* any_cast(basic_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
inline T* any_cast (basic_hold_any* operand)
{
if (operand && operand->type() == BOOST_CORE_TYPEID(T)) {
return spirit::detail::get_table::is_small::value ?
reinterpret_cast(&operand->object) :
reinterpret_cast(operand->object);
}
return 0;
}
template
inline T const* any_cast(basic_hold_any const* operand)
{
return any_cast(const_cast*>(operand));
}
template
T any_cast(basic_hold_any& operand)
{
typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref;
nonref* result = any_cast(&operand);
if(!result)
boost::throw_exception(bad_any_cast(operand.type(), BOOST_CORE_TYPEID(T)));
return *result;
}
template
T const& any_cast(basic_hold_any const& operand)
{
typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref;
return any_cast(const_cast &>(operand));
}
///////////////////////////////////////////////////////////////////////////////
// backwards compatibility
typedef basic_hold_any hold_any;
typedef basic_hold_any whold_any;
namespace traits
{
template
struct is_hold_any : mpl::false_ {};
template
struct is_hold_any > : mpl::true_ {};
}
}} // namespace boost::spirit
///////////////////////////////////////////////////////////////////////////////
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
# pragma warning(pop)
#endif
#endif