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