/Src/Dependencies/Boost/boost/spirit/home/support/detail/hold_any.hpp

http://hadesmem.googlecode.com/ · C++ Header · 459 lines · 352 code · 48 blank · 59 comment · 22 complexity · feda23fab9d3f5380eac00f92cbbc68e MD5 · raw file

  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. Distributed under the Boost Software License, Version 1.0. (See accompanying
  7. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. The class boost::spirit::hold_any is built based on the any class
  9. published here: http://www.codeproject.com/cpp/dynamic_typing.asp. It adds
  10. support for std streaming operator<<() and operator>>().
  11. ==============================================================================*/
  12. #if !defined(BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM)
  13. #define BOOST_SPIRIT_HOLD_ANY_MAY_02_2007_0857AM
  14. #if defined(_MSC_VER)
  15. #pragma once
  16. #endif
  17. #include <boost/config.hpp>
  18. #include <boost/type_traits/remove_reference.hpp>
  19. #include <boost/type_traits/is_reference.hpp>
  20. #include <boost/throw_exception.hpp>
  21. #include <boost/static_assert.hpp>
  22. #include <boost/mpl/bool.hpp>
  23. #include <boost/assert.hpp>
  24. #include <boost/detail/sp_typeinfo.hpp>
  25. #include <stdexcept>
  26. #include <typeinfo>
  27. #include <algorithm>
  28. #include <iosfwd>
  29. ///////////////////////////////////////////////////////////////////////////////
  30. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  31. # pragma warning(push)
  32. # pragma warning(disable: 4100) // 'x': unreferenced formal parameter
  33. # pragma warning(disable: 4127) // conditional expression is constant
  34. #endif
  35. ///////////////////////////////////////////////////////////////////////////////
  36. namespace boost { namespace spirit
  37. {
  38. struct bad_any_cast
  39. : std::bad_cast
  40. {
  41. bad_any_cast(boost::detail::sp_typeinfo const& src, boost::detail::sp_typeinfo const& dest)
  42. : from(src.name()), to(dest.name())
  43. {}
  44. virtual const char* what() const throw() { return "bad any cast"; }
  45. const char* from;
  46. const char* to;
  47. };
  48. namespace detail
  49. {
  50. // function pointer table
  51. template <typename Char>
  52. struct fxn_ptr_table
  53. {
  54. boost::detail::sp_typeinfo const& (*get_type)();
  55. void (*static_delete)(void**);
  56. void (*destruct)(void**);
  57. void (*clone)(void* const*, void**);
  58. void (*move)(void* const*, void**);
  59. std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**);
  60. std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, void* const*);
  61. };
  62. // static functions for small value-types
  63. template <typename Small>
  64. struct fxns;
  65. template <>
  66. struct fxns<mpl::true_>
  67. {
  68. template<typename T, typename Char>
  69. struct type
  70. {
  71. static boost::detail::sp_typeinfo const& get_type()
  72. {
  73. return BOOST_SP_TYPEID(T);
  74. }
  75. static void static_delete(void** x)
  76. {
  77. reinterpret_cast<T*>(x)->~T();
  78. }
  79. static void destruct(void** x)
  80. {
  81. reinterpret_cast<T*>(x)->~T();
  82. }
  83. static void clone(void* const* src, void** dest)
  84. {
  85. new (dest) T(*reinterpret_cast<T const*>(src));
  86. }
  87. static void move(void* const* src, void** dest)
  88. {
  89. reinterpret_cast<T*>(dest)->~T();
  90. *reinterpret_cast<T*>(dest) =
  91. *reinterpret_cast<T const*>(src);
  92. }
  93. static std::basic_istream<Char>&
  94. stream_in (std::basic_istream<Char>& i, void** obj)
  95. {
  96. i >> *reinterpret_cast<T*>(obj);
  97. return i;
  98. }
  99. static std::basic_ostream<Char>&
  100. stream_out(std::basic_ostream<Char>& o, void* const* obj)
  101. {
  102. o << *reinterpret_cast<T const*>(obj);
  103. return o;
  104. }
  105. };
  106. };
  107. // static functions for big value-types (bigger than a void*)
  108. template <>
  109. struct fxns<mpl::false_>
  110. {
  111. template<typename T, typename Char>
  112. struct type
  113. {
  114. static boost::detail::sp_typeinfo const& get_type()
  115. {
  116. return BOOST_SP_TYPEID(T);
  117. }
  118. static void static_delete(void** x)
  119. {
  120. // destruct and free memory
  121. delete (*reinterpret_cast<T**>(x));
  122. }
  123. static void destruct(void** x)
  124. {
  125. // destruct only, we'll reuse memory
  126. (*reinterpret_cast<T**>(x))->~T();
  127. }
  128. static void clone(void* const* src, void** dest)
  129. {
  130. *dest = new T(**reinterpret_cast<T* const*>(src));
  131. }
  132. static void move(void* const* src, void** dest)
  133. {
  134. (*reinterpret_cast<T**>(dest))->~T();
  135. **reinterpret_cast<T**>(dest) =
  136. **reinterpret_cast<T* const*>(src);
  137. }
  138. static std::basic_istream<Char>&
  139. stream_in(std::basic_istream<Char>& i, void** obj)
  140. {
  141. i >> **reinterpret_cast<T**>(obj);
  142. return i;
  143. }
  144. static std::basic_ostream<Char>&
  145. stream_out(std::basic_ostream<Char>& o, void* const* obj)
  146. {
  147. o << **reinterpret_cast<T* const*>(obj);
  148. return o;
  149. }
  150. };
  151. };
  152. template <typename T>
  153. struct get_table
  154. {
  155. typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small;
  156. template <typename Char>
  157. static fxn_ptr_table<Char>* get()
  158. {
  159. static fxn_ptr_table<Char> static_table =
  160. {
  161. fxns<is_small>::template type<T, Char>::get_type,
  162. fxns<is_small>::template type<T, Char>::static_delete,
  163. fxns<is_small>::template type<T, Char>::destruct,
  164. fxns<is_small>::template type<T, Char>::clone,
  165. fxns<is_small>::template type<T, Char>::move,
  166. fxns<is_small>::template type<T, Char>::stream_in,
  167. fxns<is_small>::template type<T, Char>::stream_out
  168. };
  169. return &static_table;
  170. }
  171. };
  172. ///////////////////////////////////////////////////////////////////////
  173. struct empty {};
  174. template <typename Char>
  175. inline std::basic_istream<Char>&
  176. operator>> (std::basic_istream<Char>& i, empty&)
  177. {
  178. // If this assertion fires you tried to insert from a std istream
  179. // into an empty hold_any instance. This simply can't work, because
  180. // there is no way to figure out what type to extract from the
  181. // stream.
  182. // The only way to make this work is to assign an arbitrary
  183. // value of the required type to the hold_any instance you want to
  184. // stream to. This assignment has to be executed before the actual
  185. // call to the operator>>().
  186. BOOST_ASSERT(false &&
  187. "Tried to insert from a std istream into an empty "
  188. "hold_any instance");
  189. return i;
  190. }
  191. template <typename Char>
  192. inline std::basic_ostream<Char>&
  193. operator<< (std::basic_ostream<Char>& o, empty const&)
  194. {
  195. return o;
  196. }
  197. }
  198. ///////////////////////////////////////////////////////////////////////////
  199. template <typename Char>
  200. class basic_hold_any
  201. {
  202. public:
  203. // constructors
  204. template <typename T>
  205. explicit basic_hold_any(T const& x)
  206. : table(spirit::detail::get_table<T>::template get<Char>()), object(0)
  207. {
  208. if (spirit::detail::get_table<T>::is_small::value)
  209. new (&object) T(x);
  210. else
  211. object = new T(x);
  212. }
  213. basic_hold_any()
  214. : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
  215. object(0)
  216. {
  217. }
  218. basic_hold_any(basic_hold_any const& x)
  219. : table(spirit::detail::get_table<spirit::detail::empty>::template get<Char>()),
  220. object(0)
  221. {
  222. assign(x);
  223. }
  224. ~basic_hold_any()
  225. {
  226. table->static_delete(&object);
  227. }
  228. // assignment
  229. basic_hold_any& assign(basic_hold_any const& x)
  230. {
  231. if (&x != this) {
  232. // are we copying between the same type?
  233. if (table == x.table) {
  234. // if so, we can avoid reallocation
  235. table->move(&x.object, &object);
  236. }
  237. else {
  238. reset();
  239. x.table->clone(&x.object, &object);
  240. table = x.table;
  241. }
  242. }
  243. return *this;
  244. }
  245. template <typename T>
  246. basic_hold_any& assign(T const& x)
  247. {
  248. // are we copying between the same type?
  249. spirit::detail::fxn_ptr_table<Char>* x_table =
  250. spirit::detail::get_table<T>::template get<Char>();
  251. if (table == x_table) {
  252. // if so, we can avoid deallocating and re-use memory
  253. table->destruct(&object); // first destruct the old content
  254. if (spirit::detail::get_table<T>::is_small::value) {
  255. // create copy on-top of object pointer itself
  256. new (&object) T(x);
  257. }
  258. else {
  259. // create copy on-top of old version
  260. new (object) T(x);
  261. }
  262. }
  263. else {
  264. if (spirit::detail::get_table<T>::is_small::value) {
  265. // create copy on-top of object pointer itself
  266. table->destruct(&object); // first destruct the old content
  267. new (&object) T(x);
  268. }
  269. else {
  270. reset(); // first delete the old content
  271. object = new T(x);
  272. }
  273. table = x_table; // update table pointer
  274. }
  275. return *this;
  276. }
  277. // assignment operator
  278. template <typename T>
  279. basic_hold_any& operator=(T const& x)
  280. {
  281. return assign(x);
  282. }
  283. // utility functions
  284. basic_hold_any& swap(basic_hold_any& x)
  285. {
  286. std::swap(table, x.table);
  287. std::swap(object, x.object);
  288. return *this;
  289. }
  290. boost::detail::sp_typeinfo const& type() const
  291. {
  292. return table->get_type();
  293. }
  294. template <typename T>
  295. T const& cast() const
  296. {
  297. if (type() != BOOST_SP_TYPEID(T))
  298. throw bad_any_cast(type(), BOOST_SP_TYPEID(T));
  299. return spirit::detail::get_table<T>::is_small::value ?
  300. *reinterpret_cast<T const*>(&object) :
  301. *reinterpret_cast<T const*>(object);
  302. }
  303. // implicit casting is disabled by default for compatibility with boost::any
  304. #ifdef BOOST_SPIRIT_ANY_IMPLICIT_CASTING
  305. // automatic casting operator
  306. template <typename T>
  307. operator T const& () const { return cast<T>(); }
  308. #endif // implicit casting
  309. bool empty() const
  310. {
  311. return table == spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
  312. }
  313. void reset()
  314. {
  315. if (!empty())
  316. {
  317. table->static_delete(&object);
  318. table = spirit::detail::get_table<spirit::detail::empty>::template get<Char>();
  319. object = 0;
  320. }
  321. }
  322. // these functions have been added in the assumption that the embedded
  323. // type has a corresponding operator defined, which is completely safe
  324. // because spirit::hold_any is used only in contexts where these operators
  325. // do exist
  326. template <typename Char_>
  327. friend inline std::basic_istream<Char_>&
  328. operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
  329. {
  330. return obj.table->stream_in(i, &obj.object);
  331. }
  332. template <typename Char_>
  333. friend inline std::basic_ostream<Char_>&
  334. operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
  335. {
  336. return obj.table->stream_out(o, &obj.object);
  337. }
  338. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  339. private: // types
  340. template <typename T, typename Char_>
  341. friend T* any_cast(basic_hold_any<Char_> *);
  342. #else
  343. public: // types (public so any_cast can be non-friend)
  344. #endif
  345. // fields
  346. spirit::detail::fxn_ptr_table<Char>* table;
  347. void* object;
  348. };
  349. // boost::any-like casting
  350. template <typename T, typename Char>
  351. inline T* any_cast (basic_hold_any<Char>* operand)
  352. {
  353. if (operand && operand->type() == BOOST_SP_TYPEID(T)) {
  354. return spirit::detail::get_table<T>::is_small::value ?
  355. reinterpret_cast<T*>(&operand->object) :
  356. reinterpret_cast<T*>(operand->object);
  357. }
  358. return 0;
  359. }
  360. template <typename T, typename Char>
  361. inline T const* any_cast(basic_hold_any<Char> const* operand)
  362. {
  363. return any_cast<T>(const_cast<basic_hold_any<Char>*>(operand));
  364. }
  365. template <typename T, typename Char>
  366. T any_cast(basic_hold_any<Char>& operand)
  367. {
  368. typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
  369. #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  370. // If 'nonref' is still reference type, it means the user has not
  371. // specialized 'remove_reference'.
  372. // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
  373. // to generate specialization of remove_reference for your class
  374. // See type traits library documentation for details
  375. BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
  376. #endif
  377. nonref* result = any_cast<nonref>(&operand);
  378. if(!result)
  379. boost::throw_exception(bad_any_cast(operand.type(), BOOST_SP_TYPEID(T)));
  380. return *result;
  381. }
  382. template <typename T, typename Char>
  383. T const& any_cast(basic_hold_any<Char> const& operand)
  384. {
  385. typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type nonref;
  386. #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
  387. // The comment in the above version of 'any_cast' explains when this
  388. // assert is fired and what to do.
  389. BOOST_STATIC_ASSERT(!is_reference<nonref>::value);
  390. #endif
  391. return any_cast<nonref const&>(const_cast<basic_hold_any<Char> &>(operand));
  392. }
  393. ///////////////////////////////////////////////////////////////////////////////
  394. // backwards compatibility
  395. typedef basic_hold_any<char> hold_any;
  396. typedef basic_hold_any<wchar_t> whold_any;
  397. namespace traits
  398. {
  399. template <typename T>
  400. struct is_hold_any : mpl::false_ {};
  401. template <typename Char>
  402. struct is_hold_any<basic_hold_any<Char> > : mpl::true_ {};
  403. }
  404. }} // namespace boost::spirit
  405. ///////////////////////////////////////////////////////////////////////////////
  406. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  407. # pragma warning(pop)
  408. #endif
  409. #endif