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_OPERATOR_SEQUENCE_HPP
8 #define BOOST_SPIRIT_KARMA_OPERATOR_SEQUENCE_HPP
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/karma/domain.hpp>
15 #include <boost/spirit/home/karma/generator.hpp>
16 #include <boost/spirit/home/karma/meta_compiler.hpp>
17 #include <boost/spirit/home/karma/detail/fail_function.hpp>
18 #include <boost/spirit/home/karma/detail/pass_container.hpp>
19 #include <boost/spirit/home/karma/detail/get_stricttag.hpp>
20 #include <boost/spirit/home/support/info.hpp>
21 #include <boost/spirit/home/support/detail/what_function.hpp>
22 #include <boost/spirit/home/karma/detail/attributes.hpp>
23 #include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
24 #include <boost/spirit/home/support/algorithm/any_if.hpp>
25 #include <boost/spirit/home/support/unused.hpp>
26 #include <boost/spirit/home/support/sequence_base_id.hpp>
27 #include <boost/spirit/home/support/has_semantic_action.hpp>
28 #include <boost/spirit/home/support/handles_container.hpp>
29 #include <boost/spirit/home/support/attributes.hpp>
30 #include <boost/fusion/include/vector.hpp>
31 #include <boost/fusion/include/as_vector.hpp>
32 #include <boost/fusion/include/for_each.hpp>
33 #include <boost/type_traits/is_same.hpp>
34 #include <boost/mpl/bitor.hpp>
35 #include <boost/mpl/int.hpp>
36 #include <boost/mpl/and.hpp>
37 #include <boost/mpl/not.hpp>
38 #include <boost/fusion/include/transform.hpp>
39 #include <boost/mpl/accumulate.hpp>
40 #include <boost/proto/operators.hpp>
41 #include <boost/proto/tags.hpp>
42 #include <boost/config.hpp>
43 
44 ///////////////////////////////////////////////////////////////////////////////
45 namespace boost { namespace spirit
46 {
47     ///////////////////////////////////////////////////////////////////////////
48     // Enablers
49     ///////////////////////////////////////////////////////////////////////////
50     template <>
51     struct use_operator<karma::domain, proto::tag::shift_left> // enables <<
52       : mpl::true_ {};
53 
54     template <>
55     struct flatten_tree<karma::domain, proto::tag::shift_left> // flattens <<
56       : mpl::true_ {};
57 }}
58 
59 ///////////////////////////////////////////////////////////////////////////////
60 namespace boost { namespace spirit { namespace traits
61 {
62     // specialization for sequences
63     template <typename Elements>
64     struct sequence_properties
65     {
66         struct element_properties
67         {
68             template <typename T>
69             struct result;
70 
71             template <typename F, typename Element>
72             struct result<F(Element)>
73             {
74                 typedef properties_of<Element> type;
75             };
76 
77             // never called, but needed for decltype-based result_of (C++0x)
78 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
79             template <typename Element>
80             typename result<element_properties(Element)>::type
81             operator()(Element&&) const;
82 #endif
83         };
84 
85         typedef typename mpl::accumulate<
86             typename fusion::result_of::transform<
87                 Elements, element_properties>::type
88           , mpl::int_<karma::generator_properties::no_properties>
89           , mpl::bitor_<mpl::_2, mpl::_1>
90         >::type type;
91     };
92 }}}
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 namespace boost { namespace spirit { namespace karma
96 {
97     template <typename Elements, typename Strict, typename Derived>
98     struct base_sequence : nary_generator<Derived>
99     {
100         typedef typename traits::sequence_properties<Elements>::type properties;
101 
base_sequenceboost::spirit::karma::base_sequence102         base_sequence(Elements const& elements)
103           : elements(elements) {}
104 
105         typedef Elements elements_type;
106         struct sequence_base_id;
107 
108         template <typename Context, typename Iterator = unused_type>
109         struct attribute
110         {
111             // Put all the element attributes in a tuple
112             typedef typename traits::build_attribute_sequence<
113                 Elements, Context, traits::sequence_attribute_transform
114               , Iterator, karma::domain
115             >::type all_attributes;
116 
117             // Now, build a fusion vector over the attributes. Note
118             // that build_fusion_vector 1) removes all unused attributes
119             // and 2) may return unused_type if all elements have
120             // unused_type(s).
121             typedef typename
122                 traits::build_fusion_vector<all_attributes>::type
123             type_;
124 
125             // Finally, strip single element vectors into its
126             // naked form: vector1<T> --> T
127             typedef typename
128                 traits::strip_single_element_vector<type_>::type
129             type;
130         };
131 
132         // standard case. Attribute is a fusion tuple
133         template <
134             typename OutputIterator, typename Context, typename Delimiter
135           , typename Attribute, typename Pred1, typename Pred2>
generate_implboost::spirit::karma::base_sequence136         bool generate_impl(OutputIterator& sink, Context& ctx
137           , Delimiter const& d, Attribute& attr_, Pred1, Pred2) const
138         {
139             typedef detail::fail_function<
140                 OutputIterator, Context, Delimiter> fail_function;
141             typedef traits::attribute_not_unused<Context> predicate;
142 
143             // wrap the attribute in a tuple if it is not a tuple or if the
144             // attribute of this sequence is a single element tuple
145             typedef typename attribute<Context>::type_ attr_type_;
146             typename traits::wrap_if_not_tuple<Attribute
147               , typename mpl::and_<
148                     traits::one_element_sequence<attr_type_>
149                   , mpl::not_<traits::one_element_sequence<Attribute> >
150                 >::type
151             >::type attr(attr_);
152 
153             // return false if *any* of the generators fail
154             bool r = spirit::any_if(elements, attr
155                           , fail_function(sink, ctx, d), predicate());
156 
157             typedef typename traits::attribute_size<Attribute>::type size_type;
158 
159             // fail generating if sequences have not the same (logical) length
160             return !r && (!Strict::value ||
161                 // This ignores container element count (which is not good),
162                 // but allows valid attributes to succeed. This will lead to
163                 // false positives (failing generators, even if they shouldn't)
164                 // if the embedded component is restricting the number of
165                 // container elements it consumes (i.e. repeat). This solution
166                 // is not optimal but much better than letting _all_ repetitive
167                 // components fail.
168                 Pred1::value ||
169                 size_type(traits::sequence_size<attr_type_>::value) == traits::size(attr_));
170         }
171 
172         // Special case when Attribute is an stl container and the sequence's
173         // attribute is not a one element sequence
174         template <
175             typename OutputIterator, typename Context, typename Delimiter
176           , typename Attribute>
generate_implboost::spirit::karma::base_sequence177         bool generate_impl(OutputIterator& sink, Context& ctx
178           , Delimiter const& d, Attribute const& attr_
179           , mpl::true_, mpl::false_) const
180         {
181             // return false if *any* of the generators fail
182             typedef detail::fail_function<
183                 OutputIterator, Context, Delimiter> fail_function;
184 
185             typedef typename traits::container_iterator<
186                 typename add_const<Attribute>::type
187             >::type iterator_type;
188 
189             typedef
190                 typename traits::make_indirect_iterator<iterator_type>::type
191             indirect_iterator_type;
192             typedef detail::pass_container<
193                 fail_function, Attribute, indirect_iterator_type, mpl::true_>
194             pass_container;
195 
196             iterator_type begin = traits::begin(attr_);
197             iterator_type end = traits::end(attr_);
198 
199             pass_container pass(fail_function(sink, ctx, d),
200                 indirect_iterator_type(begin), indirect_iterator_type(end));
201             bool r = fusion::any(elements, pass);
202 
203             // fail generating if sequences have not the same (logical) length
204             return !r && (!Strict::value || begin == end);
205         }
206 
207         // main generate function. Dispatches to generate_impl depending
208         // on the Attribute type.
209         template <
210             typename OutputIterator, typename Context, typename Delimiter
211           , typename Attribute>
generateboost::spirit::karma::base_sequence212         bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d
213           , Attribute const& attr) const
214         {
215             typedef typename traits::is_container<Attribute>::type
216                 is_container;
217 
218             typedef typename attribute<Context>::type_ attr_type_;
219             typedef typename traits::one_element_sequence<attr_type_>::type
220                 is_one_element_sequence;
221 
222             return generate_impl(sink, ctx, d, attr, is_container()
223               , is_one_element_sequence());
224         }
225 
226         template <typename Context>
whatboost::spirit::karma::base_sequence227         info what(Context& context) const
228         {
229             info result("sequence");
230             fusion::for_each(elements,
231                 spirit::detail::what_function<Context>(result, context));
232             return result;
233         }
234 
235         Elements elements;
236     };
237 
238     template <typename Elements>
239     struct sequence
240       : base_sequence<Elements, mpl::false_, sequence<Elements> >
241     {
242         typedef base_sequence<Elements, mpl::false_, sequence> base_sequence_;
243 
sequenceboost::spirit::karma::sequence244         sequence(Elements const& subject)
245           : base_sequence_(subject) {}
246     };
247 
248     template <typename Elements>
249     struct strict_sequence
250       : base_sequence<Elements, mpl::true_, strict_sequence<Elements> >
251     {
252         typedef base_sequence<Elements, mpl::true_, strict_sequence>
253             base_sequence_;
254 
strict_sequenceboost::spirit::karma::strict_sequence255         strict_sequence(Elements const& subject)
256           : base_sequence_(subject) {}
257     };
258 
259     ///////////////////////////////////////////////////////////////////////////
260     // Generator generators: make_xxx function (objects)
261     ///////////////////////////////////////////////////////////////////////////
262     namespace detail
263     {
264         template <typename Elements, bool strict_mode = false>
265         struct make_sequence
266           : make_nary_composite<Elements, sequence>
267         {};
268 
269         template <typename Elements>
270         struct make_sequence<Elements, true>
271           : make_nary_composite<Elements, strict_sequence>
272         {};
273     }
274 
275     template <typename Elements, typename Modifiers>
276     struct make_composite<proto::tag::shift_left, Elements, Modifiers>
277       : detail::make_sequence<Elements, detail::get_stricttag<Modifiers>::value>
278     {};
279 
280     ///////////////////////////////////////////////////////////////////////////
281     // Helper template allowing to get the required container type for a rule
282     // attribute, which is part of a sequence.
283     template <typename Iterator>
284     struct make_sequence_iterator_range
285     {
286         typedef iterator_range<detail::indirect_iterator<Iterator> > type;
287     };
288 }}}
289 
290 namespace boost { namespace spirit { namespace traits
291 {
292     ///////////////////////////////////////////////////////////////////////////
293     template <typename Elements>
294     struct has_semantic_action<karma::sequence<Elements> >
295       : nary_has_semantic_action<Elements> {};
296 
297     template <typename Elements>
298     struct has_semantic_action<karma::strict_sequence<Elements> >
299       : nary_has_semantic_action<Elements> {};
300 
301     ///////////////////////////////////////////////////////////////////////////
302     template <typename Elements, typename Attribute, typename Context
303       , typename Iterator>
304     struct handles_container<karma::sequence<Elements>, Attribute, Context
305           , Iterator>
306       : mpl::true_ {};
307 
308     template <typename Elements, typename Attribute, typename Context
309       , typename Iterator>
310     struct handles_container<karma::strict_sequence<Elements>, Attribute
311           , Context, Iterator>
312       : mpl::true_ {};
313 }}}
314 
315 #endif
316