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_POLICIES_MAR_02_2007_0936AM)
7 #define BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/config/no_tr1/cmath.hpp>
14 #include <boost/math/special_functions/fpclassify.hpp>
15 #include <boost/type_traits/remove_const.hpp>
16 
17 #include <boost/spirit/home/support/char_class.hpp>
18 #include <boost/spirit/home/karma/generator.hpp>
19 #include <boost/spirit/home/karma/char.hpp>
20 #include <boost/spirit/home/karma/numeric/int.hpp>
21 #include <boost/spirit/home/karma/numeric/detail/real_utils.hpp>
22 
23 #include <boost/mpl/bool.hpp>
24 
25 namespace boost { namespace spirit { namespace karma
26 {
27     ///////////////////////////////////////////////////////////////////////////
28     //
29     //  real_policies, if you need special handling of your floating
30     //  point numbers, just overload this policy class and use it as a template
31     //  parameter to the karma::real_generator floating point specifier:
32     //
33     //      template <typename T>
34     //      struct scientific_policy : karma::real_policies<T>
35     //      {
36     //          //  we want the numbers always to be in scientific format
37     //          static int floatfield(T n) { return fmtflags::scientific; }
38     //      };
39     //
40     //      typedef
41     //          karma::real_generator<double, scientific_policy<double> >
42     //      science_type;
43     //
44     //      karma::generate(sink, science_type(), 1.0); // will output: 1.0e00
45     //
46     ///////////////////////////////////////////////////////////////////////////
47     template <typename T>
48     struct real_policies
49     {
50         ///////////////////////////////////////////////////////////////////////
51         // Expose the data type the generator is targeted at
52         ///////////////////////////////////////////////////////////////////////
53         typedef T value_type;
54 
55         ///////////////////////////////////////////////////////////////////////
56         //  By default the policy doesn't require any special iterator
57         //  functionality. The floating point generator exposes its properties
58         //  from here, so this needs to be updated in case other properties
59         //  need to be implemented.
60         ///////////////////////////////////////////////////////////////////////
61         typedef mpl::int_<generator_properties::no_properties> properties;
62 
63         ///////////////////////////////////////////////////////////////////////
64         //  Specifies, which representation type to use during output
65         //  generation.
66         ///////////////////////////////////////////////////////////////////////
67         struct fmtflags
68         {
69             enum {
70                 scientific = 0,   // Generate floating-point values in scientific
71                                   // format (with an exponent field).
72                 fixed = 1         // Generate floating-point values in fixed-point
73                                   // format (with no exponent field).
74             };
75         };
76 
77         ///////////////////////////////////////////////////////////////////////
78         //  This is the main function used to generate the output for a
79         //  floating point number. It is called by the real generator in order
80         //  to perform the conversion. In theory all of the work can be
81         //  implemented here, but it is the easiest to use existing
82         //  functionality provided by the type specified by the template
83         //  parameter `Inserter`.
84         //
85         //      sink: the output iterator to use for generation
86         //      n:    the floating point number to convert
87         //      p:    the instance of the policy type used to instantiate this
88         //            floating point generator.
89         ///////////////////////////////////////////////////////////////////////
90         template <typename Inserter, typename OutputIterator, typename Policies>
91         static bool
callboost::spirit::karma::real_policies92         call (OutputIterator& sink, T n, Policies const& p)
93         {
94             return Inserter::call_n(sink, n, p);
95         }
96 
97         ///////////////////////////////////////////////////////////////////////
98         //  The default behavior is to not to require generating a sign. If
99         //  'force_sign()' returns true, then all generated numbers will
100         //  have a sign ('+' or '-', zeros will have a space instead of a sign)
101         //
102         //      n     The floating point number to output. This can be used to
103         //            adjust the required behavior depending on the value of
104         //            this number.
105         ///////////////////////////////////////////////////////////////////////
force_signboost::spirit::karma::real_policies106         static bool force_sign(T)
107         {
108             return false;
109         }
110 
111         ///////////////////////////////////////////////////////////////////////
112         //  Return whether trailing zero digits have to be emitted in the
113         //  fractional part of the output. If set, this flag instructs the
114         //  floating point generator to emit trailing zeros up to the required
115         //  precision digits (as returned by the precision() function).
116         //
117         //      n     The floating point number to output. This can be used to
118         //            adjust the required behavior depending on the value of
119         //            this number.
120         ///////////////////////////////////////////////////////////////////////
trailing_zerosboost::spirit::karma::real_policies121         static bool trailing_zeros(T)
122         {
123             // the default behavior is not to generate trailing zeros
124             return false;
125         }
126 
127         ///////////////////////////////////////////////////////////////////////
128         //  Decide, which representation type to use in the generated output.
129         //
130         //  By default all numbers having an absolute value of zero or in
131         //  between 0.001 and 100000 will be generated using the fixed format,
132         //  all others will be generated using the scientific representation.
133         //
134         //  The function trailing_zeros() can be used to force the output of
135         //  trailing zeros in the fractional part up to the number of digits
136         //  returned by the precision() member function. The default is not to
137         //  generate the trailing zeros.
138         //
139         //      n     The floating point number to output. This can be used to
140         //            adjust the formatting flags depending on the value of
141         //            this number.
142         ///////////////////////////////////////////////////////////////////////
floatfieldboost::spirit::karma::real_policies143         static int floatfield(T n)
144         {
145             if (traits::test_zero(n))
146                 return fmtflags::fixed;
147 
148             T abs_n = traits::get_absolute_value(n);
149             return (abs_n >= 1e5 || abs_n < 1e-3)
150               ? fmtflags::scientific : fmtflags::fixed;
151         }
152 
153         ///////////////////////////////////////////////////////////////////////
154         //  Return the maximum number of decimal digits to generate in the
155         //  fractional part of the output.
156         //
157         //      n     The floating point number to output. This can be used to
158         //            adjust the required precision depending on the value of
159         //            this number. If the trailing zeros flag is specified the
160         //            fractional part of the output will be 'filled' with
161         //            zeros, if appropriate
162         //
163         //  Note:     If the trailing_zeros flag is not in effect additional
164         //            comments apply. See the comment for the fraction_part()
165         //            function below. Moreover, this precision will be limited
166         //            to the value of std::numeric_limits<T>::digits10 + 1
167         ///////////////////////////////////////////////////////////////////////
precisionboost::spirit::karma::real_policies168         static unsigned precision(T)
169         {
170             // by default, generate max. 3 fractional digits
171             return 3;
172         }
173 
174         ///////////////////////////////////////////////////////////////////////
175         //  Generate the integer part of the number.
176         //
177         //      sink       The output iterator to use for generation
178         //      n          The absolute value of the integer part of the floating
179         //                 point number to convert (always non-negative).
180         //      sign       The sign of the overall floating point number to
181         //                 convert.
182         //      force_sign Whether a sign has to be generated even for
183         //                 non-negative numbers. Note, that force_sign will be
184         //                 set to false for zero floating point values.
185         ///////////////////////////////////////////////////////////////////////
186         template <typename OutputIterator>
integer_partboost::spirit::karma::real_policies187         static bool integer_part (OutputIterator& sink, T n, bool sign
188           , bool force_sign)
189         {
190             return sign_inserter::call(
191                       sink, traits::test_zero(n), sign, force_sign, force_sign) &&
192                    int_inserter<10>::call(sink, n);
193         }
194 
195         ///////////////////////////////////////////////////////////////////////
196         //  Generate the decimal point.
197         //
198         //      sink  The output iterator to use for generation
199         //      n     The fractional part of the floating point number to
200         //            convert. Note that this number is scaled such, that
201         //            it represents the number of units which correspond
202         //            to the value returned from the precision() function
203         //            earlier. I.e. a fractional part of 0.01234 is
204         //            represented as 1234 when the 'Precision' is 5.
205         //      precision   The number of digits to emit as returned by the
206         //                  function 'precision()' above
207         //
208         //            This is given to allow to decide, whether a decimal point
209         //            has to be generated at all.
210         //
211         //  Note:     If the trailing_zeros flag is not in effect additional
212         //            comments apply. See the comment for the fraction_part()
213         //            function below.
214         ///////////////////////////////////////////////////////////////////////
215         template <typename OutputIterator>
dotboost::spirit::karma::real_policies216         static bool dot (OutputIterator& sink, T /*n*/, unsigned /*precision*/)
217         {
218             return char_inserter<>::call(sink, '.');  // generate the dot by default
219         }
220 
221         ///////////////////////////////////////////////////////////////////////
222         //  Generate the fractional part of the number.
223         //
224         //      sink  The output iterator to use for generation
225         //      n     The fractional part of the floating point number to
226         //            convert. This number is scaled such, that it represents
227         //            the number of units which correspond to the 'Precision'.
228         //            I.e. a fractional part of 0.01234 is represented as 1234
229         //            when the 'precision_' parameter is 5.
230         //      precision_  The corrected number of digits to emit (see note
231         //                  below)
232         //      precision   The number of digits to emit as returned by the
233         //                  function 'precision()' above
234         //
235         //  Note: If trailing_zeros() does not return true the 'precision_'
236         //        parameter will have been corrected from the value the
237         //        precision() function returned earlier (defining the maximal
238         //        number of fractional digits) in the sense, that it takes into
239         //        account trailing zeros. I.e. a floating point number 0.0123
240         //        and a value of 5 returned from precision() will result in:
241         //
242         //        trailing_zeros is not specified:
243         //            n           123
244         //            precision_  4
245         //
246         //        trailing_zeros is specified:
247         //            n           1230
248         //            precision_  5
249         //
250         ///////////////////////////////////////////////////////////////////////
251         template <typename OutputIterator>
fraction_partboost::spirit::karma::real_policies252         static bool fraction_part (OutputIterator& sink, T n
253           , unsigned precision_, unsigned precision)
254         {
255             // allow for ADL to find the correct overload for floor and log10
256             using namespace std;
257 
258             // The following is equivalent to:
259             //    generate(sink, right_align(precision, '0')[ulong], n);
260             // but it's spelled out to avoid inter-modular dependencies.
261 
262             typename remove_const<T>::type digits =
263                 (traits::test_zero(n) ? 0 : floor(log10(n))) + 1;
264             bool r = true;
265             for (/**/; r && digits < precision_; digits = digits + 1)
266                 r = char_inserter<>::call(sink, '0');
267             if (precision && r)
268                 r = int_inserter<10>::call(sink, n);
269             return r;
270         }
271 
272         ///////////////////////////////////////////////////////////////////////
273         //  Generate the exponential part of the number (this is called only
274         //  if the floatfield() function returned the 'scientific' flag).
275         //
276         //      sink  The output iterator to use for generation
277         //      n     The (signed) exponential part of the floating point
278         //            number to convert.
279         //
280         //  The Tag template parameter is either of the type unused_type or
281         //  describes the character class and conversion to be applied to any
282         //  output possibly influenced by either the lower[...] or upper[...]
283         //  directives.
284         ///////////////////////////////////////////////////////////////////////
285         template <typename CharEncoding, typename Tag, typename OutputIterator>
exponentboost::spirit::karma::real_policies286         static bool exponent (OutputIterator& sink, long n)
287         {
288             long abs_n = traits::get_absolute_value(n);
289             bool r = char_inserter<CharEncoding, Tag>::call(sink, 'e') &&
290                      sign_inserter::call(sink, traits::test_zero(n)
291                         , traits::test_negative(n), false);
292 
293             // the C99 Standard requires at least two digits in the exponent
294             if (r && abs_n < 10)
295                 r = char_inserter<CharEncoding, Tag>::call(sink, '0');
296             return r && int_inserter<10>::call(sink, abs_n);
297         }
298 
299         ///////////////////////////////////////////////////////////////////////
300         //  Print the textual representations for non-normal floats (NaN and
301         //  Inf)
302         //
303         //      sink       The output iterator to use for generation
304         //      n          The (signed) floating point number to convert.
305         //      force_sign Whether a sign has to be generated even for
306         //                 non-negative numbers
307         //
308         //  The Tag template parameter is either of the type unused_type or
309         //  describes the character class and conversion to be applied to any
310         //  output possibly influenced by either the lower[...] or upper[...]
311         //  directives.
312         //
313         //  Note: These functions get called only if fpclassify() returned
314         //        FP_INFINITY or FP_NAN.
315         ///////////////////////////////////////////////////////////////////////
316         template <typename CharEncoding, typename Tag, typename OutputIterator>
nanboost::spirit::karma::real_policies317         static bool nan (OutputIterator& sink, T n, bool force_sign)
318         {
319             return sign_inserter::call(
320                         sink, false, traits::test_negative(n), force_sign) &&
321                    string_inserter<CharEncoding, Tag>::call(sink, "nan");
322         }
323 
324         template <typename CharEncoding, typename Tag, typename OutputIterator>
infboost::spirit::karma::real_policies325         static bool inf (OutputIterator& sink, T n, bool force_sign)
326         {
327             return sign_inserter::call(
328                         sink, false, traits::test_negative(n), force_sign) &&
329                    string_inserter<CharEncoding, Tag>::call(sink, "inf");
330         }
331     };
332 }}}
333 
334 #endif // defined(BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM)
335