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

source code of boost/libs/spirit/include/boost/spirit/home/karma/directive/repeat.hpp