1 // Copyright (c) 2001-2011 Hartmut Kaiser
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM)
7 #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM
13 #include <boost/spirit/home/support/unused.hpp>
14 #include <boost/spirit/home/support/attributes_fwd.hpp>
15 #include <boost/spirit/home/karma/detail/attributes.hpp>
16 #include <boost/spirit/home/support/container.hpp>
18 #include <boost/ref.hpp>
19 #include <boost/optional.hpp>
21 ///////////////////////////////////////////////////////////////////////////////
22 namespace boost { namespace spirit { namespace traits
24 ///////////////////////////////////////////////////////////////////////////
25 // This file contains attribute extraction utilities. The utilities
26 // provided also accept spirit's unused_type; all no-ops. Compiler
27 // optimization will easily strip these away.
28 ///////////////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////////
33 // extract first and second element of a fusion sequence
36 : add_reference<typename add_const<T>::type>
39 template <typename T, int N>
41 : add_const_ref<typename fusion::result_of::value_at_c<T, N>::type>
45 // This is the default case: the plain attribute values
46 template <typename Attribute, typename Exposed
47 , bool IsOneElemSeq = traits::one_element_sequence<Attribute>::value>
48 struct extract_from_attribute_base
50 typedef Attribute const& type;
52 template <typename Context>
53 static type call(Attribute const& attr, Context&)
59 // This handles the case where the attribute is a single element fusion
60 // sequence. We silently extract the only element and treat it as the
61 // attribute to generate output from.
62 template <typename Attribute, typename Exposed>
63 struct extract_from_attribute_base<Attribute, Exposed, true>
65 typedef typename remove_const<
66 typename remove_reference<
67 typename fusion::result_of::at_c<Attribute, 0>::type
71 typedef typename result_of::extract_from<Exposed, elem_type>::type type;
73 template <typename Context>
74 static type call(Attribute const& attr, Context& ctx)
76 return extract_from<Exposed>(fusion::at_c<0>(attr), ctx);
80 template <typename Attribute, typename Exposed, typename Enable/*= void*/>
81 struct extract_from_attribute
82 : extract_from_attribute_base<Attribute, Exposed>
85 // This handles optional attributes.
86 template <typename Attribute, typename Exposed>
87 struct extract_from_attribute<boost::optional<Attribute>, Exposed>
89 typedef Attribute const& type;
91 template <typename Context>
92 static type call(boost::optional<Attribute> const& attr, Context& ctx)
94 return extract_from<Exposed>(boost::get<Attribute>(attr), ctx);
98 template <typename Attribute, typename Exposed>
99 struct extract_from_attribute<boost::optional<Attribute const>, Exposed>
101 typedef Attribute const& type;
103 template <typename Context>
104 static type call(boost::optional<Attribute const> const& attr, Context& ctx)
106 return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx);
110 // This handles attributes wrapped inside a boost::ref().
111 template <typename Attribute, typename Exposed>
112 struct extract_from_attribute<reference_wrapper<Attribute>, Exposed>
114 typedef Attribute const& type;
116 template <typename Context>
117 static type call(reference_wrapper<Attribute> const& attr, Context& ctx)
119 return extract_from<Exposed>(attr.get(), ctx);
123 ///////////////////////////////////////////////////////////////////////////
124 template <typename Attribute, typename Exposed, typename Enable>
125 struct extract_from_container
127 typedef typename traits::container_value<Attribute const>::type
129 typedef typename is_convertible<value_type, Exposed>::type
130 is_convertible_to_value_type;
132 typedef typename mpl::if_<
134 is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
135 , Exposed const&, Exposed
138 // handle case where container value type is convertible to result type
139 // we simply return the front element of the container
140 template <typename Context, typename Pred>
141 static type call(Attribute const& attr, Context&, mpl::true_, Pred)
143 // return first element from container
144 typedef typename traits::container_iterator<Attribute const>::type
147 iterator_type it = traits::begin(attr);
154 template <typename Iterator>
155 static void append_to_string(Exposed& result, Iterator begin, Iterator end)
157 for (Iterator i = begin; i != end; ++i)
158 push_back(result, *i);
161 template <typename Context>
162 static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_)
164 typedef typename char_type_of<Attribute>::type char_type;
167 append_to_string(result, traits::get_begin<char_type>(attr)
168 , traits::get_end<char_type>(attr));
172 // everything else gets just passed through
173 template <typename Context>
174 static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_)
179 template <typename Context>
180 static type call(Attribute const& attr, Context& ctx)
182 typedef typename mpl::and_<
183 traits::is_string<Exposed>, traits::is_string<Attribute>
184 >::type handle_strings;
186 // return first element from container
187 return call(attr, ctx, is_convertible_to_value_type()
192 template <typename Attribute>
193 struct extract_from_container<Attribute, Attribute>
195 typedef Attribute const& type;
197 template <typename Context>
198 static type call(Attribute const& attr, Context&)
204 ///////////////////////////////////////////////////////////////////////////
207 // overload for non-container attributes
208 template <typename Exposed, typename Attribute, typename Context>
209 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
210 extract_from(Attribute const& attr, Context& ctx, mpl::false_)
212 return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
215 // overload for containers (but not for variants or optionals
216 // holding containers)
217 template <typename Exposed, typename Attribute, typename Context>
218 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
219 extract_from(Attribute const& attr, Context& ctx, mpl::true_)
221 return extract_from_container<Attribute, Exposed>::call(attr, ctx);
225 template <typename Exposed, typename Attribute, typename Context>
226 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
227 extract_from(Attribute const& attr, Context& ctx
228 #if (defined(__GNUC__) && (__GNUC__ < 4)) || \
229 (defined(__APPLE__) && defined(__INTEL_COMPILER))
230 , typename enable_if<traits::not_is_unused<Attribute> >::type*
234 typedef typename mpl::and_<
235 traits::is_container<Attribute>
236 , traits::not_is_variant<Attribute>
237 , traits::not_is_optional<Attribute>
238 >::type is_not_wrapped_container;
240 return detail::extract_from<Exposed>(attr, ctx
241 , is_not_wrapped_container());
244 template <typename Exposed, typename Context>
245 inline unused_type extract_from(unused_type, Context&)
251 ///////////////////////////////////////////////////////////////////////////////
252 namespace boost { namespace spirit { namespace result_of
254 template <typename Exposed, typename Attribute>
258 traits::is_container<Attribute>
259 , traits::not_is_variant<Attribute>
260 , traits::not_is_optional<Attribute> >
261 , traits::extract_from_container<Attribute, Exposed>
262 , traits::extract_from_attribute<Attribute, Exposed> >::type
265 template <typename Exposed>
266 struct extract_from<Exposed, unused_type>
268 typedef unused_type type;
271 template <typename Exposed>
272 struct extract_from<Exposed, unused_type const>
274 typedef unused_type type;