]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Joel de Guzman | |
3 | Copyright (c) 2001-2011 Hartmut Kaiser | |
4 | http://spirit.sourceforge.net/ | |
5 | ||
6 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | =============================================================================*/ | |
9 | #if !defined(BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM) | |
10 | #define BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM | |
11 | ||
12 | #if defined(_MSC_VER) | |
13 | #pragma once | |
14 | #endif | |
15 | ||
16 | #include <boost/spirit/home/qi/detail/construct.hpp> | |
17 | #include <boost/spirit/home/support/unused.hpp> | |
18 | #include <boost/spirit/home/qi/detail/attributes.hpp> | |
19 | #include <boost/spirit/home/support/container.hpp> | |
20 | #include <boost/fusion/include/copy.hpp> | |
21 | #include <boost/fusion/adapted/struct/detail/extension.hpp> | |
22 | #include <boost/ref.hpp> | |
23 | #include <boost/range/iterator_range.hpp> | |
24 | ||
25 | namespace boost { namespace spirit { namespace traits | |
26 | { | |
27 | /////////////////////////////////////////////////////////////////////////// | |
28 | // This file contains assignment utilities. The utilities provided also | |
29 | // accept spirit's unused_type; all no-ops. Compiler optimization will | |
30 | // easily strip these away. | |
31 | /////////////////////////////////////////////////////////////////////////// | |
32 | namespace detail | |
33 | { | |
34 | template <typename T> | |
35 | struct is_iter_range : mpl::false_ {}; | |
36 | ||
37 | template <typename I> | |
38 | struct is_iter_range<boost::iterator_range<I> > : mpl::true_ {}; | |
39 | ||
40 | template <typename C> | |
41 | struct is_container_of_ranges | |
42 | : is_iter_range<typename C::value_type> {}; | |
43 | } | |
44 | ||
45 | template <typename Attribute, typename Iterator, typename Enable> | |
46 | struct assign_to_attribute_from_iterators | |
47 | { | |
48 | // Common case | |
49 | static void | |
50 | call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::false_) | |
51 | { | |
52 | if (traits::is_empty(attr)) | |
53 | attr = Attribute(first, last); | |
54 | else { | |
55 | for (Iterator i = first; i != last; ++i) | |
56 | push_back(attr, *i); | |
57 | } | |
58 | } | |
59 | ||
60 | // If Attribute is a container with value_type==iterator_range<T> just push the | |
61 | // iterator_range into it | |
62 | static void | |
63 | call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::true_) | |
64 | { | |
65 | typename Attribute::value_type rng(first, last); | |
66 | push_back(attr, rng); | |
67 | } | |
68 | ||
69 | static void | |
70 | call(Iterator const& first, Iterator const& last, Attribute& attr) | |
71 | { | |
72 | call(first, last, attr, detail::is_container_of_ranges<Attribute>()); | |
73 | } | |
74 | }; | |
75 | ||
76 | template <typename Attribute, typename Iterator> | |
77 | struct assign_to_attribute_from_iterators< | |
78 | reference_wrapper<Attribute>, Iterator> | |
79 | { | |
80 | static void | |
81 | call(Iterator const& first, Iterator const& last | |
82 | , reference_wrapper<Attribute> attr) | |
83 | { | |
84 | if (traits::is_empty(attr)) | |
85 | attr = Attribute(first, last); | |
86 | else { | |
87 | for (Iterator i = first; i != last; ++i) | |
88 | push_back(attr, *i); | |
89 | } | |
90 | } | |
91 | }; | |
92 | ||
93 | template <typename Attribute, typename Iterator> | |
94 | struct assign_to_attribute_from_iterators< | |
95 | boost::optional<Attribute>, Iterator> | |
96 | { | |
97 | static void | |
98 | call(Iterator const& first, Iterator const& last | |
99 | , boost::optional<Attribute>& attr) | |
100 | { | |
101 | Attribute val; | |
102 | assign_to(first, last, val); | |
103 | attr = val; | |
104 | } | |
105 | }; | |
106 | ||
107 | template <typename Iterator> | |
108 | struct assign_to_attribute_from_iterators< | |
109 | iterator_range<Iterator>, Iterator> | |
110 | { | |
111 | static void | |
112 | call(Iterator const& first, Iterator const& last | |
113 | , iterator_range<Iterator>& attr) | |
114 | { | |
115 | attr = iterator_range<Iterator>(first, last); | |
116 | } | |
117 | }; | |
118 | ||
119 | template <typename Iterator, typename Attribute> | |
120 | inline void | |
121 | assign_to(Iterator const& first, Iterator const& last, Attribute& attr) | |
122 | { | |
123 | assign_to_attribute_from_iterators<Attribute, Iterator>:: | |
124 | call(first, last, attr); | |
125 | } | |
126 | ||
127 | template <typename Iterator> | |
128 | inline void | |
129 | assign_to(Iterator const&, Iterator const&, unused_type) | |
130 | { | |
131 | } | |
132 | ||
133 | /////////////////////////////////////////////////////////////////////////// | |
134 | template <typename T, typename Attribute> | |
135 | void assign_to(T const& val, Attribute& attr); | |
136 | ||
137 | template <typename Attribute, typename T, typename Enable> | |
138 | struct assign_to_attribute_from_value | |
139 | { | |
140 | typedef typename traits::one_element_sequence<Attribute>::type | |
141 | is_one_element_sequence; | |
142 | ||
143 | typedef typename mpl::eval_if< | |
144 | is_one_element_sequence | |
145 | , fusion::result_of::at_c<Attribute, 0> | |
146 | , mpl::identity<Attribute&> | |
147 | >::type type; | |
148 | ||
149 | template <typename T_> | |
150 | static void | |
151 | call(T_ const& val, Attribute& attr, mpl::false_) | |
152 | { | |
153 | attr = static_cast<Attribute>(val); | |
154 | } | |
155 | ||
156 | // This handles the case where the attribute is a single element fusion | |
157 | // sequence. We silently assign to the only element and treat it as the | |
158 | // attribute to parse the results into. | |
159 | template <typename T_> | |
160 | static void | |
161 | call(T_ const& val, Attribute& attr, mpl::true_) | |
162 | { | |
163 | typedef typename fusion::result_of::value_at_c<Attribute, 0>::type | |
164 | element_type; | |
165 | fusion::at_c<0>(attr) = static_cast<element_type>(val); | |
166 | } | |
167 | ||
168 | static void | |
169 | call(T const& val, Attribute& attr) | |
170 | { | |
171 | call(val, attr, is_one_element_sequence()); | |
172 | } | |
173 | }; | |
174 | ||
175 | template <typename Attribute> | |
176 | struct assign_to_attribute_from_value<Attribute, Attribute> | |
177 | { | |
178 | static void | |
179 | call(Attribute const& val, Attribute& attr) | |
180 | { | |
181 | attr = val; | |
182 | } | |
183 | }; | |
184 | ||
185 | template <typename Attribute, typename T> | |
186 | struct assign_to_attribute_from_value<Attribute, reference_wrapper<T> | |
187 | , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> | |
188 | { | |
189 | static void | |
190 | call(reference_wrapper<T> const& val, Attribute& attr) | |
191 | { | |
192 | assign_to(val.get(), attr); | |
193 | } | |
194 | }; | |
195 | ||
196 | template <typename Attribute, typename T> | |
197 | struct assign_to_attribute_from_value<Attribute, boost::optional<T> | |
198 | , typename disable_if<is_same<Attribute, boost::optional<T> > >::type> | |
199 | { | |
200 | static void | |
201 | call(boost::optional<T> const& val, Attribute& attr) | |
202 | { | |
203 | assign_to(val.get(), attr); | |
204 | } | |
205 | }; | |
206 | ||
207 | template <typename Attribute, int N, bool Const, typename T> | |
208 | struct assign_to_attribute_from_value<fusion::extension::adt_attribute_proxy<Attribute, N, Const>, T> | |
209 | { | |
210 | static void | |
211 | call(T const& val, typename fusion::extension::adt_attribute_proxy<Attribute, N, Const>& attr) | |
212 | { | |
213 | attr = val; | |
214 | } | |
215 | }; | |
216 | ||
217 | namespace detail | |
218 | { | |
219 | template <typename A, typename B> | |
220 | struct is_same_size_sequence | |
221 | : mpl::bool_<fusion::result_of::size<A>::value | |
222 | == fusion::result_of::size<B>::value> | |
223 | {}; | |
224 | } | |
225 | ||
226 | template <typename Attribute, typename T> | |
227 | struct assign_to_attribute_from_value<Attribute, T, | |
228 | mpl::and_< | |
229 | fusion::traits::is_sequence<Attribute>, | |
230 | fusion::traits::is_sequence<T>, | |
231 | detail::is_same_size_sequence<Attribute, T> | |
232 | > | |
233 | > | |
234 | { | |
235 | static void | |
236 | call(T const& val, Attribute& attr) | |
237 | { | |
238 | fusion::copy(val, attr); | |
239 | } | |
240 | }; | |
241 | ||
242 | /////////////////////////////////////////////////////////////////////////// | |
243 | template <typename Attribute, typename T, typename Enable> | |
244 | struct assign_to_container_from_value | |
245 | { | |
246 | // T is not a container and not a string | |
247 | template <typename T_> | |
248 | static void call(T_ const& val, Attribute& attr, mpl::false_, mpl::false_) | |
249 | { | |
250 | traits::push_back(attr, val); | |
251 | } | |
252 | ||
253 | // T is a container (but not a string), and T is convertible to the | |
254 | // value_type of the Attribute container | |
255 | template <typename T_> | |
256 | static void | |
257 | append_to_container_not_string(T_ const& val, Attribute& attr, mpl::true_) | |
258 | { | |
259 | traits::push_back(attr, val); | |
260 | } | |
261 | ||
262 | // T is a container (but not a string), generic overload | |
263 | template <typename T_> | |
264 | static void | |
265 | append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_) | |
266 | { | |
267 | typedef typename traits::container_iterator<T_ const>::type | |
268 | iterator_type; | |
269 | ||
270 | iterator_type end = traits::end(val); | |
271 | for (iterator_type i = traits::begin(val); i != end; traits::next(i)) | |
272 | traits::push_back(attr, traits::deref(i)); | |
273 | } | |
274 | ||
275 | // T is a container (but not a string) | |
276 | template <typename T_> | |
277 | static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_) | |
278 | { | |
279 | typedef typename container_value<Attribute>::type value_type; | |
280 | typedef typename is_convertible<T, value_type>::type is_value_type; | |
281 | ||
282 | append_to_container_not_string(val, attr, is_value_type()); | |
283 | } | |
284 | ||
285 | /////////////////////////////////////////////////////////////////////// | |
286 | // T is a string | |
287 | template <typename Iterator> | |
288 | static void append_to_string(Attribute& attr, Iterator begin, Iterator end) | |
289 | { | |
290 | for (Iterator i = begin; i != end; ++i) | |
291 | traits::push_back(attr, *i); | |
292 | } | |
293 | ||
294 | // T is string, but not convertible to value_type of container | |
295 | template <typename T_> | |
296 | static void append_to_container(T_ const& val, Attribute& attr, mpl::false_) | |
297 | { | |
298 | typedef typename char_type_of<T_>::type char_type; | |
299 | ||
300 | append_to_string(attr, traits::get_begin<char_type>(val) | |
301 | , traits::get_end<char_type>(val)); | |
302 | } | |
303 | ||
304 | // T is string, and convertible to value_type of container | |
305 | template <typename T_> | |
306 | static void append_to_container(T_ const& val, Attribute& attr, mpl::true_) | |
307 | { | |
308 | traits::push_back(attr, val); | |
309 | } | |
310 | ||
311 | template <typename T_, typename Pred> | |
312 | static void call(T_ const& val, Attribute& attr, Pred, mpl::true_) | |
313 | { | |
314 | typedef typename container_value<Attribute>::type value_type; | |
315 | typedef typename is_convertible<T, value_type>::type is_value_type; | |
316 | ||
317 | append_to_container(val, attr, is_value_type()); | |
318 | } | |
319 | ||
320 | /////////////////////////////////////////////////////////////////////// | |
321 | static void call(T const& val, Attribute& attr) | |
322 | { | |
323 | typedef typename traits::is_container<T>::type is_container; | |
324 | typedef typename traits::is_string<T>::type is_string; | |
325 | ||
326 | call(val, attr, is_container(), is_string()); | |
327 | } | |
328 | }; | |
329 | ||
330 | template <typename Attribute> | |
331 | struct assign_to_container_from_value<Attribute, Attribute> | |
332 | { | |
333 | static void | |
334 | call(Attribute const& val, Attribute& attr) | |
335 | { | |
336 | attr = val; | |
337 | } | |
338 | }; | |
339 | ||
340 | template <typename Attribute, typename T> | |
341 | struct assign_to_container_from_value<Attribute, boost::optional<T> | |
342 | , typename disable_if<is_same<Attribute, boost::optional<T> > >::type> | |
343 | { | |
344 | static void | |
345 | call(boost::optional<T> const& val, Attribute& attr) | |
346 | { | |
347 | assign_to(val.get(), attr); | |
348 | } | |
349 | }; | |
350 | ||
351 | template <typename Attribute, typename T> | |
352 | struct assign_to_container_from_value<Attribute, reference_wrapper<T> | |
353 | , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> | |
354 | { | |
355 | static void | |
356 | call(reference_wrapper<T> const& val, Attribute& attr) | |
357 | { | |
358 | assign_to(val.get(), attr); | |
359 | } | |
360 | }; | |
361 | ||
362 | /////////////////////////////////////////////////////////////////////////// | |
363 | namespace detail | |
364 | { | |
365 | // overload for non-container attributes | |
366 | template <typename T, typename Attribute> | |
367 | inline void | |
368 | assign_to(T const& val, Attribute& attr, mpl::false_) | |
369 | { | |
370 | assign_to_attribute_from_value<Attribute, T>::call(val, attr); | |
371 | } | |
372 | ||
373 | // overload for containers (but not for variants or optionals | |
374 | // holding containers) | |
375 | template <typename T, typename Attribute> | |
376 | inline void | |
377 | assign_to(T const& val, Attribute& attr, mpl::true_) | |
378 | { | |
379 | assign_to_container_from_value<Attribute, T>::call(val, attr); | |
380 | } | |
381 | } | |
382 | ||
383 | template <typename T, typename Attribute> | |
384 | inline void | |
385 | assign_to(T const& val, Attribute& attr) | |
386 | { | |
387 | typedef typename mpl::and_< | |
388 | traits::is_container<Attribute> | |
389 | , traits::not_is_variant<Attribute> | |
390 | , traits::not_is_optional<Attribute> | |
391 | >::type is_not_wrapped_container; | |
392 | ||
393 | detail::assign_to(val, attr, is_not_wrapped_container()); | |
394 | } | |
395 | ||
396 | template <typename T> | |
397 | inline void | |
398 | assign_to(T const&, unused_type) | |
399 | { | |
400 | } | |
401 | }}} | |
402 | ||
403 | #endif |