Chris@16
|
1 // Copyright (c) 2001-2011 Hartmut Kaiser
|
Chris@16
|
2 // Copyright (c) 2001-2011 Joel de Guzman
|
Chris@16
|
3 //
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 #if !defined(SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM)
|
Chris@16
|
8 #define SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM
|
Chris@16
|
9
|
Chris@16
|
10 #if defined(_MSC_VER)
|
Chris@16
|
11 #pragma once
|
Chris@16
|
12 #endif
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/spirit/home/karma/domain.hpp>
|
Chris@16
|
15 #include <boost/spirit/home/karma/directive/buffer.hpp>
|
Chris@16
|
16 #include <boost/spirit/home/support/unused.hpp>
|
Chris@16
|
17 #include <boost/spirit/home/support/utree/utree_traits_fwd.hpp>
|
Chris@16
|
18 #include <boost/spirit/home/karma/detail/attributes.hpp>
|
Chris@16
|
19 #include <boost/spirit/home/support/detail/hold_any.hpp>
|
Chris@16
|
20 #include <boost/spirit/home/karma/detail/output_iterator.hpp>
|
Chris@16
|
21 #include <boost/spirit/home/support/container.hpp>
|
Chris@16
|
22 #include <boost/utility/enable_if.hpp>
|
Chris@16
|
23 #include <boost/variant.hpp>
|
Chris@16
|
24 #include <boost/detail/workaround.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
27 namespace boost { namespace spirit { namespace karma { namespace detail
|
Chris@16
|
28 {
|
Chris@16
|
29 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
30 // execute a generator if the given Attribute type is compatible
|
Chris@16
|
31 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
32
|
Chris@16
|
33 // this gets instantiated if the Attribute type is _not_ compatible with
|
Chris@16
|
34 // the generator
|
Chris@16
|
35 template <typename Component, typename Attribute, typename Expected
|
Chris@16
|
36 , typename Enable = void>
|
Chris@16
|
37 struct alternative_generate
|
Chris@16
|
38 {
|
Chris@16
|
39 template <typename OutputIterator, typename Context, typename Delimiter>
|
Chris@16
|
40 static bool
|
Chris@16
|
41 call(Component const&, OutputIterator&, Context&, Delimiter const&
|
Chris@16
|
42 , Attribute const&, bool& failed)
|
Chris@16
|
43 {
|
Chris@16
|
44 failed = true;
|
Chris@16
|
45 return false;
|
Chris@16
|
46 }
|
Chris@16
|
47 };
|
Chris@16
|
48
|
Chris@16
|
49 template <typename Component>
|
Chris@16
|
50 struct alternative_generate<Component, unused_type, unused_type>
|
Chris@16
|
51 {
|
Chris@16
|
52 template <typename OutputIterator, typename Context, typename Delimiter>
|
Chris@16
|
53 static bool
|
Chris@16
|
54 call(Component const& component, OutputIterator& sink, Context& ctx
|
Chris@16
|
55 , Delimiter const& d, unused_type, bool&)
|
Chris@16
|
56 {
|
Chris@16
|
57 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
|
Chris@16
|
58 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
|
Chris@16
|
59 #endif
|
Chris@16
|
60 // return true if any of the generators succeed
|
Chris@16
|
61 return component.generate(sink, ctx, d, unused);
|
Chris@16
|
62 }
|
Chris@16
|
63 };
|
Chris@16
|
64
|
Chris@16
|
65 // this gets instantiated if there is no Attribute given for the
|
Chris@16
|
66 // alternative generator
|
Chris@16
|
67 template <typename Component, typename Expected>
|
Chris@16
|
68 struct alternative_generate<Component, unused_type, Expected>
|
Chris@16
|
69 : alternative_generate<Component, unused_type, unused_type> {};
|
Chris@16
|
70
|
Chris@16
|
71 // this gets instantiated if the generator does not expect to receive an
|
Chris@16
|
72 // Attribute (the generator is self contained).
|
Chris@16
|
73 template <typename Component, typename Attribute>
|
Chris@16
|
74 struct alternative_generate<Component, Attribute, unused_type>
|
Chris@16
|
75 : alternative_generate<Component, unused_type, unused_type> {};
|
Chris@16
|
76
|
Chris@16
|
77 // this gets instantiated if the Attribute type is compatible to the
|
Chris@16
|
78 // generator
|
Chris@16
|
79 template <typename Component, typename Attribute, typename Expected>
|
Chris@16
|
80 struct alternative_generate<Component, Attribute, Expected
|
Chris@16
|
81 , typename enable_if<
|
Chris@16
|
82 traits::compute_compatible_component<Expected, Attribute, karma::domain> >::type>
|
Chris@16
|
83 {
|
Chris@16
|
84 template <typename OutputIterator, typename Context, typename Delimiter>
|
Chris@16
|
85 static bool
|
Chris@16
|
86 call(Component const& component, OutputIterator& sink
|
Chris@16
|
87 , Context& ctx, Delimiter const& d, Attribute const& attr, bool&)
|
Chris@16
|
88 {
|
Chris@16
|
89 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
|
Chris@16
|
90 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
|
Chris@16
|
91 #endif
|
Chris@16
|
92 return call(component, sink, ctx, d, attr
|
Chris@16
|
93 , spirit::traits::not_is_variant<Attribute, karma::domain>());
|
Chris@16
|
94 }
|
Chris@16
|
95
|
Chris@16
|
96 template <typename OutputIterator, typename Context, typename Delimiter>
|
Chris@16
|
97 static bool
|
Chris@16
|
98 call(Component const& component, OutputIterator& sink
|
Chris@16
|
99 , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::true_)
|
Chris@16
|
100 {
|
Chris@16
|
101 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
|
Chris@16
|
102 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
|
Chris@16
|
103 #endif
|
Chris@16
|
104 return component.generate(sink, ctx, d, attr);
|
Chris@16
|
105 }
|
Chris@16
|
106
|
Chris@16
|
107 template <typename OutputIterator, typename Context, typename Delimiter>
|
Chris@16
|
108 static bool
|
Chris@16
|
109 call(Component const& component, OutputIterator& sink
|
Chris@16
|
110 , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::false_)
|
Chris@16
|
111 {
|
Chris@16
|
112 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
|
Chris@16
|
113 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter
|
Chris@16
|
114 #endif
|
Chris@16
|
115 typedef
|
Chris@16
|
116 traits::compute_compatible_component<Expected, Attribute, domain>
|
Chris@16
|
117 component_type;
|
Chris@16
|
118
|
Chris@16
|
119 // if we got passed an empty optional, just fail generation
|
Chris@16
|
120 if (!traits::has_optional_value(attr))
|
Chris@16
|
121 return false;
|
Chris@16
|
122
|
Chris@16
|
123 // make sure, the content of the passed variant matches our
|
Chris@16
|
124 // expectations
|
Chris@16
|
125 typename traits::optional_attribute<Attribute>::type attr_ =
|
Chris@16
|
126 traits::optional_value(attr);
|
Chris@16
|
127 if (!component_type::is_compatible(spirit::traits::which(attr_)))
|
Chris@16
|
128 return false;
|
Chris@16
|
129
|
Chris@16
|
130 // returns true if any of the generators succeed
|
Chris@16
|
131 typedef typename component_type::compatible_type compatible_type;
|
Chris@16
|
132 return component.generate(sink, ctx, d
|
Chris@16
|
133 , boost::get<compatible_type>(attr_));
|
Chris@16
|
134 }
|
Chris@16
|
135 };
|
Chris@16
|
136
|
Chris@16
|
137 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
138 // alternative_generate_function: a functor supplied to fusion::any which
|
Chris@16
|
139 // will be executed for every generator in a given alternative generator
|
Chris@16
|
140 // expression
|
Chris@16
|
141 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
142 template <typename OutputIterator, typename Context, typename Delimiter,
|
Chris@16
|
143 typename Attribute, typename Strict>
|
Chris@16
|
144 struct alternative_generate_function
|
Chris@16
|
145 {
|
Chris@16
|
146 alternative_generate_function(OutputIterator& sink_, Context& ctx_
|
Chris@16
|
147 , Delimiter const& d, Attribute const& attr_)
|
Chris@16
|
148 : sink(sink_), ctx(ctx_), delim(d), attr(attr_) {}
|
Chris@16
|
149
|
Chris@16
|
150 template <typename Component>
|
Chris@16
|
151 bool operator()(Component const& component)
|
Chris@16
|
152 {
|
Chris@16
|
153 typedef
|
Chris@16
|
154 typename traits::attribute_of<Component, Context>::type
|
Chris@16
|
155 expected_type;
|
Chris@16
|
156 typedef
|
Chris@16
|
157 alternative_generate<Component, Attribute, expected_type>
|
Chris@16
|
158 generate;
|
Chris@16
|
159
|
Chris@16
|
160 // wrap the given output iterator avoid output as long as one
|
Chris@16
|
161 // component fails
|
Chris@16
|
162 detail::enable_buffering<OutputIterator> buffering(sink);
|
Chris@16
|
163 bool r = false;
|
Chris@16
|
164 bool failed = false; // will be ignored
|
Chris@16
|
165 {
|
Chris@16
|
166 detail::disable_counting<OutputIterator> nocounting(sink);
|
Chris@16
|
167 r = generate::call(component, sink, ctx, delim, attr, failed);
|
Chris@16
|
168 }
|
Chris@16
|
169 if (r)
|
Chris@16
|
170 buffering.buffer_copy();
|
Chris@16
|
171 return r;
|
Chris@16
|
172 }
|
Chris@16
|
173
|
Chris@16
|
174 // avoid double buffering
|
Chris@16
|
175 template <typename Component>
|
Chris@16
|
176 bool operator()(buffer_directive<Component> const& component)
|
Chris@16
|
177 {
|
Chris@16
|
178 typedef typename
|
Chris@16
|
179 traits::attribute_of<Component, Context>::type
|
Chris@16
|
180 expected_type;
|
Chris@16
|
181 typedef alternative_generate<
|
Chris@16
|
182 buffer_directive<Component>, Attribute, expected_type>
|
Chris@16
|
183 generate;
|
Chris@16
|
184
|
Chris@16
|
185 bool failed = false; // will be ignored
|
Chris@16
|
186 return generate::call(component, sink, ctx, delim, attr, failed);
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@16
|
189 OutputIterator& sink;
|
Chris@16
|
190 Context& ctx;
|
Chris@16
|
191 Delimiter const& delim;
|
Chris@16
|
192 Attribute const& attr;
|
Chris@16
|
193
|
Chris@16
|
194 private:
|
Chris@16
|
195 // silence MSVC warning C4512: assignment operator could not be generated
|
Chris@16
|
196 alternative_generate_function& operator= (alternative_generate_function const&);
|
Chris@16
|
197 };
|
Chris@16
|
198
|
Chris@16
|
199 // specialization for strict alternatives
|
Chris@16
|
200 template <typename OutputIterator, typename Context, typename Delimiter,
|
Chris@16
|
201 typename Attribute>
|
Chris@16
|
202 struct alternative_generate_function<
|
Chris@16
|
203 OutputIterator, Context, Delimiter, Attribute, mpl::true_>
|
Chris@16
|
204 {
|
Chris@16
|
205 alternative_generate_function(OutputIterator& sink_, Context& ctx_
|
Chris@16
|
206 , Delimiter const& d, Attribute const& attr_)
|
Chris@16
|
207 : sink(sink_), ctx(ctx_), delim(d), attr(attr_), failed(false) {}
|
Chris@16
|
208
|
Chris@16
|
209 template <typename Component>
|
Chris@16
|
210 bool operator()(Component const& component)
|
Chris@16
|
211 {
|
Chris@16
|
212 typedef
|
Chris@16
|
213 typename traits::attribute_of<Component, Context>::type
|
Chris@16
|
214 expected_type;
|
Chris@16
|
215 typedef
|
Chris@16
|
216 alternative_generate<Component, Attribute, expected_type>
|
Chris@16
|
217 generate;
|
Chris@16
|
218
|
Chris@16
|
219 if (failed)
|
Chris@16
|
220 return false; // give up when already failed
|
Chris@16
|
221
|
Chris@16
|
222 // wrap the given output iterator avoid output as long as one
|
Chris@16
|
223 // component fails
|
Chris@16
|
224 detail::enable_buffering<OutputIterator> buffering(sink);
|
Chris@16
|
225 bool r = false;
|
Chris@16
|
226 {
|
Chris@16
|
227 detail::disable_counting<OutputIterator> nocounting(sink);
|
Chris@16
|
228 r = generate::call(component, sink, ctx, delim, attr, failed);
|
Chris@16
|
229 }
|
Chris@16
|
230 if (r && !failed)
|
Chris@16
|
231 {
|
Chris@16
|
232 buffering.buffer_copy();
|
Chris@16
|
233 return true;
|
Chris@16
|
234 }
|
Chris@16
|
235 return false;
|
Chris@16
|
236 }
|
Chris@16
|
237
|
Chris@16
|
238 OutputIterator& sink;
|
Chris@16
|
239 Context& ctx;
|
Chris@16
|
240 Delimiter const& delim;
|
Chris@16
|
241 Attribute const& attr;
|
Chris@16
|
242 bool failed;
|
Chris@16
|
243
|
Chris@16
|
244 private:
|
Chris@16
|
245 // silence MSVC warning C4512: assignment operator could not be generated
|
Chris@16
|
246 alternative_generate_function& operator= (alternative_generate_function const&);
|
Chris@16
|
247 };
|
Chris@16
|
248 }}}}
|
Chris@16
|
249
|
Chris@16
|
250 #endif
|