Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r55585 - in trunk/boost/spirit/home/karma: detail directive numeric numeric/detail
From: hartmut.kaiser_at_[hidden]
Date: 2009-08-14 16:25:03


Author: hkaiser
Date: 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
New Revision: 55585
URL: http://svn.boost.org/trac/boost/changeset/55585

Log:
Spirit: adjustments to real_policies to accommodate more use cases
Text files modified:
   trunk/boost/spirit/home/karma/detail/output_iterator.hpp | 5 +
   trunk/boost/spirit/home/karma/directive/right_alignment.hpp | 2
   trunk/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp | 75 +++++++++++++++++-----------
   trunk/boost/spirit/home/karma/numeric/int.hpp | 12 ++--
   trunk/boost/spirit/home/karma/numeric/real.hpp | 4 +
   trunk/boost/spirit/home/karma/numeric/real_policies.hpp | 105 ++++++++++++++++++++++++++++-----------
   6 files changed, 135 insertions(+), 68 deletions(-)

Modified: trunk/boost/spirit/home/karma/detail/output_iterator.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/detail/output_iterator.hpp (original)
+++ trunk/boost/spirit/home/karma/detail/output_iterator.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -248,7 +248,7 @@
         void enable(std::size_t width_)
         {
             tidy(); // release existing buffer
- width = width_;
+ width = (width_ == std::size_t(-1)) ? 0 : width_;
         }
 
         void tidy()
