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 
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     {
exact_iteratorboost::spirit::karma::exact_iterator84         exact_iterator(T const exact)
85           : exact(exact) {}
86 
87         typedef T type;
startboost::spirit::karma::exact_iterator88         T start() const { return 0; }
got_maxboost::spirit::karma::exact_iterator89         bool got_max(T i) const { return i >= exact; }
got_minboost::spirit::karma::exact_iterator90         bool got_min(T i) const { return i >= exact; }
91 
92         T const exact;
93 
94         // silence MSVC warning C4512: assignment operator could not be generated
95         BOOST_DELETED_FUNCTION(exact_iterator& operator= (exact_iterator const&))
96     };
97 
98     // handles repeat(min, max)[p]
99     template <typename T>
100     struct finite_iterator
101     {
finite_iteratorboost::spirit::karma::finite_iterator102         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;
startboost::spirit::karma::finite_iterator107         T start() const { return 0; }
got_maxboost::spirit::karma::finite_iterator108         bool got_max(T i) const { return i >= max; }
got_minboost::spirit::karma::finite_iterator109         bool got_min(T i) const { return i >= min; }
110 
111         T const min;
112         T const max;
113 
114         // silence MSVC warning C4512: assignment operator could not be generated
115         BOOST_DELETED_FUNCTION(finite_iterator& operator= (finite_iterator const&))
116     };
117 
118     // handles repeat(min, inf)[p]
119     template <typename T>
120     struct infinite_iterator
121     {
infinite_iteratorboost::spirit::karma::infinite_iterator122         infinite_iterator(T const min)
123           : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) {}
124 
125         typedef T type;
startboost::spirit::karma::infinite_iterator126         T start() const { return 0; }
got_maxboost::spirit::karma::infinite_iterator127         bool got_max(T /*i*/) const { return false; }
got_minboost::spirit::karma::infinite_iterator128         bool got_min(T i) const { return i >= min; }
129 
130         T const min;
131 
132         // silence MSVC warning C4512: assignment operator could not be generated
133         BOOST_DELETED_FUNCTION(infinite_iterator& operator= (infinite_iterator const&))
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>
generate_subjectboost::spirit::karma::base_repeat_generator145         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>
generate_subjectboost::spirit::karma::base_repeat_generator161         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>
generate_subjectboost::spirit::karma::base_repeat_generator170         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 
base_repeat_generatorboost::spirit::karma::base_repeat_generator190         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>
generateboost::spirit::karma::base_repeat_generator195         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>
whatboost::spirit::karma::base_repeat_generator245         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 
repeat_generatorboost::spirit::karma::repeat_generator264         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 
strict_repeat_generatorboost::spirit::karma::strict_repeat_generator278         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 
operator ()boost::spirit::karma::make_directive293         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>
operator ()boost::spirit::karma::make_directive313         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>
operator ()boost::spirit::karma::make_directive333         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>
operator ()boost::spirit::karma::make_directive359         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
395