• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //
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)
5 
6 #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM)
7 #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
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>
17 
18 #include <boost/ref.hpp>
19 #include <boost/optional.hpp>
20 
21 ///////////////////////////////////////////////////////////////////////////////
22 namespace boost { namespace spirit { namespace traits
23 {
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     ///////////////////////////////////////////////////////////////////////////
29 
30     namespace detail
31     {
32         ///////////////////////////////////////////////////////////////////////
33         // extract first and second element of a fusion sequence
34         template <typename T>
35         struct add_const_ref
36           : add_reference<typename add_const<T>::type>
37         {};
38 
39         template <typename T, int N>
40         struct value_at_c
41           : add_const_ref<typename fusion::result_of::value_at_c<T, N>::type>
42         {};
43     }
44 
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
49     {
50         typedef Attribute const& type;
51 
52         template <typename Context>
callboost::spirit::traits::extract_from_attribute_base53         static type call(Attribute const& attr, Context&)
54         {
55             return attr;
56         }
57     };
58 
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>
64     {
65         typedef typename remove_const<
66             typename remove_reference<
67                 typename fusion::result_of::at_c<Attribute, 0>::type
68             >::type
69         >::type elem_type;
70 
71         typedef typename result_of::extract_from<Exposed, elem_type>::type type;
72 
73         template <typename Context>
callboost::spirit::traits::extract_from_attribute_base74         static type call(Attribute const& attr, Context& ctx)
75         {
76             return extract_from<Exposed>(fusion::at_c<0>(attr), ctx);
77         }
78     };
79 
80     template <typename Attribute, typename Exposed, typename Enable/*= void*/>
81     struct extract_from_attribute
82       : extract_from_attribute_base<Attribute, Exposed>
83     {};
84 
85     // This handles optional attributes.
86     template <typename Attribute, typename Exposed>
87     struct extract_from_attribute<boost::optional<Attribute>, Exposed>
88     {
89         typedef Attribute const& type;
90 
91         template <typename Context>
callboost::spirit::traits::extract_from_attribute92         static type call(boost::optional<Attribute> const& attr, Context& ctx)
93         {
94             return extract_from<Exposed>(boost::get<Attribute>(attr), ctx);
95         }
96     };
97 
98     template <typename Attribute, typename Exposed>
99     struct extract_from_attribute<boost::optional<Attribute const>, Exposed>
100     {
101         typedef Attribute const& type;
102 
103         template <typename Context>
callboost::spirit::traits::extract_from_attribute104         static type call(boost::optional<Attribute const> const& attr, Context& ctx)
105         {
106             return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx);
107         }
108     };
109 
110     // This handles attributes wrapped inside a boost::ref().
111     template <typename Attribute, typename Exposed>
112     struct extract_from_attribute<reference_wrapper<Attribute>, Exposed>
113     {
114         typedef Attribute const& type;
115 
116         template <typename Context>
callboost::spirit::traits::extract_from_attribute117         static type call(reference_wrapper<Attribute> const& attr, Context& ctx)
118         {
119             return extract_from<Exposed>(attr.get(), ctx);
120         }
121     };
122 
123     ///////////////////////////////////////////////////////////////////////////
124     template <typename Attribute, typename Exposed, typename Enable>
125     struct extract_from_container
126     {
127         typedef typename traits::container_value<Attribute const>::type
128             value_type;
129         typedef typename is_convertible<value_type, Exposed>::type
130             is_convertible_to_value_type;
131 
132         typedef typename mpl::if_<
133            mpl::or_<
134                 is_same<value_type, Exposed>, is_same<Attribute, Exposed> >
135           , Exposed const&, Exposed
136         >::type type;
137 
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>
callboost::spirit::traits::extract_from_container141         static type call(Attribute const& attr, Context&, mpl::true_, Pred)
142         {
143             // return first element from container
144             typedef typename traits::container_iterator<Attribute const>::type
145                 iterator_type;
146 
147             iterator_type it = traits::begin(attr);
148             type result = *it;
149             ++it;
150             return result;
151         }
152 
153         // handle strings
154         template <typename Iterator>
append_to_stringboost::spirit::traits::extract_from_container155         static void append_to_string(Exposed& result, Iterator begin, Iterator end)
156         {
157             for (Iterator i = begin; i != end; ++i)
158                 push_back(result, *i);
159         }
160 
161         template <typename Context>
callboost::spirit::traits::extract_from_container162         static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_)
163         {
164             typedef typename char_type_of<Attribute>::type char_type;
165 
166             Exposed result;
167             append_to_string(result, traits::get_begin<char_type>(attr)
168               , traits::get_end<char_type>(attr));
169             return result;
170         }
171 
172         // everything else gets just passed through
173         template <typename Context>
callboost::spirit::traits::extract_from_container174         static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_)
175         {
176             return type(attr);
177         }
178 
179         template <typename Context>
callboost::spirit::traits::extract_from_container180         static type call(Attribute const& attr, Context& ctx)
181         {
182             typedef typename mpl::and_<
183                 traits::is_string<Exposed>, traits::is_string<Attribute>
184             >::type handle_strings;
185 
186             // return first element from container
187             return call(attr, ctx, is_convertible_to_value_type()
188               , handle_strings());
189         }
190     };
191 
192     template <typename Attribute>
193     struct extract_from_container<Attribute, Attribute>
194     {
195         typedef Attribute const& type;
196 
197         template <typename Context>
callboost::spirit::traits::extract_from_container198         static type call(Attribute const& attr, Context&)
199         {
200             return attr;
201         }
202     };
203 
204     ///////////////////////////////////////////////////////////////////////////
205     namespace detail
206     {
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
extract_from(Attribute const & attr,Context & ctx,mpl::false_)210         extract_from(Attribute const& attr, Context& ctx, mpl::false_)
211         {
212             return extract_from_attribute<Attribute, Exposed>::call(attr, ctx);
213         }
214 
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
extract_from(Attribute const & attr,Context & ctx,mpl::true_)219         extract_from(Attribute const& attr, Context& ctx, mpl::true_)
220         {
221             return extract_from_container<Attribute, Exposed>::call(attr, ctx);
222         }
223     }
224 
225     template <typename Exposed, typename Attribute, typename Context>
226     inline typename spirit::result_of::extract_from<Exposed, Attribute>::type
extract_from(Attribute const & attr,Context & ctx,typename enable_if<traits::not_is_unused<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*
231 #endif
232     )
233     {
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;
239 
240         return detail::extract_from<Exposed>(attr, ctx
241           , is_not_wrapped_container());
242     }
243 
244     template <typename Exposed, typename Context>
extract_from(unused_type,Context &)245     inline unused_type extract_from(unused_type, Context&)
246     {
247         return unused;
248     }
249 }}}
250 
251 ///////////////////////////////////////////////////////////////////////////////
252 namespace boost { namespace spirit { namespace result_of
253 {
254     template <typename Exposed, typename Attribute>
255     struct extract_from
256       : mpl::if_<
257             mpl::and_<
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
263     {};
264 
265     template <typename Exposed>
266     struct extract_from<Exposed, unused_type>
267     {
268         typedef unused_type type;
269     };
270 
271     template <typename Exposed>
272     struct extract_from<Exposed, unused_type const>
273     {
274         typedef unused_type type;
275     };
276 }}}
277 
278 #endif
279