assign_to.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Copyright (c) 2001-2011 Hartmut Kaiser
  4. http://spirit.sourceforge.net/
  5. Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #if !defined(BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM)
  9. #define BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/spirit/home/qi/detail/construct.hpp>
  14. #include <boost/spirit/home/support/unused.hpp>
  15. #include <boost/spirit/home/qi/detail/attributes.hpp>
  16. #include <boost/spirit/home/support/container.hpp>
  17. #include <boost/fusion/include/copy.hpp>
  18. #include <boost/fusion/adapted/struct/detail/extension.hpp>
  19. #include <boost/ref.hpp>
  20. #include <boost/range/iterator_range.hpp>
  21. namespace boost { namespace spirit { namespace traits
  22. {
  23. ///////////////////////////////////////////////////////////////////////////
  24. // This file contains assignment utilities. The utilities provided also
  25. // accept spirit's unused_type; all no-ops. Compiler optimization will
  26. // easily strip these away.
  27. ///////////////////////////////////////////////////////////////////////////
  28. namespace detail
  29. {
  30. template <typename T>
  31. struct is_iter_range : mpl::false_ {};
  32. template <typename I>
  33. struct is_iter_range<boost::iterator_range<I> > : mpl::true_ {};
  34. template <typename C>
  35. struct is_container_of_ranges
  36. : is_iter_range<typename C::value_type> {};
  37. }
  38. template <typename Attribute, typename Iterator, typename Enable>
  39. struct assign_to_attribute_from_iterators
  40. {
  41. // Common case
  42. static void
  43. call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::false_)
  44. {
  45. if (traits::is_empty(attr))
  46. attr = Attribute(first, last);
  47. else {
  48. for (Iterator i = first; i != last; ++i)
  49. push_back(attr, *i);
  50. }
  51. }
  52. // If Attribute is a container with value_type==iterator_range<T> just push the
  53. // iterator_range into it
  54. static void
  55. call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::true_)
  56. {
  57. typename Attribute::value_type rng(first, last);
  58. push_back(attr, rng);
  59. }
  60. static void
  61. call(Iterator const& first, Iterator const& last, Attribute& attr)
  62. {
  63. call(first, last, attr, detail::is_container_of_ranges<Attribute>());
  64. }
  65. };
  66. template <typename Attribute, typename Iterator>
  67. struct assign_to_attribute_from_iterators<
  68. reference_wrapper<Attribute>, Iterator>
  69. {
  70. static void
  71. call(Iterator const& first, Iterator const& last
  72. , reference_wrapper<Attribute> attr)
  73. {
  74. if (traits::is_empty(attr))
  75. attr = Attribute(first, last);
  76. else {
  77. for (Iterator i = first; i != last; ++i)
  78. push_back(attr, *i);
  79. }
  80. }
  81. };
  82. template <typename Attribute, typename Iterator>
  83. struct assign_to_attribute_from_iterators<
  84. boost::optional<Attribute>, Iterator>
  85. {
  86. static void
  87. call(Iterator const& first, Iterator const& last
  88. , boost::optional<Attribute>& attr)
  89. {
  90. Attribute val;
  91. assign_to(first, last, val);
  92. attr = val;
  93. }
  94. };
  95. template <typename Iterator>
  96. struct assign_to_attribute_from_iterators<
  97. iterator_range<Iterator>, Iterator>
  98. {
  99. static void
  100. call(Iterator const& first, Iterator const& last
  101. , iterator_range<Iterator>& attr)
  102. {
  103. attr = iterator_range<Iterator>(first, last);
  104. }
  105. };
  106. template <typename Iterator, typename Attribute>
  107. inline void
  108. assign_to(Iterator const& first, Iterator const& last, Attribute& attr)
  109. {
  110. assign_to_attribute_from_iterators<Attribute, Iterator>::
  111. call(first, last, attr);
  112. }
  113. template <typename Iterator>
  114. inline void
  115. assign_to(Iterator const&, Iterator const&, unused_type)
  116. {
  117. }
  118. ///////////////////////////////////////////////////////////////////////////
  119. template <typename T, typename Attribute>
  120. void assign_to(T const& val, Attribute& attr);
  121. template <typename Attribute, typename T, typename Enable>
  122. struct assign_to_attribute_from_value
  123. {
  124. typedef typename traits::one_element_sequence<Attribute>::type
  125. is_one_element_sequence;
  126. typedef typename mpl::eval_if<
  127. is_one_element_sequence
  128. , fusion::result_of::at_c<Attribute, 0>
  129. , mpl::identity<Attribute&>
  130. >::type type;
  131. template <typename T_>
  132. static void
  133. call(T_ const& val, Attribute& attr, mpl::false_)
  134. {
  135. attr = static_cast<Attribute>(val);
  136. }
  137. // This handles the case where the attribute is a single element fusion
  138. // sequence. We silently assign to the only element and treat it as the
  139. // attribute to parse the results into.
  140. template <typename T_>
  141. static void
  142. call(T_ const& val, Attribute& attr, mpl::true_)
  143. {
  144. typedef typename fusion::result_of::value_at_c<Attribute, 0>::type
  145. element_type;
  146. fusion::at_c<0>(attr) = static_cast<element_type>(val);
  147. }
  148. static void
  149. call(T const& val, Attribute& attr)
  150. {
  151. call(val, attr, is_one_element_sequence());
  152. }
  153. };
  154. template <typename Attribute>
  155. struct assign_to_attribute_from_value<Attribute, Attribute>
  156. {
  157. static void
  158. call(Attribute const& val, Attribute& attr)
  159. {
  160. attr = val;
  161. }
  162. };
  163. template <typename Attribute, typename T>
  164. struct assign_to_attribute_from_value<Attribute, reference_wrapper<T>
  165. , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type>
  166. {
  167. static void
  168. call(reference_wrapper<T> const& val, Attribute& attr)
  169. {
  170. assign_to(val.get(), attr);
  171. }
  172. };
  173. template <typename Attribute, typename T>
  174. struct assign_to_attribute_from_value<Attribute, boost::optional<T>
  175. , typename disable_if<is_same<Attribute, boost::optional<T> > >::type>
  176. {
  177. static void
  178. call(boost::optional<T> const& val, Attribute& attr)
  179. {
  180. assign_to(val.get(), attr);
  181. }
  182. };
  183. template <typename Attribute, int N, bool Const, typename T>
  184. struct assign_to_attribute_from_value<fusion::extension::adt_attribute_proxy<Attribute, N, Const>, T>
  185. {
  186. static void
  187. call(T const& val, typename fusion::extension::adt_attribute_proxy<Attribute, N, Const>& attr)
  188. {
  189. attr = val;
  190. }
  191. };
  192. namespace detail
  193. {
  194. template <typename A, typename B>
  195. struct is_same_size_sequence
  196. : mpl::bool_<fusion::result_of::size<A>::value
  197. == fusion::result_of::size<B>::value>
  198. {};
  199. }
  200. template <typename Attribute, typename T>
  201. struct assign_to_attribute_from_value<Attribute, T,
  202. mpl::and_<
  203. fusion::traits::is_sequence<Attribute>,
  204. fusion::traits::is_sequence<T>,
  205. detail::is_same_size_sequence<Attribute, T>
  206. >
  207. >
  208. {
  209. static void
  210. call(T const& val, Attribute& attr)
  211. {
  212. fusion::copy(val, attr);
  213. }
  214. };
  215. ///////////////////////////////////////////////////////////////////////////
  216. template <typename Attribute, typename T, typename Enable>
  217. struct assign_to_container_from_value
  218. {
  219. // T is not a container and not a string
  220. template <typename T_>
  221. static void call(T_ const& val, Attribute& attr, mpl::false_, mpl::false_)
  222. {
  223. traits::push_back(attr, val);
  224. }
  225. // T is a container (but not a string), and T is convertible to the
  226. // value_type of the Attribute container
  227. template <typename T_>
  228. static void
  229. append_to_container_not_string(T_ const& val, Attribute& attr, mpl::true_)
  230. {
  231. traits::push_back(attr, val);
  232. }
  233. // T is a container (but not a string), generic overload
  234. template <typename T_>
  235. static void
  236. append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_)
  237. {
  238. typedef typename traits::container_iterator<T_ const>::type
  239. iterator_type;
  240. iterator_type end = traits::end(val);
  241. for (iterator_type i = traits::begin(val); i != end; traits::next(i))
  242. traits::push_back(attr, traits::deref(i));
  243. }
  244. // T is a container (but not a string)
  245. template <typename T_>
  246. static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_)
  247. {
  248. typedef typename container_value<Attribute>::type value_type;
  249. typedef typename is_convertible<T, value_type>::type is_value_type;
  250. append_to_container_not_string(val, attr, is_value_type());
  251. }
  252. ///////////////////////////////////////////////////////////////////////
  253. // T is a string
  254. template <typename Iterator>
  255. static void append_to_string(Attribute& attr, Iterator begin, Iterator end)
  256. {
  257. for (Iterator i = begin; i != end; ++i)
  258. traits::push_back(attr, *i);
  259. }
  260. // T is string, but not convertible to value_type of container
  261. template <typename T_>
  262. static void append_to_container(T_ const& val, Attribute& attr, mpl::false_)
  263. {
  264. typedef typename char_type_of<T_>::type char_type;
  265. append_to_string(attr, traits::get_begin<char_type>(val)
  266. , traits::get_end<char_type>(val));
  267. }
  268. // T is string, and convertible to value_type of container
  269. template <typename T_>
  270. static void append_to_container(T_ const& val, Attribute& attr, mpl::true_)
  271. {
  272. traits::push_back(attr, val);
  273. }
  274. template <typename T_, typename Pred>
  275. static void call(T_ const& val, Attribute& attr, Pred, mpl::true_)
  276. {
  277. typedef typename container_value<Attribute>::type value_type;
  278. typedef typename is_convertible<T, value_type>::type is_value_type;
  279. append_to_container(val, attr, is_value_type());
  280. }
  281. ///////////////////////////////////////////////////////////////////////
  282. static void call(T const& val, Attribute& attr)
  283. {
  284. typedef typename traits::is_container<T>::type is_container;
  285. typedef typename traits::is_string<T>::type is_string;
  286. call(val, attr, is_container(), is_string());
  287. }
  288. };
  289. template <typename Attribute>
  290. struct assign_to_container_from_value<Attribute, Attribute>
  291. {
  292. static void
  293. call(Attribute const& val, Attribute& attr)
  294. {
  295. attr = val;
  296. }
  297. };
  298. template <typename Attribute, typename T>
  299. struct assign_to_container_from_value<Attribute, boost::optional<T>
  300. , typename disable_if<is_same<Attribute, boost::optional<T> > >::type>
  301. {
  302. static void
  303. call(boost::optional<T> const& val, Attribute& attr)
  304. {
  305. assign_to(val.get(), attr);
  306. }
  307. };
  308. template <typename Attribute, typename T>
  309. struct assign_to_container_from_value<Attribute, reference_wrapper<T>
  310. , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type>
  311. {
  312. static void
  313. call(reference_wrapper<T> const& val, Attribute& attr)
  314. {
  315. assign_to(val.get(), attr);
  316. }
  317. };
  318. ///////////////////////////////////////////////////////////////////////////
  319. namespace detail
  320. {
  321. // overload for non-container attributes
  322. template <typename T, typename Attribute>
  323. inline void
  324. assign_to(T const& val, Attribute& attr, mpl::false_)
  325. {
  326. assign_to_attribute_from_value<Attribute, T>::call(val, attr);
  327. }
  328. // overload for containers (but not for variants or optionals
  329. // holding containers)
  330. template <typename T, typename Attribute>
  331. inline void
  332. assign_to(T const& val, Attribute& attr, mpl::true_)
  333. {
  334. assign_to_container_from_value<Attribute, T>::call(val, attr);
  335. }
  336. }
  337. template <typename T, typename Attribute>
  338. inline void
  339. assign_to(T const& val, Attribute& attr)
  340. {
  341. typedef typename mpl::and_<
  342. traits::is_container<Attribute>
  343. , traits::not_is_variant<Attribute>
  344. , traits::not_is_optional<Attribute>
  345. >::type is_not_wrapped_container;
  346. detail::assign_to(val, attr, is_not_wrapped_container());
  347. }
  348. template <typename T>
  349. inline void
  350. assign_to(T const&, unused_type)
  351. {
  352. }
  353. }}}
  354. #endif