• 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_REAL_FEB_26_2007_0512PM)
7 #define BOOST_SPIRIT_KARMA_REAL_FEB_26_2007_0512PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/config/no_tr1/cmath.hpp>
14 #include <boost/config.hpp>
15 #include <boost/mpl/bool.hpp>
16 #include <boost/utility/enable_if.hpp>
17 #include <boost/spirit/home/support/common_terminals.hpp>
18 #include <boost/spirit/home/support/string_traits.hpp>
19 #include <boost/spirit/home/support/numeric_traits.hpp>
20 #include <boost/spirit/home/support/info.hpp>
21 #include <boost/spirit/home/support/char_class.hpp>
22 #include <boost/spirit/home/support/container.hpp>
23 #include <boost/spirit/home/support/detail/get_encoding.hpp>
24 #include <boost/spirit/home/karma/meta_compiler.hpp>
25 #include <boost/spirit/home/karma/char.hpp>
26 #include <boost/spirit/home/karma/delimit_out.hpp>
27 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
28 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
29 #include <boost/spirit/home/karma/detail/extract_from.hpp>
30 #include <boost/spirit/home/karma/detail/enable_lit.hpp>
31 #include <boost/spirit/home/karma/domain.hpp>
32 #include <boost/spirit/home/karma/numeric/real_policies.hpp>
33 #include <boost/spirit/home/karma/numeric/detail/real_utils.hpp>
34 #include <boost/fusion/include/at.hpp>
35 #include <boost/fusion/include/value_at.hpp>
36 #include <boost/fusion/include/vector.hpp>
37 
38 namespace boost { namespace spirit
39 {
40     namespace karma
41     {
42         ///////////////////////////////////////////////////////////////////////
43         // forward declaration only
44         template <typename T>
45         struct real_policies;
46 
47         ///////////////////////////////////////////////////////////////////////
48         // This is the class that the user can instantiate directly in
49         // order to create a customized real generator
50         template <typename T = double, typename Policies = real_policies<T> >
51         struct real_generator
52           : spirit::terminal<tag::stateful_tag<Policies, tag::double_, T> >
53         {
54             typedef tag::stateful_tag<Policies, tag::double_, T> tag_type;
55 
real_generatorboost::spirit::karma::real_generator56             real_generator() {}
real_generatorboost::spirit::karma::real_generator57             real_generator(Policies const& p)
58               : spirit::terminal<tag_type>(p) {}
59         };
60     }
61 
62     ///////////////////////////////////////////////////////////////////////////
63     // Enablers
64     ///////////////////////////////////////////////////////////////////////////
65     template <>
66     struct use_terminal<karma::domain, tag::float_>       // enables float_
67       : mpl::true_ {};
68 
69     template <>
70     struct use_terminal<karma::domain, tag::double_>      // enables double_
71       : mpl::true_ {};
72 
73     template <>
74     struct use_terminal<karma::domain, tag::long_double>  // enables long_double
75       : mpl::true_ {};
76 
77     ///////////////////////////////////////////////////////////////////////////
78     template <>
79     struct use_terminal<karma::domain, float>             // enables lit(1.0f)
80       : mpl::true_ {};
81 
82     template <>
83     struct use_terminal<karma::domain, double>            // enables lit(1.0)
84       : mpl::true_ {};
85 
86     template <>
87     struct use_terminal<karma::domain, long double>       // enables lit(1.0l)
88       : mpl::true_ {};
89 
90     ///////////////////////////////////////////////////////////////////////////
91     template <typename A0>
92     struct use_terminal<karma::domain                   // enables float_(...)
93       , terminal_ex<tag::float_, fusion::vector1<A0> >
94     > : mpl::true_ {};
95 
96     template <typename A0>
97     struct use_terminal<karma::domain                   // enables double_(...)
98       , terminal_ex<tag::double_, fusion::vector1<A0> >
99     > : mpl::true_ {};
100 
101     template <typename A0>
102     struct use_terminal<karma::domain                   // enables long_double(...)
103       , terminal_ex<tag::long_double, fusion::vector1<A0> >
104     > : mpl::true_ {};
105 
106     // lazy float_(...), double_(...), long_double(...)
107     template <>
108     struct use_lazy_terminal<karma::domain, tag::float_, 1>
109       : mpl::true_ {};
110 
111     template <>
112     struct use_lazy_terminal<karma::domain, tag::double_, 1>
113       : mpl::true_ {};
114 
115     template <>
116     struct use_lazy_terminal<karma::domain, tag::long_double, 1>
117       : mpl::true_ {};
118 
119     ///////////////////////////////////////////////////////////////////////////
120     // enables custom real generator
121     template <typename T, typename Policies>
122     struct use_terminal<karma::domain
123           , tag::stateful_tag<Policies, tag::double_, T> >
124       : mpl::true_ {};
125 
126     template <typename T, typename Policies, typename A0>
127     struct use_terminal<karma::domain
128           , terminal_ex<tag::stateful_tag<Policies, tag::double_, T>
129           , fusion::vector1<A0> > >
130       : mpl::true_ {};
131 
132     // enables *lazy* custom real generator
133     template <typename T, typename Policies>
134     struct use_lazy_terminal<
135         karma::domain
136       , tag::stateful_tag<Policies, tag::double_, T>
137       , 1 // arity
138     > : mpl::true_ {};
139 
140     // enables lit(double)
141     template <typename A0>
142     struct use_terminal<karma::domain
143           , terminal_ex<tag::lit, fusion::vector1<A0> >
144           , typename enable_if<traits::is_real<A0> >::type>
145       : mpl::true_ {};
146 }}
147 
148 ///////////////////////////////////////////////////////////////////////////////
149 namespace boost { namespace spirit { namespace karma
150 {
151 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
152     using spirit::float_;
153     using spirit::double_;
154     using spirit::long_double;
155 #endif
156 
157     using spirit::float_type;
158     using spirit::double_type;
159     using spirit::long_double_type;
160 
161     ///////////////////////////////////////////////////////////////////////////
162     //  This specialization is used for real generators not having a direct
163     //  initializer: float_, double_ etc. These generators must be used in
164     //  conjunction with an attribute.
165     ///////////////////////////////////////////////////////////////////////////
166     template <
167         typename T, typename Policies, typename CharEncoding, typename Tag>
168     struct any_real_generator
169       : primitive_generator<any_real_generator<T, Policies, CharEncoding, Tag> >
170     {
171         typedef typename Policies::properties properties;
172 
173         template <typename Context, typename Unused>
174         struct attribute
175         {
176             typedef T type;
177         };
178 
any_real_generatorboost::spirit::karma::any_real_generator179         any_real_generator(Policies const& policies = Policies())
180           : p_(policies) {}
181 
182         // double_/float_/etc. has an attached attribute
183         template <typename OutputIterator, typename Context, typename Delimiter
184           , typename Attribute>
generateboost::spirit::karma::any_real_generator185         bool generate(OutputIterator& sink, Context& context
186           , Delimiter const& d, Attribute const& attr) const
187         {
188             if (!traits::has_optional_value(attr))
189                 return false;       // fail if it's an uninitialized optional
190 
191             typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type;
192             return inserter_type::call(sink, traits::extract_from<T>(attr, context), p_) &&
193                    karma::delimit_out(sink, d);    // always do post-delimiting
194         }
195 
196         // this double_/float_/etc. has no attribute attached, it needs to have
197         // been initialized from a direct literal
198         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::any_real_generator199         static bool generate(OutputIterator&, Context&, Delimiter const&
200           , unused_type)
201         {
202             // It is not possible (doesn't make sense) to use numeric generators
203             // without providing any attribute, as the generator doesn't 'know'
204             // what to output. The following assertion fires if this situation
205             // is detected in your code.
206             BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, real_not_usable_without_attribute, ());
207             return false;
208         }
209 
210         template <typename Context>
whatboost::spirit::karma::any_real_generator211         static info what(Context const& /*context*/)
212         {
213             return info("real");
214         }
215 
216         Policies p_;
217     };
218 
219     ///////////////////////////////////////////////////////////////////////////
220     //  This specialization is used for real generators having a direct
221     //  initializer: float_(10.), double_(20.) etc.
222     ///////////////////////////////////////////////////////////////////////////
223     template <
224         typename T, typename Policies, typename CharEncoding, typename Tag
225       , bool no_attribute>
226     struct literal_real_generator
227       : primitive_generator<literal_real_generator<T, Policies, CharEncoding
228           , Tag, no_attribute> >
229     {
230         typedef typename Policies::properties properties;
231 
232         template <typename Context, typename Unused = unused_type>
233         struct attribute
234           : mpl::if_c<no_attribute, unused_type, T>
235         {};
236 
literal_real_generatorboost::spirit::karma::literal_real_generator237         literal_real_generator(typename add_const<T>::type n
238               , Policies const& policies = Policies())
239           : n_(n), p_(policies) {}
240 
241         // A double_(1.0) which additionally has an associated attribute emits
242         // its immediate literal only if it matches the attribute, otherwise
243         // it fails.
244         template <typename OutputIterator, typename Context, typename Delimiter
245           , typename Attribute>
generateboost::spirit::karma::literal_real_generator246         bool generate(OutputIterator& sink, Context& context
247           , Delimiter const& d, Attribute const& attr) const
248         {
249             typedef typename attribute<Context>::type attribute_type;
250             if (!traits::has_optional_value(attr) ||
251                 n_ != traits::extract_from<attribute_type>(attr, context))
252             {
253                 return false;
254             }
255 
256             typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type;
257             return inserter_type::call(sink, n_, p_) &&
258                    karma::delimit_out(sink, d);    // always do post-delimiting
259         }
260 
261         // A double_(1.0) without any associated attribute just emits its
262         // immediate literal
263         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::literal_real_generator264         bool generate(OutputIterator& sink, Context&, Delimiter const& d
265           , unused_type) const
266         {
267             typedef real_inserter<T, Policies, CharEncoding, Tag> inserter_type;
268             return inserter_type::call(sink, n_, p_) &&
269                    karma::delimit_out(sink, d);    // always do post-delimiting
270         }
271 
272         template <typename Context>
whatboost::spirit::karma::literal_real_generator273         static info what(Context const& /*context*/)
274         {
275             return info("real");
276         }
277 
278         T n_;
279         Policies p_;
280     };
281 
282     ///////////////////////////////////////////////////////////////////////////
283     // Generator generators: make_xxx function (objects)
284     ///////////////////////////////////////////////////////////////////////////
285     namespace detail
286     {
287         template <typename T, typename Modifiers
288           , typename Policies = real_policies<T> >
289         struct make_real
290         {
291             static bool const lower =
292                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
293             static bool const upper =
294                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
295 
296             typedef any_real_generator<
297                 T, Policies
298               , typename spirit::detail::get_encoding_with_case<
299                     Modifiers, unused_type, lower || upper>::type
300               , typename detail::get_casetag<Modifiers, lower || upper>::type
301             > result_type;
302 
303             template <typename Terminal>
operator ()boost::spirit::karma::detail::make_real304             result_type operator()(Terminal const& term, unused_type) const
305             {
306                 typedef tag::stateful_tag<Policies, tag::double_, T> tag_type;
307                 using spirit::detail::get_stateful_data;
308                 return result_type(get_stateful_data<tag_type>::call(term));
309             }
310         };
311     }
312 
313     template <typename Modifiers>
314     struct make_primitive<tag::float_, Modifiers>
315       : detail::make_real<float, Modifiers> {};
316 
317     template <typename Modifiers>
318     struct make_primitive<tag::double_, Modifiers>
319       : detail::make_real<double, Modifiers> {};
320 
321     template <typename Modifiers>
322     struct make_primitive<tag::long_double, Modifiers>
323       : detail::make_real<long double, Modifiers> {};
324 
325     ///////////////////////////////////////////////////////////////////////////
326     template <typename T, typename Policies, typename Modifiers>
327     struct make_primitive<
328             tag::stateful_tag<Policies, tag::double_, T>, Modifiers>
329       : detail::make_real<typename remove_const<T>::type
330           , Modifiers, Policies> {};
331 
332     ///////////////////////////////////////////////////////////////////////////
333     namespace detail
334     {
335         template <typename T, typename Modifiers
336           , typename Policies = real_policies<T> >
337         struct make_real_direct
338         {
339             static bool const lower =
340                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
341             static bool const upper =
342                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
343 
344             typedef literal_real_generator<
345                 T, Policies
346               , typename spirit::detail::get_encoding_with_case<
347                     Modifiers, unused_type, lower || upper>::type
348               , typename detail::get_casetag<Modifiers, lower || upper>::type
349               , false
350             > result_type;
351 
352             template <typename Terminal>
operator ()boost::spirit::karma::detail::make_real_direct353             result_type operator()(Terminal const& term, unused_type) const
354             {
355                 typedef tag::stateful_tag<Policies, tag::double_, T> tag_type;
356                 using spirit::detail::get_stateful_data;
357                 return result_type(T(fusion::at_c<0>(term.args))
358                   , get_stateful_data<tag_type>::call(term.term));
359             }
360         };
361     }
362 
363     template <typename Modifiers, typename A0>
364     struct make_primitive<
365         terminal_ex<tag::float_, fusion::vector1<A0> >, Modifiers>
366       : detail::make_real_direct<float, Modifiers> {};
367 
368     template <typename Modifiers, typename A0>
369     struct make_primitive<
370         terminal_ex<tag::double_, fusion::vector1<A0> >, Modifiers>
371       : detail::make_real_direct<double, Modifiers> {};
372 
373     template <typename Modifiers, typename A0>
374     struct make_primitive<
375         terminal_ex<tag::long_double, fusion::vector1<A0> >, Modifiers>
376       : detail::make_real_direct<long double, Modifiers> {};
377 
378     ///////////////////////////////////////////////////////////////////////////
379     template <typename T, typename Policies, typename A0, typename Modifiers>
380     struct make_primitive<
381         terminal_ex<tag::stateful_tag<Policies, tag::double_, T>
382           , fusion::vector1<A0> >
383           , Modifiers>
384       : detail::make_real_direct<typename remove_const<T>::type
385           , Modifiers, Policies> {};
386 
387     ///////////////////////////////////////////////////////////////////////////
388     namespace detail
389     {
390         template <typename T, typename Modifiers>
391         struct basic_real_literal
392         {
393             static bool const lower =
394                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
395             static bool const upper =
396                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
397 
398             typedef literal_real_generator<
399                 T, real_policies<T>
400               , typename spirit::detail::get_encoding_with_case<
401                     Modifiers, unused_type, lower || upper>::type
402               , typename detail::get_casetag<Modifiers, lower || upper>::type
403               , true
404             > result_type;
405 
406             template <typename T_>
operator ()boost::spirit::karma::detail::basic_real_literal407             result_type operator()(T_ i, unused_type) const
408             {
409                 return result_type(T(i));
410             }
411         };
412     }
413 
414     template <typename Modifiers>
415     struct make_primitive<float, Modifiers>
416       : detail::basic_real_literal<float, Modifiers> {};
417 
418     template <typename Modifiers>
419     struct make_primitive<double, Modifiers>
420       : detail::basic_real_literal<double, Modifiers> {};
421 
422     template <typename Modifiers>
423     struct make_primitive<long double, Modifiers>
424       : detail::basic_real_literal<long double, Modifiers> {};
425 
426     // lit(double)
427     template <typename Modifiers, typename A0>
428     struct make_primitive<
429             terminal_ex<tag::lit, fusion::vector1<A0> >
430           , Modifiers
431           , typename enable_if<traits::is_real<A0> >::type>
432     {
433         static bool const lower =
434             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
435         static bool const upper =
436             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
437 
438         typedef literal_real_generator<
439             typename remove_const<A0>::type, real_policies<A0>
440           , typename spirit::detail::get_encoding_with_case<
441                 Modifiers, unused_type, lower || upper>::type
442           , typename detail::get_casetag<Modifiers, lower || upper>::type
443           , true
444         > result_type;
445 
446         template <typename Terminal>
operator ()boost::spirit::karma::make_primitive447         result_type operator()(Terminal const& term, unused_type) const
448         {
449             return result_type(fusion::at_c<0>(term.args));
450         }
451     };
452 }}}
453 
454 #endif // defined(BOOST_SPIRIT_KARMA_REAL_FEB_26_2007_0512PM)
455