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

source code of boost/libs/spirit/include/boost/spirit/home/karma/detail/pass_container.hpp