• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/range_fwd.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
callboost::spirit::traits::assign_to_attribute_from_iterators50         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
callboost::spirit::traits::assign_to_attribute_from_iterators63         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
callboost::spirit::traits::assign_to_attribute_from_iterators70         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
callboost::spirit::traits::assign_to_attribute_from_iterators81         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
callboost::spirit::traits::assign_to_attribute_from_iterators98         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
callboost::spirit::traits::assign_to_attribute_from_iterators112         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
assign_to(Iterator const & first,Iterator const & last,Attribute & attr)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
assign_to(Iterator const &,Iterator const &,unused_type)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
callboost::spirit::traits::assign_to_attribute_from_value151         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
callboost::spirit::traits::assign_to_attribute_from_value161         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
callboost::spirit::traits::assign_to_attribute_from_value169         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
callboost::spirit::traits::assign_to_attribute_from_value179         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
callboost::spirit::traits::assign_to_attribute_from_value190         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
callboost::spirit::traits::assign_to_attribute_from_value201         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
callboost::spirit::traits::assign_to_attribute_from_value211         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
callboost::spirit::traits::assign_to_attribute_from_value236         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_>
callboost::spirit::traits::assign_to_container_from_value248         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
append_to_container_not_stringboost::spirit::traits::assign_to_container_from_value257         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
append_to_container_not_stringboost::spirit::traits::assign_to_container_from_value265         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_>
callboost::spirit::traits::assign_to_container_from_value277         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>
append_to_stringboost::spirit::traits::assign_to_container_from_value288         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_>
append_to_containerboost::spirit::traits::assign_to_container_from_value296         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_>
append_to_containerboost::spirit::traits::assign_to_container_from_value306         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>
callboost::spirit::traits::assign_to_container_from_value312         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         ///////////////////////////////////////////////////////////////////////
callboost::spirit::traits::assign_to_container_from_value321         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
callboost::spirit::traits::assign_to_container_from_value334         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
callboost::spirit::traits::assign_to_container_from_value345         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
callboost::spirit::traits::assign_to_container_from_value356         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
assign_to(T const & val,Attribute & attr,mpl::false_)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
assign_to(T const & val,Attribute & attr,mpl::true_)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
assign_to(T const & val,Attribute & attr)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
assign_to(T const &,unused_type)398     assign_to(T const&, unused_type)
399     {
400     }
401 }}}
402 
403 #endif
404