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_QI_META_CREATE_NOV_21_2009_0432PM)
7 #define BOOST_SPIRIT_QI_META_CREATE_NOV_21_2009_0432PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/qi/domain.hpp>
14 #include <boost/spirit/home/support/common_terminals.hpp>
15 #include <boost/spirit/home/support/auto/meta_create.hpp>
16 
17 #include <boost/utility/enable_if.hpp>
18 #include <boost/variant.hpp>
19 #include <boost/optional.hpp>
20 #include <boost/config.hpp>
21 #include <boost/mpl/and.hpp>
22 #include <boost/mpl/not.hpp>
23 #include <boost/mpl/fold.hpp>
24 #include <boost/mpl/vector.hpp>
25 #include <boost/mpl/push_back.hpp>
26 #include <boost/type_traits/is_same.hpp>
27 #include <boost/fusion/include/as_vector.hpp>
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 namespace boost { namespace spirit { namespace qi
31 {
32     ///////////////////////////////////////////////////////////////////////////
33     // compatible STL containers
34     template <typename Container>
35     struct meta_create_container
36     {
37         typedef make_unary_proto_expr<
38             typename Container::value_type
39           , proto::tag::dereference, qi::domain
40         > make_proto_expr;
41 
42         typedef typename make_proto_expr::type type;
43 
callboost::spirit::qi::meta_create_container44         static type call()
45         {
46             return make_proto_expr::call();
47         }
48     };
49 
50     ///////////////////////////////////////////////////////////////////////////
51     // Fusion sequences
52     template <typename Sequence>
53     struct meta_create_sequence
54     {
55         // create a mpl sequence from the given fusion sequence
56         typedef typename mpl::fold<
57             typename fusion::result_of::as_vector<Sequence>::type
58           , mpl::vector<>, mpl::push_back<mpl::_, mpl::_>
59         >::type sequence_type;
60 
61         typedef make_nary_proto_expr<
62             sequence_type, proto::tag::shift_right, qi::domain
63         > make_proto_expr;
64 
65         typedef typename make_proto_expr::type type;
66 
callboost::spirit::qi::meta_create_sequence67         static type call()
68         {
69             return make_proto_expr::call();
70         }
71     };
72 
73     ///////////////////////////////////////////////////////////////////////////
74     // the default is to use the standard streaming operator unless it's a
75     // STL container or a fusion sequence
76 
77     // The default implementation will be chosen if no predefined mapping of
78     // the data type T to a Qi component is defined.
79     struct no_auto_mapping_exists {};
80 
81     template <typename T, typename Enable = void>
82     struct meta_create_impl : mpl::identity<no_auto_mapping_exists> {};
83 
84     template <typename T>
85     struct meta_create_impl<T
86           , typename enable_if<mpl::and_<
87                 traits::is_container<T>, mpl::not_<traits::is_string<T> > >
88             >::type>
89       : meta_create_container<T> {};
90 
91     template <typename T>
92     struct meta_create_impl<T, typename enable_if<
93                 spirit::detail::is_fusion_sequence_but_not_proto_expr<T>
94             >::type>
95       : meta_create_sequence<T> {};
96 
97     template <typename T, typename Enable = void>
98     struct meta_create : meta_create_impl<T> {};
99 
100     ///////////////////////////////////////////////////////////////////////////
101     // optional
102     template <typename T>
103     struct meta_create<boost::optional<T> >
104     {
105         typedef make_unary_proto_expr<
106             T, proto::tag::negate, qi::domain
107         > make_proto_expr;
108 
109         typedef typename make_proto_expr::type type;
110 
callboost::spirit::qi::meta_create111         static type call()
112         {
113             return make_proto_expr::call();
114         }
115     };
116 
117     ///////////////////////////////////////////////////////////////////////////
118     // alternatives
119     template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
120     struct meta_create<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
121     {
122         typedef make_nary_proto_expr<
123             typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types
124           , proto::tag::bitwise_or, qi::domain
125         > make_proto_expr;
126 
127         typedef typename make_proto_expr::type type;
128 
callboost::spirit::qi::meta_create129         static type call()
130         {
131             return make_proto_expr::call();
132         }
133     };
134 
135     ///////////////////////////////////////////////////////////////////////////
136     // predefined specializations for primitive components
137 
138     // character generator
139     template <>
140     struct meta_create<char>
141     {
142         typedef spirit::standard::char_type type;
callboost::spirit::qi::meta_create143         static type call() { return type(); }
144     };
145     template <>
146     struct meta_create<signed char>
147     {
148         typedef spirit::standard::char_type type;
callboost::spirit::qi::meta_create149         static type call() { return type(); }
150     };
151     template <>
152     struct meta_create<wchar_t>
153     {
154         typedef spirit::standard_wide::char_type type;
callboost::spirit::qi::meta_create155         static type call() { return type(); }
156     };
157 
158     template <>
159     struct meta_create<unsigned char>
160     {
161         typedef spirit::standard::char_type type;
callboost::spirit::qi::meta_create162         static type call() { return type(); }
163     };
164 
165     // boolean generator
166     template <>
167     struct meta_create<bool>
168     {
169         typedef spirit::bool_type type;
callboost::spirit::qi::meta_create170         static type call() { return type(); }
171     };
172 
173     // integral generators
174     template <>
175     struct meta_create<int>
176     {
177         typedef spirit::int_type type;
callboost::spirit::qi::meta_create178         static type call() { return type(); }
179     };
180     template <>
181     struct meta_create<short>
182     {
183         typedef spirit::short_type type;
callboost::spirit::qi::meta_create184         static type call() { return type(); }
185     };
186     template <>
187     struct meta_create<long>
188     {
189         typedef spirit::long_type type;
callboost::spirit::qi::meta_create190         static type call() { return type(); }
191     };
192     template <>
193     struct meta_create<unsigned int>
194     {
195         typedef spirit::uint_type type;
callboost::spirit::qi::meta_create196         static type call() { return type(); }
197     };
198 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
199     template <>
200     struct meta_create<unsigned short>
201     {
202         typedef spirit::ushort_type type;
callboost::spirit::qi::meta_create203         static type call() { return type(); }
204     };
205 #endif
206     template <>
207     struct meta_create<unsigned long>
208     {
209         typedef spirit::ulong_type type;
callboost::spirit::qi::meta_create210         static type call() { return type(); }
211     };
212 
213 #ifdef BOOST_HAS_LONG_LONG
214     template <>
215     struct meta_create<boost::long_long_type>
216     {
217         typedef spirit::long_long_type type;
callboost::spirit::qi::meta_create218         static type call() { return type(); }
219     };
220     template <>
221     struct meta_create<boost::ulong_long_type>
222     {
223         typedef spirit::ulong_long_type type;
callboost::spirit::qi::meta_create224         static type call() { return type(); }
225     };
226 #endif
227 
228     // floating point generators
229     template <>
230     struct meta_create<float>
231     {
232         typedef spirit::float_type type;
callboost::spirit::qi::meta_create233         static type call() { return type(); }
234     };
235     template <>
236     struct meta_create<double>
237     {
238         typedef spirit::double_type type;
callboost::spirit::qi::meta_create239         static type call() { return type(); }
240     };
241     template <>
242     struct meta_create<long double>
243     {
244         typedef spirit::long_double_type type;
callboost::spirit::qi::meta_create245         static type call() { return type(); }
246     };
247 }}}
248 
249 ///////////////////////////////////////////////////////////////////////////////
250 namespace boost { namespace spirit { namespace traits
251 {
252     ///////////////////////////////////////////////////////////////////////////
253     // main customization point for create_parser
254     template <typename T, typename Enable = void>
255     struct create_parser : qi::meta_create<T> {};
256 
257     ///////////////////////////////////////////////////////////////////////////
258     // dispatch this to the Qi related specializations
259     template <typename T>
260     struct meta_create<qi::domain, T>
261       : create_parser<typename spirit::detail::remove_const_ref<T>::type> {};
262 
263     ///////////////////////////////////////////////////////////////////////////
264     // Check whether a valid mapping exits for the given data type to a Qi
265     // component
266     template <typename T>
267     struct meta_create_exists<qi::domain, T>
268       : mpl::not_<is_same<
269             qi::no_auto_mapping_exists
270           , typename meta_create<qi::domain, T>::type
271         > > {};
272 }}}
273 
274 #endif
275