hold_any.hpp 15 KB

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