hold_any.hpp 15 KB

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