/Src/Dependencies/Boost/boost/spirit/home/karma/detail/pass_container.hpp

http://hadesmem.googlecode.com/ · C++ Header · 350 lines · 225 code · 42 blank · 83 comment · 3 complexity · 3acd396be550dde14927fe8933bff4d4 MD5 · raw file

  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 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. #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \
  184. pass_through_container<Container, ValueType, \
  185. BOOST_PP_CAT(T, N), Sequence>::type::value || \
  186. /***/
  187. // make sure unused variant parameters do not affect the outcome
  188. template <typename Container, typename ValueType, typename Sequence>
  189. struct pass_through_container<Container, ValueType
  190. , boost::detail::variant::void_, Sequence>
  191. : mpl::false_
  192. {};
  193. template <typename Container, typename ValueType, typename Sequence
  194. , BOOST_VARIANT_ENUM_PARAMS(typename T)>
  195. struct pass_through_container<Container, ValueType
  196. , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Sequence>
  197. : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
  198. , BOOST_SPIRIT_PASS_THROUGH_CONTAINER, _) false>
  199. {};
  200. #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER
  201. }}}}
  202. ///////////////////////////////////////////////////////////////////////////////
  203. namespace boost { namespace spirit { namespace traits
  204. {
  205. ///////////////////////////////////////////////////////////////////////////
  206. // forwarding customization point for domain karma::domain
  207. template <typename Container, typename ValueType, typename Attribute
  208. , typename Sequence>
  209. struct pass_through_container<
  210. Container, ValueType, Attribute, Sequence, karma::domain>
  211. : karma::detail::pass_through_container<
  212. Container, ValueType, Attribute, Sequence>
  213. {};
  214. }}}
  215. namespace boost { namespace spirit { namespace karma { namespace detail
  216. {
  217. ///////////////////////////////////////////////////////////////////////////
  218. // This function handles the case where the attribute (Attr) given
  219. // to the sequence is an STL container. This is a wrapper around F.
  220. // The function F does the actual generating.
  221. template <typename F, typename Attr, typename Iterator, typename Sequence>
  222. struct pass_container
  223. {
  224. typedef typename F::context_type context_type;
  225. pass_container(F const& f, Iterator begin, Iterator end)
  226. : f(f), iter(begin), end(end)
  227. {}
  228. bool is_at_end() const
  229. {
  230. return traits::compare(iter, end);
  231. }
  232. void next()
  233. {
  234. traits::next(iter);
  235. }
  236. // this is for the case when the current element expects an attribute
  237. // which is taken from the next entry in the container
  238. template <typename Component>
  239. bool dispatch_container(Component const& component, mpl::false_) const
  240. {
  241. // get the next value to generate from container
  242. if (!is_at_end() && !f(component, traits::deref(iter)))
  243. {
  244. // needs to return false as long as everything is ok
  245. traits::next(iter);
  246. return false;
  247. }
  248. // either no elements available any more or generation failed
  249. return true;
  250. }
  251. // this is for the case when the current element is able to handle an
  252. // attribute which is a container itself, this element will push its
  253. // data directly into the attribute container
  254. template <typename Component>
  255. bool dispatch_container(Component const& component, mpl::true_) const
  256. {
  257. return f(component, make_iterator_range(iter, end));
  258. }
  259. ///////////////////////////////////////////////////////////////////////
  260. // this is for the case when the current element doesn't expect an
  261. // attribute
  262. template <typename Component>
  263. bool dispatch_attribute(Component const& component, mpl::false_) const
  264. {
  265. return f(component, unused);
  266. }
  267. // the current element expects an attribute
  268. template <typename Component>
  269. bool dispatch_attribute(Component const& component, mpl::true_) const
  270. {
  271. typedef typename traits::container_value<Attr>::type value_type;
  272. typedef typename
  273. traits::attribute_of<Component, context_type>::type
  274. lhs_attribute;
  275. // this predicate detects, whether the value type of the container
  276. // attribute is a substitute for the attribute of the current
  277. // element
  278. typedef mpl::and_<
  279. traits::handles_container<Component, Attr, context_type>
  280. , traits::pass_through_container<
  281. Attr, value_type, lhs_attribute, Sequence, karma::domain>
  282. > predicate;
  283. return dispatch_container(component, predicate());
  284. }
  285. // Dispatches to dispatch_main depending on the attribute type
  286. // of the Component
  287. template <typename Component>
  288. bool operator()(Component const& component) const
  289. {
  290. // we need to dispatch depending on the type of the attribute
  291. // of the current element (component). If this is has no attribute
  292. // we shouldn't use an element of the container but unused_type
  293. // instead
  294. typedef traits::not_is_unused<
  295. typename traits::attribute_of<Component, context_type>::type
  296. > predicate;
  297. return dispatch_attribute(component, predicate());
  298. }
  299. F f;
  300. mutable Iterator iter;
  301. mutable Iterator end;
  302. private:
  303. // silence MSVC warning C4512: assignment operator could not be generated
  304. pass_container& operator= (pass_container const&);
  305. };
  306. }}}}
  307. #endif