📄 hold_any.hpp
字号:
// Copyright (c) 2008 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#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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -