pass_container.hpp 16 KB

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