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