@@ -529,7 +529,8 @@
     template <typename OutputIterator>
     struct enable_buffering
     {
- enable_buffering(OutputIterator& sink_, std::size_t width = 0)
+ enable_buffering(OutputIterator& sink_
+ , std::size_t width = std::size_t(-1))
           : sink(sink_), prev_buffer(NULL), enabled(false)
         {
             buffer_data.enable(width);

Modified: trunk/boost/spirit/home/karma/directive/right_alignment.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/directive/right_alignment.hpp (original)
+++ trunk/boost/spirit/home/karma/directive/right_alignment.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -98,7 +98,7 @@
             } // re-enable counting
 
             buffering.disable(); // do not perform buffering any more
-
+
             // generate the left padding
             detail::enable_counting<OutputIterator> counting(sink, buffering.buffer_size());
             while(r && counting.count() < width)

Modified: trunk/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp (original)
+++ trunk/boost/spirit/home/karma/numeric/detail/numeric_utils.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -547,16 +547,15 @@
     //
     // The sign_inserter template generates a sign for a given numeric value.
     //
- // The parameter ForceSign allows to generate a sign even for positive
+ // The parameter forcesign allows to generate a sign even for positive
     // numbers.
     //
     ///////////////////////////////////////////////////////////////////////////
- template <bool ForceSign>
     struct sign_inserter
     {
         template <typename OutputIterator>
         static bool
- call(OutputIterator& sink, bool /*is_zero*/, bool is_negative)
+ call_noforce(OutputIterator& sink, bool /*is_zero*/, bool is_negative)
         {
             // generate a sign for negative numbers only
             if (is_negative) {
@@ -565,14 +564,10 @@
             }
             return true;
         }
- };
 
- template <>
- struct sign_inserter<true>
- {
         template <typename OutputIterator>
         static bool
- call(OutputIterator& sink, bool is_zero, bool is_negative)
+ call_force(OutputIterator& sink, bool is_zero, bool is_negative)
         {
             // generate a sign for all numbers except zero
             if (!is_zero)
@@ -583,6 +578,16 @@
             ++sink;
             return true;
         }
+
+ template <typename OutputIterator>
+ static bool
+ call(OutputIterator& sink, bool is_zero, bool is_negative
+ , bool forcesign)
+ {
+ return forcesign ?
+ call_force(sink, is_zero, is_negative) :
+ call_noforce(sink, is_zero, is_negative);
+ }
     };
 
     ///////////////////////////////////////////////////////////////////////////
@@ -625,18 +630,20 @@
       , typename Tag = unused_type>
     struct real_inserter
     {
- enum { force_sign = Policies::force_sign };
-
         template <typename OutputIterator>
         static bool
         call (OutputIterator& sink, float n, Policies const& p = Policies())
         {
             int fpclass = (math::fpclassify)(n);
- if ((int)FP_NAN == fpclass)
- return Policies::template nan<force_sign, CharEncoding, Tag>(sink, n);
- else if ((int)FP_INFINITE == fpclass)
- return Policies::template inf<force_sign, CharEncoding, Tag>(sink, n);
- return call_n(sink, n, p);
+ if ((int)FP_NAN == fpclass) {
+ return Policies::template nan<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ else if ((int)FP_INFINITE == fpclass) {
+ return Policies::template inf<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ return p.template call<real_inserter>(sink, n, p);
         }
 
         template <typename OutputIterator>
@@ -644,11 +651,15 @@
         call (OutputIterator& sink, double n, Policies const& p = Policies())
         {
             int fpclass = (math::fpclassify)(n);
- if ((int)FP_NAN == fpclass)
- return Policies::template nan<force_sign, CharEncoding, Tag>(sink, n);
- else if ((int)FP_INFINITE == fpclass)
- return Policies::template inf<force_sign, CharEncoding, Tag>(sink, n);
- return call_n(sink, n, p);
+ if ((int)FP_NAN == fpclass) {
+ return Policies::template nan<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ else if ((int)FP_INFINITE == fpclass) {
+ return Policies::template inf<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ return p.template call<real_inserter>(sink, n, p);
         }
 
         template <typename OutputIterator>
@@ -656,11 +667,15 @@
         call (OutputIterator& sink, long double n, Policies const& p = Policies())
         {
             int fpclass = (math::fpclassify)(n);
- if ((int)FP_NAN == fpclass)
- return Policies::template nan<force_sign, CharEncoding, Tag>(sink, n);
- else if ((int)FP_INFINITE == fpclass)
- return Policies::template inf<force_sign, CharEncoding, Tag>(sink, n);
- return call_n(sink, n, p);
+ if ((int)FP_NAN == fpclass) {
+ return Policies::template nan<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ else if ((int)FP_INFINITE == fpclass) {
+ return Policies::template inf<CharEncoding, Tag>(
+ sink, n, p.force_sign(n));
+ }
+ return p.template call<real_inserter>(sink, n, p);
         }
 
         template <typename OutputIterator, typename U>
@@ -669,7 +684,7 @@
         {
             // we have no means of testing whether the number is normalized if
             // the type is not float, double or long double
- return call_n(sink, T(n), p);
+ return p.template call<real_inserter>(sink, T(n), p);
         }
 
 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
@@ -686,6 +701,7 @@
         call_n (OutputIterator& sink, U n, Policies const& p)
         {
         // prepare sign and get output format
+ bool force_sign = p.force_sign(n);
             bool sign_val = false;
             int flags = p.floatfield(n);
             if (detail::is_negative(n))
@@ -769,14 +785,13 @@
             }
 
         // generate integer part
- bool r = p.template integer_part<force_sign>(
- sink, long_int_part, sign_val);
+ bool r = p.integer_part(sink, long_int_part, sign_val, force_sign);
 
         // generate decimal point
- r = r && p.dot(sink, long_frac_part);
+ r = r && p.dot(sink, long_frac_part, precision);
 
         // generate fractional part with the desired precision
- r = r && p.fraction_part(sink, long_frac_part, prec);
+ r = r && p.fraction_part(sink, long_frac_part, prec, precision);
 
             if (r && 0 == (Policies::fmtflags::fixed & flags)) {
                 return p.template exponent<CharEncoding, Tag>(sink,

Modified: trunk/boost/spirit/home/karma/numeric/int.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/numeric/int.hpp (original)
+++ trunk/boost/spirit/home/karma/numeric/int.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -200,8 +200,8 @@
         generate(OutputIterator& sink, Context&, Delimiter const& d
           , Attribute const& attr)
         {
- return sign_inserter<force_sign>::call(sink
- , detail::is_zero(attr), detail::is_negative(attr)) &&
+ return sign_inserter::call(sink, detail::is_zero(attr)
+ , detail::is_negative(attr), force_sign) &&
                    int_inserter<Radix, CharEncoding, Tag>::call(sink
                       , detail::absolute_value(attr)) &&
                    karma::delimit_out(sink, d); // always do post-delimiting
@@ -262,8 +262,8 @@
             if (n_ != attr)
                 return false;
 
- return sign_inserter<force_sign>::call(sink
- , detail::is_zero(n_), detail::is_negative(n_)) &&
+ return sign_inserter::call(sink, detail::is_zero(n_)
+ , detail::is_negative(n_), force_sign) &&
                    int_inserter<Radix, CharEncoding, Tag>::call(sink
                       , detail::absolute_value(n_)) &&
                    karma::delimit_out(sink, d); // always do post-delimiting
@@ -275,8 +275,8 @@
         bool generate(OutputIterator& sink, Context&, Delimiter const& d
           , unused_type) const
         {
- return sign_inserter<force_sign>::call(sink
- , detail::is_zero(n_), detail::is_negative(n_)) &&
+ return sign_inserter::call(sink, detail::is_zero(n_)
+ , detail::is_negative(n_), force_sign) &&
                    int_inserter<Radix, CharEncoding, Tag>::call(sink
                       , detail::absolute_value(n_)) &&
                    karma::delimit_out(sink, d); // always do post-delimiting

Modified: trunk/boost/spirit/home/karma/numeric/real.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/numeric/real.hpp (original)
+++ trunk/boost/spirit/home/karma/numeric/real.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -156,6 +156,8 @@
     struct any_real_generator
       : primitive_generator<any_real_generator<T, Policies, CharEncoding, Tag> >
     {
+ typedef typename Policies::properties properties;
+
         template <typename Context, typename Unused>
         struct attribute
         {
@@ -206,6 +208,8 @@
       : primitive_generator<literal_real_generator<T, Policies, CharEncoding
           , Tag, no_attribute> >
     {
+ typedef typename Policies::properties properties;
+
         template <typename Context, typename Unused>
         struct attribute
           : mpl::if_c<no_attribute, unused_type, T>

Modified: trunk/boost/spirit/home/karma/numeric/real_policies.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/numeric/real_policies.hpp (original)
+++ trunk/boost/spirit/home/karma/numeric/real_policies.hpp 2009-08-14 16:25:02 EDT (Fri, 14 Aug 2009)
@@ -19,6 +19,8 @@
 #include <boost/spirit/home/karma/char.hpp>
 #include <boost/spirit/home/karma/numeric/int.hpp>
 
+#include <boost/mpl/bool.hpp>
+
 namespace boost { namespace spirit { namespace karma
 {
     ///////////////////////////////////////////////////////////////////////////
@@ -50,6 +52,14 @@
         typedef T value_type;
 
         ///////////////////////////////////////////////////////////////////////
+ // By default the policy doesn't require any special iterator
+ // functionality. The floating point generator exposes its properties
+ // from here, so this needs to be updated in case other properties
+ // need to be implemented.
+ ///////////////////////////////////////////////////////////////////////
+ typedef mpl::int_<generator_properties::no_properties> properties;
+
+ ///////////////////////////////////////////////////////////////////////
         // Specifies, which representation type to use during output
         // generation.
         ///////////////////////////////////////////////////////////////////////
@@ -63,11 +73,38 @@
         BOOST_SCOPED_ENUM_END
 
         ///////////////////////////////////////////////////////////////////////
+ // This is the main function used to generate the output for a
+ // floating point number. It is called by the real generator in order
+ // to perform the conversion. In theory all of the work can be
+ // implemented here, but it is the easiest to use existing
+ // functionality provided by the type specified by the template
+ // parameter `Inserter`.
+ //
+ // sink: the output iterator to use for generation
+ // n: the floating point number to convert
+ // p: the instance of the policy type used to instantiate this
+ // floating point generator.
+ ///////////////////////////////////////////////////////////////////////
+ template <typename Inserter, typename OutputIterator, typename Policies>
+ static bool
+ call (OutputIterator& sink, T n, Policies const& p)
+ {
+ return Inserter::call_n(sink, n, p);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
         // The default behavior is to not to require generating a sign. If
- // 'force_sign' is specified as true, then all generated numbers will
+ // 'force_sign()' returns true, then all generated numbers will
         // have a sign ('+' or '-', zeros will have a space instead of a sign)
+ //
+ // n The floating point number to output. This can be used to
+ // adjust the required behavior depending on the value of
+ // this number.
         ///////////////////////////////////////////////////////////////////////
- static bool const force_sign = false;
+ static bool const force_sign(T)
+ {
+ return false;
+ }
 
         ///////////////////////////////////////////////////////////////////////
         // Return whether trailing zero digits have to be emitted in the
@@ -135,16 +172,20 @@
         ///////////////////////////////////////////////////////////////////////
         // Generate the integer part of the number.
         //
- // sink The output iterator to use for generation
- // n The absolute value of the integer part of the floating
- // point number to convert (always non-negative).
- // sign The sign of the overall floating point number to convert.
+ // sink The output iterator to use for generation
+ // n The absolute value of the integer part of the floating
+ // point number to convert (always non-negative).
+ // sign The sign of the overall floating point number to
+ // convert.
+ // force_sign Whether a sign has to be generated even for
+ // non-negative numbers
         ///////////////////////////////////////////////////////////////////////
- template <bool ForceSign, typename OutputIterator>
- static bool integer_part (OutputIterator& sink, T n, bool sign)
+ template <typename OutputIterator>
+ static bool integer_part (OutputIterator& sink, T n, bool sign
+ , bool force_sign)
         {
- return sign_inserter<ForceSign>::call(
- sink, detail::is_zero(n), sign) &&
+ return sign_inserter::call(
+ sink, detail::is_zero(n), sign, force_sign) &&
                    int_inserter<10>::call(sink, n);
         }
 
@@ -158,6 +199,8 @@
         // to the value returned from the precision() function
         // earlier. I.e. a fractional part of 0.01234 is
         // represented as 1234 when the 'Precision' is 5.
+ // precision The number of digits to emit as returned by the
+ // function 'precision()' above
         //
         // This is given to allow to decide, whether a decimal point
         // has to be generated at all.
@@ -167,7 +210,7 @@
         // function below.
         ///////////////////////////////////////////////////////////////////////
         template <typename OutputIterator>
- static bool dot (OutputIterator& sink, T)
+ static bool dot (OutputIterator& sink, T /*n*/, unsigned /*precision*/)
         {
             return char_inserter<>::call(sink, '.'); // generate the dot by default
         }
@@ -181,6 +224,10 @@
         // the number of units which correspond to the 'Precision'.
         // I.e. a fractional part of 0.01234 is represented as 1234
         // when the 'precision_' parameter is 5.
+ // precision_ The corrected number of digits to emit (see note
+ // below)
+ // precision The number of digits to emit as returned by the
+ // function 'precision()' above
         //
         // Note: If trailing_zeros() does not return true the 'precision_'
         // parameter will have been corrected from the value the
@@ -200,7 +247,7 @@
         ///////////////////////////////////////////////////////////////////////
         template <typename OutputIterator>
         static bool fraction_part (OutputIterator& sink, T n
- , unsigned precision_)
+ , unsigned precision_, unsigned precision)
         {
             // allow for ADL to find the correct overload for floor and log10
             using namespace std;
@@ -213,7 +260,9 @@
             bool r = true;
             for (/**/; r && digits < precision_; digits = digits + 1)
                 r = char_inserter<>::call(sink, '0');
- return r && int_inserter<10>::call(sink, n);
+ if (precision && r)
+ r = int_inserter<10>::call(sink, n);
+ return r;
         }
 
         ///////////////////////////////////////////////////////////////////////
@@ -234,8 +283,8 @@
         {
             long abs_n = detail::absolute_value(n);
             bool r = char_inserter<CharEncoding, Tag>::call(sink, 'e') &&
- sign_inserter<false>::call(
- sink, detail::is_zero(n), detail::is_negative(n));
+ sign_inserter::call(sink, detail::is_zero(n)
+ , detail::is_negative(n), false);
 
             // the C99 Standard requires at least two digits in the exponent
             if (r && abs_n < 10)
@@ -247,8 +296,10 @@
         // Print the textual representations for non-normal floats (NaN and
         // Inf)
         //
- // sink The output iterator to use for generation
- // n The (signed) floating point number to convert.
+ // sink The output iterator to use for generation
+ // n The (signed) floating point number to convert.
+ // force_sign Whether a sign has to be generated even for
+ // non-negative numbers
         //
         // The Tag template parameter is either of the type unused_type or
         // describes the character class and conversion to be applied to any
@@ -258,23 +309,19 @@
         // Note: These functions get called only if fpclassify() returned
         // FP_INFINITY or FP_NAN.
         ///////////////////////////////////////////////////////////////////////
- template <
- bool ForceSign, typename CharEncoding, typename Tag
- , typename OutputIterator>
- static bool nan (OutputIterator& sink, T n)
+ template <typename CharEncoding, typename Tag, typename OutputIterator>
+ static bool nan (OutputIterator& sink, T n, bool force_sign)
         {
- return sign_inserter<ForceSign>::call(
- sink, false, detail::is_negative(n)) &&
+ return sign_inserter::call(
+ sink, false, detail::is_negative(n), force_sign) &&
                    string_inserter<CharEncoding, Tag>::call(sink, "nan");
         }
 
- template <
- bool ForceSign, typename CharEncoding, typename Tag
- , typename OutputIterator>
- static bool inf (OutputIterator& sink, T n)
+ template <typename CharEncoding, typename Tag, typename OutputIterator>
+ static bool inf (OutputIterator& sink, T n, bool force_sign)
         {
- return sign_inserter<ForceSign>::call(
- sink, false, detail::is_negative(n)) &&
+ return sign_inserter::call(
+ sink, false, detail::is_negative(n), force_sign) &&
                    string_inserter<CharEncoding, Tag>::call(sink, "inf");
         }
     };


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk