Chris@16
|
1 // Copyright (c) 2001-2011 Hartmut Kaiser
|
Chris@16
|
2 //
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM)
|
Chris@16
|
7 #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM
|
Chris@16
|
8
|
Chris@16
|
9 #if defined(_MSC_VER)
|
Chris@16
|
10 #pragma once
|
Chris@16
|
11 #endif
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/spirit/include/phoenix_core.hpp>
|
Chris@16
|
14 #include <boost/spirit/home/support/unused.hpp>
|
Chris@16
|
15 #include <boost/spirit/home/support/attributes_fwd.hpp>
|
Chris@16
|
16 #include <boost/spirit/home/karma/detail/attributes.hpp>
|
Chris@16
|
17 #include <boost/spirit/home/support/container.hpp>
|
Chris@16
|
18
|
Chris@16
|
19 #include <boost/ref.hpp>
|
Chris@16
|
20 #include <boost/optional.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
23 namespace boost { namespace spirit { namespace traits
|
Chris@16
|
24 {
|
Chris@16
|
25 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
26 // This file contains attribute extraction utilities. The utilities
|
Chris@16
|
27 // provided also accept spirit's unused_type; all no-ops. Compiler
|
Chris@16
|
28 // optimization will easily strip these away.
|
Chris@16
|
29 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
30
|
Chris@16
|
31 namespace detail
|
Chris@16
|
32 {
|
Chris@16
|
33 ///////////////////////////////////////////////////////////////////////
|
Chris@16
|
34 // extract first and second element of a fusion sequence
|
Chris@16
|
35 template <typename T>
|
Chris@16
|
36 struct add_const_ref
|
Chris@16
|
37 : add_reference<typename add_const<T>::type>
|
Chris@16
|
38 {};
|
Chris@16
|
39
|
Chris@16
|
40 template <typename T, int N>
|
Chris@16
|
41 struct value_at_c
|
Chris@16
|
42 : add_const_ref<typename fusion::result_of::value_at_c<T, N>::type>
|
Chris@16
|
43 {};
|
Chris@16
|
44 }
|
Chris@16
|
45
|
Chris@16
|
46 // This is the default case: the plain attribute values
|
Chris@16
|
47 template <typename Attribute, typename Exposed, typename Enable/*= void*/>
|
Chris@16
|
48 struct extract_from_attribute
|
Chris@16
|
49 {
|
Chris@16
|
50 typedef typename traits::one_element_sequence<Attribute>::type
|
Chris@16
|
51 is_one_element_sequence;
|
Chris@16
|
52
|
Chris@16
|
53 typedef typename mpl::eval_if<
|
Chris@16
|
54 is_one_element_sequence
|
Chris@16
|
55 , detail::value_at_c<Attribute, 0>
|
Chris@16
|
56 , mpl::identity<Attribute const&>
|
Chris@16
|
57 >::type type;
|
Chris@16
|
58
|
Chris@16
|
59 template <typename Context>
|
Chris@16
|
60 static type call(Attribute const& attr, Context&, mpl::false_)
|
Chris@16
|
61 {
|
Chris@16
|
62 return attr;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 // This handles the case where the attribute is a single element fusion
|
Chris@16
|
66 // sequence. We silently extract the only element and treat it as the
|
Chris@16
|
67 // attribute to generate output from.
|
Chris@16
|
68 template <typename Context>
|
Chris@16
|
69 static type call(Attribute const& attr, Context& ctx, mpl::true_)
|
Chris@16
|
70 {
|
Chris@16
|
71 return extract_from<Exposed>(fusion::at_c<0>(attr), ctx);
|
Chris@16
|
72 }
|
Chris@16
|
73
|
Chris@16
|
74 template <typename Context>
|
Chris@16
|
75 static type call(Attribute const& attr, Context& ctx)
|
Chris@16
|
76 {
|
Chris@16
|
77 return call(attr, ctx, is_one_element_sequence());
|
Chris@16
|
78 }
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81 // This handles optional attributes.
|
Chris@16
|
82 template <typename Attribute, typename Exposed>
|
Chris@16
|
83 struct extract_from_attribute<boost::optional<Attribute>, Exposed>
|
Chris@16
|
84 {
|
Chris@16
|
85 typedef Attribute const& type;
|
Chris@16
|
86
|
Chris@16
|
87 template <typename Context>
|
Chris@16
|
88 static type call(boost::optional<Attribute> const& attr, Context& ctx)
|
Chris@16
|
89 {
|
Chris@16
|
90 return extract_from<Exposed>(boost::get<Attribute>(attr), ctx);
|
Chris@16
|
91 }
|
Chris@16
|
92 };
|
Chris@16
|
93
|
Chris@16
|
94 template <typename Attribute, typename Exposed>
|
Chris@16
|
95 struct extract_from_attribute<boost::optional<Attribute const>, Exposed>
|
Chris@16
|
96 {
|
Chris@16
|
97 typedef Attribute const& type;
|
Chris@16
|
98
|
Chris@16
|
99 template <typename Context>
|
Chris@16
|
100 static type call(boost::optional<Attribute const> const& attr, Context& ctx)
|
Chris@16
|
101 {
|
Chris@16
|
102 return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx);
|
Chris@16
|
103 }
|
Chris@16
|
104 };
|
Chris@16
|
105
|
Chris@16
|
106 // This handles attributes wrapped inside a boost::ref().
|
Chris@16
|
107 template <typename Attribute, typename Exposed>
|
Chris@16
|
108 struct extract_from_attribute<reference_wrapper<Attribute>, Exposed>
|
Chris@16
|
109 {
|
Chris@16
|
110 typedef Attribute const& type;
|
Chris@16
|
111
|
Chris@16
|
112 template <typename Context>
|
Chris@16
|
113 static type call(reference_wrapper<Attribute> const& attr, Context& ctx)
|
Chris@16
|
114 {
|
Chris@16
|
115 return extract_from<Exposed>(attr.get(), ctx);
|
Chris@16
|
116 }
|
Chris@16
|
117 };
|
Chris@16
|
118
|
Chris@16
|
119 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
120 template <typename Attribute, typename Exposed, typename Enable>
|
Chris@16
|
121 struct extract_from_container
|
Chris@16
|
122 {
|
Chris@16
|
123 typedef typename traits::container_value<Attribute const>::type
|
Chris@16
|
124 value_type;
|
Chris@16
|
125 typedef typename is_convertible<value_type, Exposed>::type
|
Chris@16
|
126 is_convertible_to_value_type;
|
Chris@16
|
127
|
Chris@16
|
128 typedef typename mpl::if_<
|
Chris@16
|
129 mpl::or_<
|
Chris@16
|
130 is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
|
Chris@16
|
131 , Exposed const&, Exposed
|
Chris@16
|
132 >::type type;
|
Chris@16
|
133
|
Chris@16
|
134 // handle case where container value type is convertible to result type
|
Chris@16
|
135 // we simply return the front element of the container
|
Chris@16
|
136 template <typename Context, typename Pred>
|
Chris@16
|
137 static type call(Attribute const& attr, Context&, mpl::true_, Pred)
|
Chris@16
|
138 {
|
Chris@16
|
139 // return first element from container
|
Chris@16
|
140 typedef typename traits::container_iterator<Attribute const>::type
|
Chris@16
|
141 iterator_type;
|
Chris@16
|
142
|
Chris@16
|
143 iterator_type it = traits::begin(attr);
|
Chris@16
|
144 type result = *it;
|
Chris@16
|
145 ++it;
|
Chris@16
|
146 return result;
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 // handle strings
|
Chris@16
|
150 template <typename Iterator>
|
Chris@16
|
151 static void append_to_string(Exposed& result, Iterator begin, Iterator end)
|
Chris@16
|
152 {
|
Chris@16
|
153 for (Iterator i = begin; i != end; ++i)
|
Chris@16
|
154 push_back(result, *i);
|
Chris@16
|
155 }
|
Chris@16
|
156
|
Chris@16
|
157 template <typename Context>
|
Chris@16
|
158 static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_)
|
Chris@16
|
159 {
|
Chris@16
|
160 typedef typename char_type_of<Attribute>::type char_type;
|
Chris@16
|
161
|
Chris@16
|
162 Exposed result;
|
Chris@16
|
163 append_to_string(result, traits::get_begin<char_type>(attr)
|
Chris@16
|
164 , traits::get_end<char_type>(attr));
|
Chris@16
|
165 return result;
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 // everything else gets just passed through
|
Chris@16
|
169 template <typename Context>
|
Chris@16
|
170 static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_)
|
Chris@16
|
171 {
|
Chris@16
|
172 return type(attr);
|
Chris@16
|
173 }
|
Chris@16
|
174
|
Chris@16
|
175 template <typename Context>
|
Chris@16
|
176 static type call(Attribute const& attr, Context& ctx)
|
Chris@16
|
177 {
|
Chris@16
|
178 typedef typename mpl::and_<
|
Chris@16
|
179 traits::is_string<Exposed>, traits::is_string<Attribute>
|
Chris@16
|
180 >::type handle_strings;
|
Chris@16
|
181
|
Chris@16
|
182 // return first element from container
|
Chris@16
|
183 return call(attr, ctx, is_convertible_to_value_type()
|
Chris@16
|
184 , handle_strings());
|
Chris@16
|
185 }
|
Chris@16
|
186 };
|
Chris@16
|
187
|
Chris@16
|
188 template <typename Attribute>
|
Chris@16
|
189 struct extract_from_container<Attribute, Attribute>
|
Chris@16
|
190 {
|
Chris@16
|
191 typedef Attribute const& type;
|
Chris@16
|
192
|
Chris@16
|
193 template <typename Context>
|
Chris@16
|
194 static type call(Attribute const& attr, Context&)
|
Chris@16
|
195 {
|
Chris@16
|
196 return attr;
|
Chris@16
|
197 }
|
Chris@16
|
198 };
|
Chris@16
|
199
|
Chris@16
|
200 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
201 namespace detail
|
Chris@16
|
202 {
|
Chris@16
|
203 // overload for non-container attributes
|
Chris@16
|
204 template <typename Exposed, typename Attribute, typename Context>
|
Chris@16
|
205 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
Chris@16
|
206 extract_from(Attribute const& attr, Context& ctx, mpl::false_)
|
Chris@16
|
207 {
|
Chris@16
|
208 return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 // overload for containers (but not for variants or optionals
|
Chris@16
|
212 // holding containers)
|
Chris@16
|
213 template <typename Exposed, typename Attribute, typename Context>
|
Chris@16
|
214 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
Chris@16
|
215 extract_from(Attribute const& attr, Context& ctx, mpl::true_)
|
Chris@16
|
216 {
|
Chris@16
|
217 return extract_from_container<Attribute, Exposed>::call(attr, ctx);
|
Chris@16
|
218 }
|
Chris@16
|
219 }
|
Chris@16
|
220
|
Chris@16
|
221 template <typename Exposed, typename Attribute, typename Context>
|
Chris@16
|
222 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
|
Chris@16
|
223 extract_from(Attribute const& attr, Context& ctx
|
Chris@16
|
224 #if (defined(__GNUC__) && (__GNUC__ < 4)) || \
|
Chris@16
|
225 (defined(__APPLE__) && defined(__INTEL_COMPILER))
|
Chris@16
|
226 , typename enable_if<traits::not_is_unused<Attribute> >::type*
|
Chris@16
|
227 #endif
|
Chris@16
|
228 )
|
Chris@16
|
229 {
|
Chris@16
|
230 typedef typename mpl::and_<
|
Chris@16
|
231 traits::is_container<Attribute>
|
Chris@16
|
232 , traits::not_is_variant<Attribute>
|
Chris@16
|
233 , traits::not_is_optional<Attribute>
|
Chris@16
|
234 >::type is_not_wrapped_container;
|
Chris@16
|
235
|
Chris@16
|
236 return detail::extract_from<Exposed>(attr, ctx
|
Chris@16
|
237 , is_not_wrapped_container());
|
Chris@16
|
238 }
|
Chris@16
|
239
|
Chris@16
|
240 template <typename Exposed, typename Context>
|
Chris@16
|
241 inline unused_type extract_from(unused_type, Context&)
|
Chris@16
|
242 {
|
Chris@16
|
243 return unused;
|
Chris@16
|
244 }
|
Chris@16
|
245 }}}
|
Chris@16
|
246
|
Chris@16
|
247 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
248 namespace boost { namespace spirit { namespace result_of
|
Chris@16
|
249 {
|
Chris@16
|
250 template <typename Exposed, typename Attribute>
|
Chris@16
|
251 struct extract_from
|
Chris@16
|
252 : mpl::if_<
|
Chris@16
|
253 mpl::and_<
|
Chris@16
|
254 traits::is_container<Attribute>
|
Chris@16
|
255 , traits::not_is_variant<Attribute>
|
Chris@16
|
256 , traits::not_is_optional<Attribute> >
|
Chris@16
|
257 , traits::extract_from_container<Attribute, Exposed>
|
Chris@16
|
258 , traits::extract_from_attribute<Attribute, Exposed> >::type
|
Chris@16
|
259 {};
|
Chris@16
|
260
|
Chris@16
|
261 template <typename Exposed>
|
Chris@16
|
262 struct extract_from<Exposed, unused_type>
|
Chris@16
|
263 {
|
Chris@16
|
264 typedef unused_type type;
|
Chris@16
|
265 };
|
Chris@16
|
266
|
Chris@16
|
267 template <typename Exposed>
|
Chris@16
|
268 struct extract_from<Exposed, unused_type const>
|
Chris@16
|
269 {
|
Chris@16
|
270 typedef unused_type type;
|
Chris@16
|
271 };
|
Chris@16
|
272 }}}
|
Chris@16
|
273
|
Chris@16
|
274 #endif
|