pass_container.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Copyright (c) 2001-2011 Hartmut Kaiser
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. =============================================================================*/
  7. #if !defined(SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM)
  8. #define SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM
  9. #if defined(_MSC_VER)
  10. #pragma once
  11. #endif
  12. #include <boost/spirit/home/qi/detail/attributes.hpp>
  13. #include <boost/spirit/home/support/container.hpp>
  14. #include <boost/spirit/home/support/handles_container.hpp>
  15. #include <boost/type_traits/is_base_of.hpp>
  16. #include <boost/type_traits/is_convertible.hpp>
  17. #include <boost/mpl/bool.hpp>
  18. #include <boost/mpl/and.hpp>
  19. #include <boost/mpl/or.hpp>
  20. #include <boost/preprocessor/cat.hpp>
  21. #include <boost/preprocessor/repetition/repeat.hpp>
  22. namespace boost { namespace spirit { namespace qi { namespace detail
  23. {
  24. // Helper meta-function allowing to evaluate weak substitutability and
  25. // negate the result if the predicate (Sequence) is not true
  26. template <typename Sequence, typename Attribute, typename ValueType>
  27. struct negate_weak_substitute_if_not
  28. : mpl::if_<
  29. Sequence
  30. , typename traits::is_weak_substitute<Attribute, ValueType>::type
  31. , typename mpl::not_<
  32. traits::is_weak_substitute<Attribute, ValueType>
  33. >::type>
  34. {};
  35. // pass_through_container: utility to check decide whether a provided
  36. // container attribute needs to be passed through to the current component
  37. // or of we need to split the container by passing along instances of its
  38. // value type
  39. // if the expected attribute of the current component is neither a Fusion
  40. // sequence nor a container, we will pass through the provided container
  41. // only if its value type is not compatible with the component
  42. template <typename Container, typename ValueType, typename Attribute
  43. , typename Sequence, typename Enable = void>
  44. struct pass_through_container_base
  45. : negate_weak_substitute_if_not<Sequence, Attribute, ValueType>
  46. {};
  47. // Specialization for fusion sequences, in this case we check whether all
  48. // the types in the sequence are convertible to the lhs attribute.
  49. //
  50. // We return false if the rhs attribute itself is a fusion sequence, which
  51. // is compatible with the LHS sequence (we want to pass through this
  52. // attribute without it being split apart).
  53. template <typename Container, typename ValueType, typename Attribute
  54. , typename Sequence = mpl::true_>
  55. struct not_compatible_element
  56. : mpl::and_<
  57. negate_weak_substitute_if_not<Sequence, Attribute, Container>
  58. , negate_weak_substitute_if_not<Sequence, Attribute, ValueType> >
  59. {};
  60. // If the value type of the container is not a Fusion sequence, we pass
  61. // through the container if each of the elements of the Attribute
  62. // sequence is compatible with either the container or its value type.
  63. template <typename Container, typename ValueType, typename Attribute
  64. , typename Sequence
  65. , bool IsSequence = fusion::traits::is_sequence<ValueType>::value>
  66. struct pass_through_container_fusion_sequence
  67. {
  68. typedef typename mpl::find_if<
  69. Attribute, not_compatible_element<Container, ValueType, mpl::_1>
  70. >::type iter;
  71. typedef typename mpl::end<Attribute>::type end;
  72. typedef typename is_same<iter, end>::type type;
  73. };
  74. // If both, the Attribute and the value type of the provided container
  75. // are Fusion sequences, we pass the container only if the two
  76. // sequences are not compatible.
  77. template <typename Container, typename ValueType, typename Attribute
  78. , typename Sequence>
  79. struct pass_through_container_fusion_sequence<
  80. Container, ValueType, Attribute, Sequence, true>
  81. {
  82. typedef typename mpl::find_if<
  83. Attribute
  84. , not_compatible_element<Container, ValueType, mpl::_1, Sequence>
  85. >::type iter;
  86. typedef typename mpl::end<Attribute>::type end;
  87. typedef typename is_same<iter, end>::type type;
  88. };
  89. template <typename Container, typename ValueType, typename Attribute
  90. , typename Sequence>
  91. struct pass_through_container_base<Container, ValueType, Attribute
  92. , Sequence
  93. , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
  94. : pass_through_container_fusion_sequence<
  95. Container, ValueType, Attribute, Sequence>
  96. {};
  97. // Specialization for containers
  98. //
  99. // If the value type of the attribute of the current component is not
  100. // a Fusion sequence, we have to pass through the provided container if
  101. // both are compatible.
  102. template <typename Container, typename ValueType, typename Attribute
  103. , typename Sequence, typename AttributeValueType
  104. , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
  105. struct pass_through_container_container
  106. : mpl::or_<
  107. traits::is_weak_substitute<Attribute, Container>
  108. , traits::is_weak_substitute<AttributeValueType, Container> >
  109. {};
  110. // If the value type of the exposed container attribute is a Fusion
  111. // sequence, we use the already existing logic for those.
  112. template <typename Container, typename ValueType, typename Attribute
  113. , typename Sequence, typename AttributeValueType>
  114. struct pass_through_container_container<
  115. Container, ValueType, Attribute, Sequence, AttributeValueType, true>
  116. : pass_through_container_fusion_sequence<
  117. Container, ValueType, AttributeValueType, Sequence>
  118. {};
  119. template <typename Container, typename ValueType, typename Attribute
  120. , typename Sequence>
  121. struct pass_through_container_base<
  122. Container, ValueType, Attribute, Sequence
  123. , typename enable_if<traits::is_container<Attribute> >::type>
  124. : detail::pass_through_container_container<
  125. Container, ValueType, Attribute, Sequence
  126. , typename traits::container_value<Attribute>::type>
  127. {};
  128. // Specialization for exposed optional attributes
  129. //
  130. // If the type embedded in the exposed optional is not a Fusion
  131. // sequence we pass through the container attribute if it is compatible
  132. // either to the optionals embedded type or to the containers value
  133. // type.
  134. template <typename Container, typename ValueType, typename Attribute
  135. , typename Sequence
  136. , bool IsSequence = fusion::traits::is_sequence<Attribute>::value>
  137. struct pass_through_container_optional
  138. : mpl::or_<
  139. traits::is_weak_substitute<Attribute, Container>
  140. , traits::is_weak_substitute<Attribute, ValueType> >
  141. {};
  142. // If the embedded type of the exposed optional attribute is a Fusion
  143. // sequence, we use the already existing logic for those.
  144. template <typename Container, typename ValueType, typename Attribute
  145. , typename Sequence>
  146. struct pass_through_container_optional<
  147. Container, ValueType, Attribute, Sequence, true>
  148. : pass_through_container_fusion_sequence<
  149. Container, ValueType, Attribute, Sequence>
  150. {};
  151. ///////////////////////////////////////////////////////////////////////////
  152. template <typename Container, typename ValueType, typename Attribute
  153. , typename Sequence>
  154. struct pass_through_container
  155. : pass_through_container_base<Container, ValueType, Attribute, Sequence>
  156. {};
  157. // Handle optional attributes
  158. template <typename Container, typename ValueType, typename Attribute
  159. , typename Sequence>
  160. struct pass_through_container<
  161. Container, ValueType, boost::optional<Attribute>, Sequence>
  162. : pass_through_container_optional<
  163. Container, ValueType, Attribute, Sequence>
  164. {};
  165. // If both, the containers value type and the exposed attribute type are
  166. // optionals we are allowed to pass through the container only if the
  167. // embedded types of those optionals are not compatible.
  168. template <typename Container, typename ValueType, typename Attribute
  169. , typename Sequence>
  170. struct pass_through_container<
  171. Container, boost::optional<ValueType>, boost::optional<Attribute>
  172. , Sequence>
  173. : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
  174. {};
  175. // Specialization for exposed variant attributes
  176. //
  177. // We pass through the container attribute if at least one of the embedded
  178. // types in the variant requires to pass through the attribute
  179. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
  180. template <typename Container, typename ValueType, typename Sequence
  181. , typename T>
  182. struct pass_through_container<Container, ValueType, boost::variant<T>
  183. , Sequence>
  184. : pass_through_container<Container, ValueType, T, Sequence>
  185. {};
  186. template <typename Container, typename ValueType, typename Sequence
  187. , typename T0, typename ...TN>
  188. struct pass_through_container<Container, ValueType
  189. , boost::variant<T0, TN...>, Sequence>
  190. : mpl::bool_<pass_through_container<
  191. Container, ValueType, T0, Sequence
  192. >::type::value || pass_through_container<
  193. Container, ValueType, boost::variant<TN...>, Sequence
  194. >::type::value>
  195. {};
  196. #else
  197. #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \
  198. pass_through_container<Container, ValueType, \
  199. BOOST_PP_CAT(T, N), Sequence>::type::value || \
  200. /***/
  201. // make sure unused variant parameters do not affect the outcome
  202. template <typename Container, typename ValueType, typename Sequence>
  203. struct pass_through_container<Container, ValueType
  204. , boost::detail::variant::void_, Sequence>
  205. : mpl::false_
  206. {};
  207. template <typename Container, typename ValueType, typename Sequence
  208. , BOOST_VARIANT_ENUM_PARAMS(typename T)>
  209. struct pass_through_container<Container, ValueType
  210. , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Sequence>
  211. : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
  212. , BOOST_SPIRIT_PASS_THROUGH_CONTAINER, _) false>
  213. {};
  214. #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER
  215. #endif
  216. }}}}
  217. ///////////////////////////////////////////////////////////////////////////////
  218. namespace boost { namespace spirit { namespace traits
  219. {
  220. ///////////////////////////////////////////////////////////////////////////
  221. // forwarding customization point for domain qi::domain
  222. template <typename Container, typename ValueType, typename Attribute
  223. , typename Sequence>
  224. struct pass_through_container<
  225. Container, ValueType, Attribute, Sequence, qi::domain>
  226. : qi::detail::pass_through_container<
  227. Container, ValueType, Attribute, Sequence>
  228. {};
  229. }}}
  230. namespace boost { namespace spirit { namespace qi { namespace detail
  231. {
  232. ///////////////////////////////////////////////////////////////////////////
  233. // This function handles the case where the attribute (Attr) given
  234. // the sequence is an STL container. This is a wrapper around F.
  235. // The function F does the actual parsing.
  236. template <typename F, typename Attr, typename Sequence>
  237. struct pass_container
  238. {
  239. typedef typename F::context_type context_type;
  240. typedef typename F::iterator_type iterator_type;
  241. pass_container(F const& f_, Attr& attr_)
  242. : f(f_), attr(attr_) {}
  243. // this is for the case when the current element exposes an attribute
  244. // which is pushed back onto the container
  245. template <typename Component>
  246. bool dispatch_container(Component const& component, mpl::false_) const
  247. {
  248. // synthesized attribute needs to be default constructed
  249. typename traits::container_value<Attr>::type val =
  250. typename traits::container_value<Attr>::type();
  251. iterator_type save = f.first;
  252. bool r = f(component, val);
  253. if (!r)
  254. {
  255. // push the parsed value into our attribute
  256. r = !traits::push_back(attr, val);
  257. if (r)
  258. f.first = save;
  259. }
  260. return r;
  261. }
  262. // this is for the case when the current element is able to handle an
  263. // attribute which is a container itself, this element will push its
  264. // data directly into the attribute container
  265. template <typename Component>
  266. bool dispatch_container(Component const& component, mpl::true_) const
  267. {
  268. return f(component, attr);
  269. }
  270. ///////////////////////////////////////////////////////////////////////
  271. // this is for the case when the current element doesn't expect an
  272. // attribute
  273. template <typename Component>
  274. bool dispatch_attribute(Component const& component, mpl::false_) const
  275. {
  276. return f(component, unused);
  277. }
  278. // the current element expects an attribute
  279. template <typename Component>
  280. bool dispatch_attribute(Component const& component, mpl::true_) const
  281. {
  282. typedef typename traits::container_value<Attr>::type value_type;
  283. typedef typename traits::attribute_of<
  284. Component, context_type, iterator_type>::type
  285. rhs_attribute;
  286. // this predicate detects, whether the attribute of the current
  287. // element is a substitute for the value type of the container
  288. // attribute
  289. typedef mpl::and_<
  290. traits::handles_container<
  291. Component, Attr, context_type, iterator_type>
  292. , traits::pass_through_container<
  293. Attr, value_type, rhs_attribute, Sequence, qi::domain>
  294. > predicate;
  295. return dispatch_container(component, predicate());
  296. }
  297. // Dispatches to dispatch_main depending on the attribute type
  298. // of the Component
  299. template <typename Component>
  300. bool operator()(Component const& component) const
  301. {
  302. // we need to dispatch depending on the type of the attribute
  303. // of the current element (component). If this is has no attribute
  304. // we shouldn't pass an attribute at all.
  305. typedef typename traits::not_is_unused<
  306. typename traits::attribute_of<
  307. Component, context_type, iterator_type
  308. >::type
  309. >::type predicate;
  310. // ensure the attribute is actually a container type
  311. traits::make_container(attr);
  312. return dispatch_attribute(component, predicate());
  313. }
  314. F f;
  315. Attr& attr;
  316. // silence MSVC warning C4512: assignment operator could not be generated
  317. BOOST_DELETED_FUNCTION(pass_container& operator= (pass_container const&))
  318. };
  319. ///////////////////////////////////////////////////////////////////////////
  320. // Utility function to make a pass_container for container components
  321. // (kleene, list, plus, repeat)
  322. template <typename F, typename Attr>
  323. inline pass_container<F, Attr, mpl::false_>
  324. make_pass_container(F const& f, Attr& attr)
  325. {
  326. return pass_container<F, Attr, mpl::false_>(f, attr);
  327. }
  328. // Utility function to make a pass_container for sequences
  329. template <typename F, typename Attr>
  330. inline pass_container<F, Attr, mpl::true_>
  331. make_sequence_pass_container(F const& f, Attr& attr)
  332. {
  333. return pass_container<F, Attr, mpl::true_>(f, attr);
  334. }
  335. }}}}
  336. #endif