]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/include/boost/spirit/home/support/detail/hold_any.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / support / detail / hold_any.hpp
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 ///////////////////////////////////////////////////////////////////////////////
43 namespace 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) =
102 *reinterpret_cast<T const*>(src);
103 }
104 static std::basic_istream<Char>&
105 stream_in (std::basic_istream<Char>& i, void** obj)
106 {
107 i >> *reinterpret_cast<T*>(obj);
108 return i;
109 }
110 static std::basic_ostream<Char>&
111 stream_out(std::basic_ostream<Char>& o, void* const* obj)
112 {
113 o << *reinterpret_cast<T const*>(obj);
114 return o;
115 }
116 };
117 };
118
119 // static functions for big value-types (bigger than a void*)
120 template <>
121 struct fxns<mpl::false_>
122 {
123 template<typename T, typename Char>
124 struct type
125 {
126 static boost::detail::sp_typeinfo const& get_type()
127 {
128 return BOOST_SP_TYPEID(T);
129 }
130 static void static_delete(void** x)
131 {
132 // destruct and free memory
133 delete (*reinterpret_cast<T**>(x));
134 }
135 static void destruct(void** x)
136 {
137 // destruct only, we'll reuse memory
138 (*reinterpret_cast<T**>(x))->~T();
139 }
140 static void clone(void* const* src, void** dest)
141 {
142 *dest = new T(**reinterpret_cast<T* const*>(src));
143 }
144 static void move(void* const* src, void** dest)
145 {
146 **reinterpret_cast<T**>(dest) =
147 **reinterpret_cast<T* const*>(src);
148 }
149 static std::basic_istream<Char>&
150 stream_in(std::basic_istream<Char>& i, void** obj)
151 {
152 i >> **reinterpret_cast<T**>(obj);
153 return i;
154 }
155 static std::basic_ostream<Char>&
156 stream_out(std::basic_ostream<Char>& o, void* const* obj)
157 {
158 o << **reinterpret_cast<T* const*>(obj);
159 return o;
160 }
161 };
162 };
163
164 template <typename T>
165 struct get_table
166 {
167 typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
168
169 template <typename Char>
170 static fxn_ptr_table<Char>* get()
171 {
172 static fxn_ptr_table<Char> static_table =
173 {
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
181 };
182 return &static_table;
183 }
184 };
185
186 ///////////////////////////////////////////////////////////////////////
187 struct empty {};
188
189 template <typename Char>
190 inline std::basic_istream<Char>&
191 operator>> (std::basic_istream<Char>& i, empty&)
192 {
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
196 // stream.
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");
204 return i;
205 }
206
207 template <typename Char>
208 inline std::basic_ostream<Char>&
209 operator<< (std::basic_ostream<Char>& o, empty const&)
210 {
211 return o;
212 }
213 }
214
215 ///////////////////////////////////////////////////////////////////////////
216 template <typename Char>
217 class basic_hold_any
218 {
219 public:
220 // constructors
221 template <typename T>
222 explicit basic_hold_any(T const& x)
223 : table(spirit::detail::get_table<T>::template get<Char>()), object(0)
224 {
225 if (spirit::detail::get_table<T>::is_small::value)
226 new (&object) T(x);
227 else
228 object = new T(x);
229 }
230
231 basic_hold_any()
232 : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
233 object(0)
234 {
235 }
236
237 basic_hold_any(basic_hold_any const& x)
238 : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
239 object(0)
240 {
241 assign(x);
242 }
243
244 ~basic_hold_any()
245 {
246 table->static_delete(&object);
247 }
248
249 // assignment
250 basic_hold_any& assign(basic_hold_any const& x)
251 {
252 if (&x != this) {
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);
257 }
258 else {
259 reset();
260 x.table->clone(&x.object, &object);
261 table = x.table;
262 }
263 }
264 return *this;
265 }
266
267 template <typename T>
268 basic_hold_any& assign(T const& x)
269 {
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
278 new (&object) T(x);
279 }
280 else {
281 // create copy on-top of old version
282 new (object) T(x);
283 }
284 }
285 else {
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
289 new (&object) T(x);
290 }
291 else {
292 reset(); // first delete the old content
293 object = new T(x);
294 }
295 table = x_table; // update table pointer
296 }
297 return *this;
298 }
299
300 // assignment operator
301 #ifdef BOOST_HAS_RVALUE_REFS
302 template <typename T>
303 basic_hold_any& operator=(T&& x)
304 {
305 return assign(std::forward<T>(x));
306 }
307 #else
308 template <typename T>
309 basic_hold_any& operator=(T& x)
310 {
311 return assign(x);
312 }
313
314 template <typename T>
315 basic_hold_any& operator=(T const& x)
316 {
317 return assign(x);
318 }
319 #endif
320
321 // utility functions
322 basic_hold_any& swap(basic_hold_any& x)
323 {
324 std::swap(table, x.table);
325 std::swap(object, x.object);
326 return *this;
327 }
328
329 boost::detail::sp_typeinfo const& type() const
330 {
331 return table->get_type();
332 }
333
334 template <typename T>
335 T const& cast() const
336 {
337 if (type() != BOOST_SP_TYPEID(T))
338 throw bad_any_cast(type(), BOOST_SP_TYPEID(T));
339
340 return spirit::detail::get_table<T>::is_small::value ?
341 *reinterpret_cast<T const*>(&object) :
342 *reinterpret_cast<T const*>(object);
343 }
344
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
351
352 bool empty() const
353 {
354 return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
355 }
356
357 void reset()
358 {
359 if (!empty())
360 {
361 table->static_delete(&object);
362 table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
363 object = 0;
364 }
365 }
366
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
370 // do exist
371 template <typename Char_>
372 friend inline std::basic_istream<Char_>&
373 operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
374 {
375 return obj.table->stream_in(i, &obj.object);
376 }
377
378 template <typename Char_>
379 friend inline std::basic_ostream<Char_>&
380 operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
381 {
382 return obj.table->stream_out(o, &obj.object);
383 }
384
385 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
386 private: // types
387 template <typename T, typename Char_>
388 friend T* any_cast(basic_hold_any<Char_> *);
389 #else
390 public: // types (public so any_cast can be non-friend)
391 #endif
392 // fields
393 spirit::detail::fxn_ptr_table<Char>* table;
394 void* object;
395 };
396
397 // boost::any-like casting
398 template <typename T, typename Char>
399 inline T* any_cast (basic_hold_any<Char>* operand)
400 {
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);
405 }
406 return 0;
407 }
408
409 template <typename T, typename Char>
410 inline T const* any_cast(basic_hold_any<Char> const* operand)
411 {
412 return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
413 }
414
415 template <typename T, typename Char>
416 T any_cast(basic_hold_any<Char>& operand)
417 {
418 typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
419
420
421 nonref* result = any_cast<nonref>(&operand);
422 if(!result)
423 boost::throw_exception(bad_any_cast(operand.type(), BOOST_SP_TYPEID(T)));
424 return *result;
425 }
426
427 template <typename T, typename Char>
428 T const& any_cast(basic_hold_any<Char> const& operand)
429 {
430 typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
431
432
433 return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
434 }
435
436 ///////////////////////////////////////////////////////////////////////////////
437 // backwards compatibility
438 typedef basic_hold_any<char> hold_any;
439 typedef basic_hold_any<wchar_t> whold_any;
440
441 namespace traits
442 {
443 template <typename T>
444 struct is_hold_any : mpl::false_ {};
445
446 template <typename Char>
447 struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
448 }
449
450 }} // namespace boost::spirit
451
452 ///////////////////////////////////////////////////////////////////////////////
453 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
454 # pragma warning(pop)
455 #endif
456
457 #endif