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
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)
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
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>
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
42 ///////////////////////////////////////////////////////////////////////////////
43 namespace boost { namespace spirit
48 bad_any_cast(boost::detail::sp_typeinfo const& src, boost::detail::sp_typeinfo const& dest)
49 : from(src.name()), to(dest.name())
52 virtual const char* what() const throw() { return "bad any cast"; }
60 // function pointer table
61 template <typename Char>
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*);
73 // static functions for small value-types
74 template <typename Small>
78 struct fxns<mpl::true_>
80 template<typename T, typename Char>
83 static boost::detail::sp_typeinfo const& get_type()
85 return BOOST_SP_TYPEID(T);
87 static void static_delete(void** x)
89 reinterpret_cast<T*>(x)->~T();
91 static void destruct(void** x)
93 reinterpret_cast<T*>(x)->~T();
95 static void clone(void* const* src, void** dest)
97 new (dest) T(*reinterpret_cast<T const*>(src));
99 static void move(void* const* src, void** dest)
101 *reinterpret_cast<T*>(dest) =
102 *reinterpret_cast<T const*>(src);
104 static std::basic_istream<Char>&
105 stream_in (std::basic_istream<Char>& i, void** obj)
107 i >> *reinterpret_cast<T*>(obj);
110 static std::basic_ostream<Char>&
111 stream_out(std::basic_ostream<Char>& o, void* const* obj)
113 o << *reinterpret_cast<T const*>(obj);
119 // static functions for big value-types (bigger than a void*)
121 struct fxns<mpl::false_>
123 template<typename T, typename Char>
126 static boost::detail::sp_typeinfo const& get_type()
128 return BOOST_SP_TYPEID(T);
130 static void static_delete(void** x)
132 // destruct and free memory
133 delete (*reinterpret_cast<T**>(x));
135 static void destruct(void** x)
137 // destruct only, we'll reuse memory
138 (*reinterpret_cast<T**>(x))->~T();
140 static void clone(void* const* src, void** dest)
142 *dest = new T(**reinterpret_cast<T* const*>(src));
144 static void move(void* const* src, void** dest)
146 **reinterpret_cast<T**>(dest) =
147 **reinterpret_cast<T* const*>(src);
149 static std::basic_istream<Char>&
150 stream_in(std::basic_istream<Char>& i, void** obj)
152 i >> **reinterpret_cast<T**>(obj);
155 static std::basic_ostream<Char>&
156 stream_out(std::basic_ostream<Char>& o, void* const* obj)
158 o << **reinterpret_cast<T* const*>(obj);
164 template <typename T>
167 typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
169 template <typename Char>
170 static fxn_ptr_table<Char>* get()
172 static fxn_ptr_table<Char> static_table =
174 fxns<is_small>::template type<T, Char>::get_type,
175 fxns<is_small>::template type<T, Char>::static_delete,
176 fxns<is_small>::template type<T, Char>::destruct,
177 fxns<is_small>::template type<T, Char>::clone,
178 fxns<is_small>::template type<T, Char>::move,
179 fxns<is_small>::template type<T, Char>::stream_in,
180 fxns<is_small>::template type<T, Char>::stream_out
182 return &static_table;
186 ///////////////////////////////////////////////////////////////////////
189 template <typename Char>
190 inline std::basic_istream<Char>&
191 operator>> (std::basic_istream<Char>& i, empty&)
193 // If this assertion fires you tried to insert from a std istream
194 // into an empty hold_any instance. This simply can't work, because
195 // there is no way to figure out what type to extract from the
197 // The only way to make this work is to assign an arbitrary
198 // value of the required type to the hold_any instance you want to
199 // stream to. This assignment has to be executed before the actual
200 // call to the operator>>().
201 BOOST_ASSERT(false &&
202 "Tried to insert from a std istream into an empty "
203 "hold_any instance");
207 template <typename Char>
208 inline std::basic_ostream<Char>&
209 operator<< (std::basic_ostream<Char>& o, empty const&)
215 ///////////////////////////////////////////////////////////////////////////
216 template <typename Char>
221 template <typename T>
222 explicit basic_hold_any(T const& x)
223 : table(spirit::detail::get_table<T>::template get<Char>()), object(0)
225 if (spirit::detail::get_table<T>::is_small::value)
232 : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
237 basic_hold_any(basic_hold_any const& x)
238 : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
246 table->static_delete(&object);
250 basic_hold_any& assign(basic_hold_any const& x)
253 // are we copying between the same type?
254 if (table == x.table) {
255 // if so, we can avoid reallocation
256 table->move(&x.object, &object);
260 x.table->clone(&x.object, &object);
267 template <typename T>
268 basic_hold_any& assign(T const& x)
270 // are we copying between the same type?
271 spirit::detail::fxn_ptr_table<Char>* x_table =
272 spirit::detail::get_table<T>::template get<Char>();
273 if (table == x_table) {
274 // if so, we can avoid deallocating and re-use memory
275 table->destruct(&object); // first destruct the old content
276 if (spirit::detail::get_table<T>::is_small::value) {
277 // create copy on-top of object pointer itself
281 // create copy on-top of old version
286 if (spirit::detail::get_table<T>::is_small::value) {
287 // create copy on-top of object pointer itself
288 table->destruct(&object); // first destruct the old content
292 reset(); // first delete the old content
295 table = x_table; // update table pointer
300 // assignment operator
301 #ifdef BOOST_HAS_RVALUE_REFS
302 template <typename T>
303 basic_hold_any& operator=(T&& x)
305 return assign(std::forward<T>(x));
308 template <typename T>
309 basic_hold_any& operator=(T& x)
314 template <typename T>
315 basic_hold_any& operator=(T const& x)
322 basic_hold_any& swap(basic_hold_any& x)
324 std::swap(table, x.table);
325 std::swap(object, x.object);
329 boost::detail::sp_typeinfo const& type() const
331 return table->get_type();
334 template <typename T>
335 T const& cast() const
337 if (type() != BOOST_SP_TYPEID(T))
338 throw bad_any_cast(type(), BOOST_SP_TYPEID(T));
340 return spirit::detail::get_table<T>::is_small::value ?
341 *reinterpret_cast<T const*>(&object) :
342 *reinterpret_cast<T const*>(object);
345 // implicit casting is disabled by default for compatibility with boost::any
346 #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
347 // automatic casting operator
348 template <typename T>
349 operator T const& () const { return cast<T>(); }
350 #endif // implicit casting
354 return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
361 table->static_delete(&object);
362 table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
367 // these functions have been added in the assumption that the embedded
368 // type has a corresponding operator defined, which is completely safe
369 // because spirit::hold_any is used only in contexts where these operators
371 template <typename Char_>
372 friend inline std::basic_istream<Char_>&
373 operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
375 return obj.table->stream_in(i, &obj.object);
378 template <typename Char_>
379 friend inline std::basic_ostream<Char_>&
380 operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
382 return obj.table->stream_out(o, &obj.object);
385 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
387 template <typename T, typename Char_>
388 friend T* any_cast(basic_hold_any<Char_> *);
390 public: // types (public so any_cast can be non-friend)
393 spirit::detail::fxn_ptr_table<Char>* table;
397 // boost::any-like casting
398 template <typename T, typename Char>
399 inline T* any_cast (basic_hold_any<Char>* operand)
401 if (operand && operand->type() == BOOST_SP_TYPEID(T)) {
402 return spirit::detail::get_table<T>::is_small::value ?
403 reinterpret_cast<T*>(&operand->object) :
404 reinterpret_cast<T*>(operand->object);
409 template <typename T, typename Char>
410 inline T const* any_cast(basic_hold_any<Char> const* operand)
412 return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
415 template <typename T, typename Char>
416 T any_cast(basic_hold_any<Char>& operand)
418 typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
421 nonref* result = any_cast<nonref>(&operand);
423 boost::throw_exception(bad_any_cast(operand.type(), BOOST_SP_TYPEID(T)));
427 template <typename T, typename Char>
428 T const& any_cast(basic_hold_any<Char> const& operand)
430 typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
433 return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
436 ///////////////////////////////////////////////////////////////////////////////
437 // backwards compatibility
438 typedef basic_hold_any<char> hold_any;
439 typedef basic_hold_any<wchar_t> whold_any;
443 template <typename T>
444 struct is_hold_any : mpl::false_ {};
446 template <typename Char>
447 struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
450 }} // namespace boost::spirit
452 ///////////////////////////////////////////////////////////////////////////////
453 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
454 # pragma warning(pop)