]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (c) 2001-2011 Hartmut Kaiser |
2 | // Copyright (c) 2001-2011 Joel de Guzman | |
3 | // | |
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_KARMA_REPEAT_MAY_18_2009_0926AM) | |
8 | #define SPIRIT_KARMA_REPEAT_MAY_18_2009_0926AM | |
9 | ||
10 | #if defined(_MSC_VER) | |
11 | #pragma once | |
12 | #endif | |
13 | ||
14 | #include <boost/spirit/home/karma/meta_compiler.hpp> | |
15 | #include <boost/spirit/home/karma/detail/output_iterator.hpp> | |
16 | #include <boost/spirit/home/karma/detail/get_stricttag.hpp> | |
17 | #include <boost/spirit/home/karma/generator.hpp> | |
18 | #include <boost/spirit/home/karma/auxiliary/lazy.hpp> | |
19 | #include <boost/spirit/home/karma/operator/kleene.hpp> | |
20 | #include <boost/spirit/home/support/container.hpp> | |
21 | #include <boost/spirit/home/support/common_terminals.hpp> | |
22 | #include <boost/spirit/home/support/has_semantic_action.hpp> | |
23 | #include <boost/spirit/home/support/handles_container.hpp> | |
24 | #include <boost/spirit/home/karma/detail/attributes.hpp> | |
25 | #include <boost/spirit/home/support/info.hpp> | |
26 | #include <boost/fusion/include/at.hpp> | |
27 | ||
28 | namespace boost { namespace spirit | |
29 | { | |
30 | /////////////////////////////////////////////////////////////////////////// | |
31 | // Enablers | |
32 | /////////////////////////////////////////////////////////////////////////// | |
33 | template <> | |
34 | struct use_directive<karma::domain, tag::repeat> // enables repeat[p] | |
35 | : mpl::true_ {}; | |
36 | ||
37 | template <typename T> | |
38 | struct use_directive<karma::domain | |
39 | , terminal_ex<tag::repeat // enables repeat(exact)[p] | |
40 | , fusion::vector1<T> > | |
41 | > : mpl::true_ {}; | |
42 | ||
43 | template <typename T> | |
44 | struct use_directive<karma::domain | |
45 | , terminal_ex<tag::repeat // enables repeat(min, max)[p] | |
46 | , fusion::vector2<T, T> > | |
47 | > : mpl::true_ {}; | |
48 | ||
49 | template <typename T> | |
50 | struct use_directive<karma::domain | |
51 | , terminal_ex<tag::repeat // enables repeat(min, inf)[p] | |
52 | , fusion::vector2<T, inf_type> > | |
53 | > : mpl::true_ {}; | |
54 | ||
55 | template <> // enables *lazy* repeat(exact)[p] | |
56 | struct use_lazy_directive< | |
57 | karma::domain | |
58 | , tag::repeat | |
59 | , 1 // arity | |
60 | > : mpl::true_ {}; | |
61 | ||
62 | template <> // enables *lazy* repeat(min, max)[p] | |
63 | struct use_lazy_directive< // and repeat(min, inf)[p] | |
64 | karma::domain | |
65 | , tag::repeat | |
66 | , 2 // arity | |
67 | > : mpl::true_ {}; | |
68 | }} | |
69 | ||
70 | namespace boost { namespace spirit { namespace karma | |
71 | { | |
72 | #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS | |
73 | using spirit::repeat; | |
74 | using spirit::inf; | |
75 | #endif | |
76 | using spirit::repeat_type; | |
77 | using spirit::inf_type; | |
78 | ||
79 | /////////////////////////////////////////////////////////////////////////// | |
80 | // handles repeat(exact)[p] | |
81 | template <typename T> | |
82 | struct exact_iterator | |
83 | { | |
84 | exact_iterator(T const exact) | |
85 | : exact(exact) {} | |
86 | ||
87 | typedef T type; | |
88 | T start() const { return 0; } | |
89 | bool got_max(T i) const { return i >= exact; } | |
90 | bool got_min(T i) const { return i >= exact; } | |
91 | ||
92 | T const exact; | |
93 | ||
7c673cae | 94 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 95 | BOOST_DELETED_FUNCTION(exact_iterator& operator= (exact_iterator const&)) |
7c673cae FG |
96 | }; |
97 | ||
98 | // handles repeat(min, max)[p] | |
99 | template <typename T> | |
100 | struct finite_iterator | |
101 | { | |
102 | finite_iterator(T const min, T const max) | |
103 | : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) | |
104 | , max BOOST_PREVENT_MACRO_SUBSTITUTION (max) {} | |
105 | ||
106 | typedef T type; | |
107 | T start() const { return 0; } | |
108 | bool got_max(T i) const { return i >= max; } | |
109 | bool got_min(T i) const { return i >= min; } | |
110 | ||
111 | T const min; | |
112 | T const max; | |
113 | ||
7c673cae | 114 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 115 | BOOST_DELETED_FUNCTION(finite_iterator& operator= (finite_iterator const&)) |
7c673cae FG |
116 | }; |
117 | ||
118 | // handles repeat(min, inf)[p] | |
119 | template <typename T> | |
120 | struct infinite_iterator | |
121 | { | |
122 | infinite_iterator(T const min) | |
123 | : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) {} | |
124 | ||
125 | typedef T type; | |
126 | T start() const { return 0; } | |
127 | bool got_max(T /*i*/) const { return false; } | |
128 | bool got_min(T i) const { return i >= min; } | |
129 | ||
130 | T const min; | |
131 | ||
7c673cae | 132 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 133 | BOOST_DELETED_FUNCTION(infinite_iterator& operator= (infinite_iterator const&)) |
7c673cae FG |
134 | }; |
135 | ||
136 | /////////////////////////////////////////////////////////////////////////// | |
137 | template <typename Subject, typename LoopIter, typename Strict | |
138 | , typename Derived> | |
139 | struct base_repeat_generator : unary_generator<Derived> | |
140 | { | |
141 | private: | |
142 | // iterate over the given container until its exhausted or the embedded | |
143 | // generator succeeds | |
144 | template <typename F, typename Attribute> | |
145 | bool generate_subject(F f, Attribute const&, mpl::false_) const | |
146 | { | |
147 | // Failing subject generators are just skipped. This allows to | |
148 | // selectively generate items in the provided attribute. | |
149 | while (!f.is_at_end()) | |
150 | { | |
151 | bool r = !f(subject); | |
152 | if (r) | |
153 | return true; | |
154 | if (!f.is_at_end()) | |
155 | f.next(); | |
156 | } | |
157 | return false; | |
158 | } | |
159 | ||
160 | template <typename F, typename Attribute> | |
161 | bool generate_subject(F f, Attribute const&, mpl::true_) const | |
162 | { | |
163 | return !f(subject); | |
164 | } | |
165 | ||
166 | // There is no way to distinguish a failed generator from a | |
167 | // generator to be skipped. We assume the user takes responsibility | |
168 | // for ending the loop if no attribute is specified. | |
169 | template <typename F> | |
170 | bool generate_subject(F f, unused_type, mpl::false_) const | |
171 | { | |
172 | return !f(subject); | |
173 | } | |
174 | ||
175 | public: | |
176 | typedef Subject subject_type; | |
177 | ||
178 | typedef mpl::int_<subject_type::properties::value> properties; | |
179 | ||
180 | // Build a std::vector from the subject's attribute. Note | |
181 | // that build_std_vector may return unused_type if the | |
182 | // subject's attribute is an unused_type. | |
183 | template <typename Context, typename Iterator> | |
184 | struct attribute | |
185 | : traits::build_std_vector< | |
186 | typename traits::attribute_of<Subject, Context, Iterator>::type | |
187 | > | |
188 | {}; | |
189 | ||
190 | base_repeat_generator(Subject const& subject, LoopIter const& iter) | |
191 | : subject(subject), iter(iter) {} | |
192 | ||
193 | template <typename OutputIterator, typename Context, typename Delimiter | |
194 | , typename Attribute> | |
195 | bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d | |
196 | , Attribute const& attr) const | |
197 | { | |
198 | typedef detail::fail_function< | |
199 | OutputIterator, Context, Delimiter | |
200 | > fail_function; | |
201 | ||
202 | typedef typename traits::container_iterator< | |
203 | typename add_const<Attribute>::type | |
204 | >::type iterator_type; | |
205 | ||
206 | typedef | |
207 | typename traits::make_indirect_iterator<iterator_type>::type | |
208 | indirect_iterator_type; | |
209 | ||
210 | typedef detail::pass_container< | |
211 | fail_function, Attribute, indirect_iterator_type, mpl::false_> | |
212 | pass_container; | |
213 | ||
214 | iterator_type it = traits::begin(attr); | |
215 | iterator_type end = traits::end(attr); | |
216 | ||
217 | pass_container pass(fail_function(sink, ctx, d), | |
218 | indirect_iterator_type(it), indirect_iterator_type(end)); | |
219 | ||
220 | // generate the minimal required amount of output | |
221 | typename LoopIter::type i = iter.start(); | |
222 | for (/**/; !pass.is_at_end() && !iter.got_min(i); ++i) | |
223 | { | |
224 | if (!generate_subject(pass, attr, Strict())) | |
225 | { | |
226 | // if we fail before reaching the minimum iteration | |
227 | // required, do not output anything and return false | |
228 | return false; | |
229 | } | |
230 | } | |
231 | ||
232 | if (pass.is_at_end() && !iter.got_min(i)) | |
233 | return false; // insufficient attribute elements | |
234 | ||
235 | // generate some more up to the maximum specified | |
236 | for (/**/; !pass.is_at_end() && !iter.got_max(i); ++i) | |
237 | { | |
238 | if (!generate_subject(pass, attr, Strict())) | |
239 | break; | |
240 | } | |
241 | return detail::sink_is_good(sink); | |
242 | } | |
243 | ||
244 | template <typename Context> | |
245 | info what(Context& context) const | |
246 | { | |
247 | return info("repeat", subject.what(context)); | |
248 | } | |
249 | ||
250 | Subject subject; | |
251 | LoopIter iter; | |
252 | }; | |
253 | ||
254 | template <typename Subject, typename LoopIter> | |
255 | struct repeat_generator | |
256 | : base_repeat_generator< | |
257 | Subject, LoopIter, mpl::false_ | |
258 | , repeat_generator<Subject, LoopIter> > | |
259 | { | |
260 | typedef base_repeat_generator< | |
261 | Subject, LoopIter, mpl::false_, repeat_generator | |
262 | > base_repeat_generator_; | |
263 | ||
264 | repeat_generator(Subject const& subject, LoopIter const& iter) | |
265 | : base_repeat_generator_(subject, iter) {} | |
266 | }; | |
267 | ||
268 | template <typename Subject, typename LoopIter> | |
269 | struct strict_repeat_generator | |
270 | : base_repeat_generator< | |
271 | Subject, LoopIter, mpl::true_ | |
272 | , strict_repeat_generator<Subject, LoopIter> > | |
273 | { | |
274 | typedef base_repeat_generator< | |
275 | Subject, LoopIter, mpl::true_, strict_repeat_generator | |
276 | > base_repeat_generator_; | |
277 | ||
278 | strict_repeat_generator(Subject const& subject, LoopIter const& iter) | |
279 | : base_repeat_generator_(subject, iter) {} | |
280 | }; | |
281 | ||
282 | /////////////////////////////////////////////////////////////////////////// | |
283 | // Generator generators: make_xxx function (objects) | |
284 | /////////////////////////////////////////////////////////////////////////// | |
285 | template <typename Subject, typename Modifiers> | |
286 | struct make_directive<tag::repeat, Subject, Modifiers> | |
287 | { | |
288 | typedef typename mpl::if_< | |
289 | detail::get_stricttag<Modifiers> | |
290 | , strict_kleene<Subject>, kleene<Subject> | |
291 | >::type result_type; | |
292 | ||
293 | result_type operator()(unused_type, Subject const& subject | |
294 | , unused_type) const | |
295 | { | |
296 | return result_type(subject); | |
297 | } | |
298 | }; | |
299 | ||
300 | template <typename T, typename Subject, typename Modifiers> | |
301 | struct make_directive< | |
302 | terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers> | |
303 | { | |
304 | typedef exact_iterator<T> iterator_type; | |
305 | ||
306 | typedef typename mpl::if_< | |
307 | detail::get_stricttag<Modifiers> | |
308 | , strict_repeat_generator<Subject, iterator_type> | |
309 | , repeat_generator<Subject, iterator_type> | |
310 | >::type result_type; | |
311 | ||
312 | template <typename Terminal> | |
313 | result_type operator()( | |
314 | Terminal const& term, Subject const& subject, unused_type) const | |
315 | { | |
316 | return result_type(subject, fusion::at_c<0>(term.args)); | |
317 | } | |
318 | }; | |
319 | ||
320 | template <typename T, typename Subject, typename Modifiers> | |
321 | struct make_directive< | |
322 | terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers> | |
323 | { | |
324 | typedef finite_iterator<T> iterator_type; | |
325 | ||
326 | typedef typename mpl::if_< | |
327 | detail::get_stricttag<Modifiers> | |
328 | , strict_repeat_generator<Subject, iterator_type> | |
329 | , repeat_generator<Subject, iterator_type> | |
330 | >::type result_type; | |
331 | ||
332 | template <typename Terminal> | |
333 | result_type operator()( | |
334 | Terminal const& term, Subject const& subject, unused_type) const | |
335 | { | |
336 | return result_type(subject, | |
337 | iterator_type( | |
338 | fusion::at_c<0>(term.args) | |
339 | , fusion::at_c<1>(term.args) | |
340 | ) | |
341 | ); | |
342 | } | |
343 | }; | |
344 | ||
345 | template <typename T, typename Subject, typename Modifiers> | |
346 | struct make_directive< | |
347 | terminal_ex<tag::repeat | |
348 | , fusion::vector2<T, inf_type> >, Subject, Modifiers> | |
349 | { | |
350 | typedef infinite_iterator<T> iterator_type; | |
351 | ||
352 | typedef typename mpl::if_< | |
353 | detail::get_stricttag<Modifiers> | |
354 | , strict_repeat_generator<Subject, iterator_type> | |
355 | , repeat_generator<Subject, iterator_type> | |
356 | >::type result_type; | |
357 | ||
358 | template <typename Terminal> | |
359 | result_type operator()( | |
360 | Terminal const& term, Subject const& subject, unused_type) const | |
361 | { | |
362 | return result_type(subject, fusion::at_c<0>(term.args)); | |
363 | } | |
364 | }; | |
365 | }}} | |
366 | ||
367 | namespace boost { namespace spirit { namespace traits | |
368 | { | |
369 | /////////////////////////////////////////////////////////////////////////// | |
370 | template <typename Subject, typename LoopIter> | |
371 | struct has_semantic_action<karma::repeat_generator<Subject, LoopIter> > | |
372 | : unary_has_semantic_action<Subject> {}; | |
373 | ||
374 | template <typename Subject, typename LoopIter> | |
375 | struct has_semantic_action<karma::strict_repeat_generator<Subject, LoopIter> > | |
376 | : unary_has_semantic_action<Subject> {}; | |
377 | ||
378 | /////////////////////////////////////////////////////////////////////////// | |
379 | template <typename Subject, typename LoopIter, typename Attribute | |
380 | , typename Context, typename Iterator> | |
381 | struct handles_container< | |
382 | karma::repeat_generator<Subject, LoopIter>, Attribute | |
383 | , Context, Iterator> | |
384 | : mpl::true_ {}; | |
385 | ||
386 | template <typename Subject, typename LoopIter, typename Attribute | |
387 | , typename Context, typename Iterator> | |
388 | struct handles_container< | |
389 | karma::strict_repeat_generator<Subject, LoopIter>, Attribute | |
390 | , Context, Iterator> | |
391 | : mpl::true_ {}; | |
392 | }}} | |
393 | ||
394 | #endif |