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