pass_container.hpp 16 KB

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