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_META_CREATE_NOV_21_2009_0425PM)
7 #define BOOST_SPIRIT_KARMA_META_CREATE_NOV_21_2009_0425PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/karma/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/not.hpp>
22 #include <boost/mpl/fold.hpp>
23 #include <boost/mpl/vector.hpp>
24 #include <boost/mpl/push_back.hpp>
25 #include <boost/fusion/include/as_vector.hpp>
26 #include <boost/proto/tags.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 
29 ///////////////////////////////////////////////////////////////////////////////
30 namespace boost { namespace spirit { namespace karma
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, karma::domain
40         > make_proto_expr;
41 
42         typedef typename make_proto_expr::type type;
43 
callboost::spirit::karma::meta_create_container44         static type call()
45         {
46             return make_proto_expr::call();
47         }
48     };
49 
50     ///////////////////////////////////////////////////////////////////////////
51     // String types
52     template <typename String>
53     struct meta_create_string
54     {
55         typedef spirit::standard::string_type type;
callboost::spirit::karma::meta_create_string56         static type const call() { return type(); }
57     };
58 
59     template <>
60     struct meta_create_string<wchar_t*>
61     {
62         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string63         static type const call() { return type(); }
64     };
65 
66     template <>
67     struct meta_create_string<wchar_t const*>
68     {
69         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string70         static type const call() { return type(); }
71     };
72 
73     template <int N>
74     struct meta_create_string<wchar_t[N]>
75     {
76         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string77         static type const call() { return type(); }
78     };
79 
80     template <int N>
81     struct meta_create_string<wchar_t const[N]>
82     {
83         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string84         static type const call() { return type(); }
85     };
86 
87     template <int N>
88     struct meta_create_string<wchar_t(&)[N]>
89     {
90         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string91         static type const call() { return type(); }
92     };
93 
94     template <int N>
95     struct meta_create_string<wchar_t const(&)[N]>
96     {
97         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string98         static type const call() { return type(); }
99     };
100 
101     template <typename Traits, typename Allocator>
102     struct meta_create_string<std::basic_string<wchar_t, Traits, Allocator> >
103     {
104         typedef spirit::standard_wide::string_type type;
callboost::spirit::karma::meta_create_string105         static type const call() { return type(); }
106     };
107 
108     ///////////////////////////////////////////////////////////////////////////
109     // Fusion sequences
110     template <typename Sequence>
111     struct meta_create_sequence
112     {
113         // create a mpl sequence from the given fusion sequence
114         typedef typename mpl::fold<
115             typename fusion::result_of::as_vector<Sequence>::type
116           , mpl::vector<>, mpl::push_back<mpl::_, mpl::_>
117         >::type sequence_type;
118 
119         typedef make_nary_proto_expr<
120             sequence_type, proto::tag::shift_left, karma::domain
121         > make_proto_expr;
122 
123         typedef typename make_proto_expr::type type;
124 
callboost::spirit::karma::meta_create_sequence125         static type call()
126         {
127             return make_proto_expr::call();
128         }
129     };
130 
131     ///////////////////////////////////////////////////////////////////////////
132     // the default is to use the standard streaming operator unless it's a
133     // STL container or a fusion sequence
134 
135     // The default implementation will be chosen if no predefined mapping of
136     // the data type T to a Karma component is defined.
137     struct no_auto_mapping_exists {};
138 
139     template <typename T, typename Enable = void>
140     struct meta_create_impl : mpl::identity<no_auto_mapping_exists> {};
141 
142     template <typename T>
143     struct meta_create_impl<T
144           , typename enable_if<
145                 mpl::and_<
146                     traits::is_container<T>
147                   , mpl::not_<traits::is_string<T> >
148                   , mpl::not_<fusion::traits::is_sequence<T> >
149                 > >::type>
150       : meta_create_container<T> {};
151 
152     template <typename T>
153     struct meta_create_impl<T
154           , typename enable_if<traits::is_string<T> >::type>
155       : meta_create_string<T> {};
156 
157     template <typename T>
158     struct meta_create_impl<T, typename enable_if<
159                 spirit::detail::is_fusion_sequence_but_not_proto_expr<T>
160             >::type>
161       : meta_create_sequence<T> {};
162 
163     template <typename T, typename Enable = void>
164     struct meta_create : meta_create_impl<T> {};
165 
166     ///////////////////////////////////////////////////////////////////////////
167     // optional
168     template <typename T>
169     struct meta_create<boost::optional<T> >
170     {
171         typedef make_unary_proto_expr<
172             T, proto::tag::negate, karma::domain
173         > make_proto_expr;
174 
175         typedef typename make_proto_expr::type type;
176 
callboost::spirit::karma::meta_create177         static type call()
178         {
179             return make_proto_expr::call();
180         }
181     };
182 
183     ///////////////////////////////////////////////////////////////////////////
184     // alternatives
185     template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
186     struct meta_create<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
187     {
188         typedef make_nary_proto_expr<
189             typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types
190           , proto::tag::bitwise_or, karma::domain
191         > make_proto_expr;
192 
193         typedef typename make_proto_expr::type type;
194 
callboost::spirit::karma::meta_create195         static type call()
196         {
197             return make_proto_expr::call();
198         }
199     };
200 
201     ///////////////////////////////////////////////////////////////////////////
202     // predefined specializations for primitive components
203 
204     // character generator
205     template <>
206     struct meta_create<char>
207     {
208         typedef spirit::standard::char_type type;
callboost::spirit::karma::meta_create209         static type const call() { return type(); }
210     };
211     template <>
212     struct meta_create<signed char>
213     {
214         typedef spirit::standard::char_type type;
callboost::spirit::karma::meta_create215         static type const call() { return type(); }
216     };
217     template <>
218     struct meta_create<wchar_t>
219     {
220         typedef spirit::standard_wide::char_type type;
callboost::spirit::karma::meta_create221         static type const call() { return type(); }
222     };
223 
224     template <>
225     struct meta_create<unsigned char>
226     {
227         typedef spirit::standard::char_type type;
callboost::spirit::karma::meta_create228         static type const call() { return type(); }
229     };
230 
231     // boolean generator
232     template <>
233     struct meta_create<bool>
234     {
235         typedef spirit::bool_type type;
callboost::spirit::karma::meta_create236         static type call() { return type(); }
237     };
238 
239     // integral generators
240     template <>
241     struct meta_create<int>
242     {
243         typedef spirit::int_type type;
callboost::spirit::karma::meta_create244         static type call() { return type(); }
245     };
246     template <>
247     struct meta_create<short>
248     {
249         typedef spirit::short_type type;
callboost::spirit::karma::meta_create250         static type call() { return type(); }
251     };
252     template <>
253     struct meta_create<long>
254     {
255         typedef spirit::long_type type;
callboost::spirit::karma::meta_create256         static type call() { return type(); }
257     };
258     template <>
259     struct meta_create<unsigned int>
260     {
261         typedef spirit::uint_type type;
callboost::spirit::karma::meta_create262         static type call() { return type(); }
263     };
264 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
265     template <>
266     struct meta_create<unsigned short>
267     {
268         typedef spirit::ushort_type type;
callboost::spirit::karma::meta_create269         static type call() { return type(); }
270     };
271 #endif
272     template <>
273     struct meta_create<unsigned long>
274     {
275         typedef spirit::ulong_type type;
callboost::spirit::karma::meta_create276         static type call() { return type(); }
277     };
278 
279 #ifdef BOOST_HAS_LONG_LONG
280     template <>
281     struct meta_create<boost::long_long_type>
282     {
283         typedef spirit::long_long_type type;
callboost::spirit::karma::meta_create284         static type call() { return type(); }
285     };
286     template <>
287     struct meta_create<boost::ulong_long_type>
288     {
289         typedef spirit::ulong_long_type type;
callboost::spirit::karma::meta_create290         static type call() { return type(); }
291     };
292 #endif
293 
294     // floating point generators
295     template <>
296     struct meta_create<float>
297     {
298         typedef spirit::float_type type;
callboost::spirit::karma::meta_create299         static type call() { return type(); }
300     };
301     template <>
302     struct meta_create<double>
303     {
304         typedef spirit::double_type type;
callboost::spirit::karma::meta_create305         static type call() { return type(); }
306     };
307     template <>
308     struct meta_create<long double>
309     {
310         typedef spirit::long_double_type type;
callboost::spirit::karma::meta_create311         static type call() { return type(); }
312     };
313 }}}
314 
315 ///////////////////////////////////////////////////////////////////////////////
316 namespace boost { namespace spirit { namespace traits
317 {
318     ///////////////////////////////////////////////////////////////////////////
319     // main customization point for create_generator
320     template <typename T, typename Enable = void>
321     struct create_generator : karma::meta_create<T> {};
322 
323     ///////////////////////////////////////////////////////////////////////////
324     // dispatch this to the karma related specializations
325     template <typename T>
326     struct meta_create<karma::domain, T>
327       : create_generator<typename spirit::detail::remove_const_ref<T>::type> {};
328 
329     ///////////////////////////////////////////////////////////////////////////
330     // Check whether a valid mapping exits for the given data type to a Karma
331     // component
332     template <typename T>
333     struct meta_create_exists<karma::domain, T>
334       : mpl::not_<is_same<
335             karma::no_auto_mapping_exists
336           , typename meta_create<karma::domain, T>::type
337         > > {};
338 }}}
339 
340 #endif
341