// Copyright (c) 2001-2011 Hartmut Kaiser // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if !defined(BOOST_SPIRIT_KARMA_NUMERIC_UTILS_FEB_23_2007_0841PM) #define BOOST_SPIRIT_KARMA_NUMERIC_UTILS_FEB_23_2007_0841PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// // // The value BOOST_KARMA_NUMERICS_LOOP_UNROLL specifies, how to unroll the // integer string generation loop (see below). // // Set the value to some integer in between 0 (no unrolling) and the // largest expected generated integer string length (complete unrolling). // If not specified, this value defaults to 6. // /////////////////////////////////////////////////////////////////////////////// #if !defined(BOOST_KARMA_NUMERICS_LOOP_UNROLL) #define BOOST_KARMA_NUMERICS_LOOP_UNROLL 6 #endif #if BOOST_KARMA_NUMERICS_LOOP_UNROLL < 0 #error "Please set the BOOST_KARMA_NUMERICS_LOOP_UNROLL to a non-negative value!" #endif namespace boost { namespace spirit { namespace traits { /////////////////////////////////////////////////////////////////////// // // return the absolute value from a given number, avoiding over- and // underflow // /////////////////////////////////////////////////////////////////////// template struct absolute_value { typedef T type; static T call (T n) { // allow for ADL to find the correct overloads for fabs using namespace std; return fabs(n); } }; #define BOOST_SPIRIT_ABSOLUTE_VALUE(signedtype, unsignedtype) \ template <> \ struct absolute_value \ { \ typedef unsignedtype type; \ static type call(signedtype n) \ { \ return static_cast((n >= 0) ? n : -n); \ } \ } \ /**/ #define BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsignedtype) \ template <> \ struct absolute_value \ { \ typedef unsignedtype type; \ static type call(unsignedtype n) \ { \ return n; \ } \ } \ /**/ BOOST_SPIRIT_ABSOLUTE_VALUE(signed char, unsigned char); BOOST_SPIRIT_ABSOLUTE_VALUE(char, unsigned char); BOOST_SPIRIT_ABSOLUTE_VALUE(short, unsigned short); BOOST_SPIRIT_ABSOLUTE_VALUE(int, unsigned int); BOOST_SPIRIT_ABSOLUTE_VALUE(long, unsigned long); BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned char); BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned short); BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned int); BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned long); #ifdef BOOST_HAS_LONG_LONG BOOST_SPIRIT_ABSOLUTE_VALUE(boost::long_long_type, boost::ulong_long_type); BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(boost::ulong_long_type); #endif #undef BOOST_SPIRIT_ABSOLUTE_VALUE #undef BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED template <> struct absolute_value { typedef float type; static type call(float n) { return (spirit::detail::signbit)(n) ? -n : n; } }; template <> struct absolute_value { typedef double type; static type call(double n) { return (spirit::detail::signbit)(n) ? -n : n; } }; template <> struct absolute_value { typedef long double type; static type call(long double n) { return (spirit::detail::signbit)(n) ? -n : n; } }; // specialization for pointers template struct absolute_value { typedef std::size_t type; static type call (T* p) { return std::size_t(p); } }; template inline typename absolute_value::type get_absolute_value(T n) { return absolute_value::call(n); } /////////////////////////////////////////////////////////////////////// template struct is_negative { static bool call(T n) { return (n < 0) ? true : false; } }; template <> struct is_negative { static bool call(float n) { return (spirit::detail::signbit)(n) ? true : false; } }; template <> struct is_negative { static bool call(double n) { return (spirit::detail::signbit)(n) ? true : false; } }; template <> struct is_negative { static bool call(long double n) { return (spirit::detail::signbit)(n) ? true : false; } }; template inline bool test_negative(T n) { return is_negative::call(n); } /////////////////////////////////////////////////////////////////////// template struct is_zero { static bool call(T n) { return (n == 0) ? true : false; } }; template <> struct is_zero { static bool call(float n) { return (math::fpclassify)(n) == FP_ZERO; } }; template <> struct is_zero { static bool call(double n) { return (math::fpclassify)(n) == FP_ZERO; } }; template <> struct is_zero { static bool call(long double n) { return (math::fpclassify)(n) == FP_ZERO; } }; template inline bool test_zero(T n) { return is_zero::call(n); } /////////////////////////////////////////////////////////////////////// template struct is_nan { static bool call(T n) { // NaN numbers are not equal to anything return (n != n) ? true : false; } }; template <> struct is_nan { static bool call(float n) { return (math::fpclassify)(n) == FP_NAN; } }; template <> struct is_nan { static bool call(double n) { return (math::fpclassify)(n) == FP_NAN; } }; template <> struct is_nan { static bool call(long double n) { return (math::fpclassify)(n) == FP_NAN; } }; template inline bool test_nan(T n) { return is_nan::call(n); } /////////////////////////////////////////////////////////////////////// template struct is_infinite { static bool call(T n) { if (!std::numeric_limits::has_infinity) return false; return (n == std::numeric_limits::infinity()) ? true : false; } }; template <> struct is_infinite { static bool call(float n) { return (math::fpclassify)(n) == FP_INFINITE; } }; template <> struct is_infinite { static bool call(double n) { return (math::fpclassify)(n) == FP_INFINITE; } }; template <> struct is_infinite { static bool call(long double n) { return (math::fpclassify)(n) == FP_INFINITE; } }; template inline bool test_infinite(T n) { return is_infinite::call(n); } /////////////////////////////////////////////////////////////////////// struct cast_to_long { static long call(float n, mpl::false_) { return static_cast(std::floor(n)); } static long call(double n, mpl::false_) { return static_cast(std::floor(n)); } static long call(long double n, mpl::false_) { return static_cast(std::floor(n)); } template static long call(T n, mpl::false_) { // allow for ADL to find the correct overload for floor and // lround using namespace std; return lround(floor(n)); } template static long call(T n, mpl::true_) { return static_cast(n); } template static long call(T n) { return call(n, mpl::bool_::value>()); } }; /////////////////////////////////////////////////////////////////////// struct truncate_to_long { static long call(float n, mpl::false_) { return test_negative(n) ? static_cast(std::ceil(n)) : static_cast(std::floor(n)); } static long call(double n, mpl::false_) { return test_negative(n) ? static_cast(std::ceil(n)) : static_cast(std::floor(n)); } static long call(long double n, mpl::false_) { return test_negative(n) ? static_cast(std::ceil(n)) : static_cast(std::floor(n)); } template static long call(T n, mpl::false_) { // allow for ADL to find the correct overloads for ltrunc using namespace std; return ltrunc(n); } template static long call(T n, mpl::true_) { return static_cast(n); } template static long call(T n) { return call(n, mpl::bool_::value>()); } }; /////////////////////////////////////////////////////////////////////// // // Traits class for radix specific number conversion // // Convert a digit from binary representation to character // representation: // // static int call(unsigned n); // /////////////////////////////////////////////////////////////////////// namespace detail { template struct convert_digit { static int call(unsigned n) { if (n <= 9) return n + '0'; using spirit::char_class::convert; return convert::to(Tag(), n - 10 + 'a'); } }; template <> struct convert_digit { static int call(unsigned n) { if (n <= 9) return n + '0'; return n - 10 + 'a'; } }; template struct convert_digit { static int call(unsigned n) { return n + '0'; } }; } template struct convert_digit : detail::convert_digit {}; /////////////////////////////////////////////////////////////////////// template struct divide { template static T call(T& n, mpl::true_) { return n / Radix; } template static T call(T& n, mpl::false_) { // Allow ADL to find the correct overload for floor using namespace std; return floor(n / Radix); } template static T call(T& n, T const&, int) { return call(n, mpl::bool_::value>()); } template static T call(T& n) { return call(n, mpl::bool_::value>()); } }; // specialization for division by 10 template <> struct divide<10> { template static T call(T& n, T, int, mpl::true_) { return n / 10; } template static T call(T, T& num, int exp, mpl::false_) { // Allow ADL to find the correct overload for floor using namespace std; return floor(num / spirit::traits::pow10(exp)); } template static T call(T& n, T& num, int exp) { return call(n, num, exp, mpl::bool_::value>()); } template static T call(T& n) { return call(n, n, 1, mpl::bool_::value>()); } }; /////////////////////////////////////////////////////////////////////// template struct remainder { template static long call(T n, mpl::true_) { // this cast is safe since we know the result is not larger // than Radix return static_cast(n % Radix); } template static long call(T n, mpl::false_) { // Allow ADL to find the correct overload for fmod using namespace std; return cast_to_long::call(fmod(n, T(Radix))); } template static long call(T n) { return call(n, mpl::bool_::value>()); } }; }}} namespace boost { namespace spirit { namespace karma { /////////////////////////////////////////////////////////////////////////// // // The int_inserter template takes care of the integer to string // conversion. If specified, the loop is unrolled for better performance. // // Set the value BOOST_KARMA_NUMERICS_LOOP_UNROLL to some integer in // between 0 (no unrolling) and the largest expected generated integer // string length (complete unrolling). // If not specified, this value defaults to 6. // /////////////////////////////////////////////////////////////////////////// #define BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX(z, x, data) \ if (!traits::test_zero(n)) { \ int ch = radix_type::call(remainder_type::call(n)); \ n = divide_type::call(n, num, ++exp); \ /**/ #define BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX(z, x, data) \ *sink = char(ch); \ ++sink; \ } \ /**/ template < unsigned Radix, typename CharEncoding = unused_type , typename Tag = unused_type> struct int_inserter { typedef traits::convert_digit radix_type; typedef traits::divide divide_type; typedef traits::remainder remainder_type; template static bool call(OutputIterator& sink, T n, T& num, int exp) { // remainder_type::call returns n % Radix int ch = radix_type::call(remainder_type::call(n)); n = divide_type::call(n, num, ++exp); BOOST_PP_REPEAT( BOOST_KARMA_NUMERICS_LOOP_UNROLL, BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX, _); if (!traits::test_zero(n)) call(sink, n, num, exp); BOOST_PP_REPEAT( BOOST_KARMA_NUMERICS_LOOP_UNROLL, BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX, _); *sink = char(ch); ++sink; return true; } // Common code for integer string representations template static bool call(OutputIterator& sink, T n) { return call(sink, n, n, 0); } private: // helper function returning the biggest number representable either in // a boost::long_long_type (if this does exist) or in a plain long // otherwise #if defined(BOOST_HAS_LONG_LONG) typedef boost::long_long_type biggest_long_type; #else typedef long biggest_long_type; #endif static biggest_long_type max_long() { return (std::numeric_limits::max)(); } public: // Specialization for doubles and floats, falling back to long integers // for representable values. These specializations speed up formatting // of floating point numbers considerably as all the required // arithmetics will be executed using integral data types. template static bool call(OutputIterator& sink, long double n) { if (std::fabs(n) < max_long()) { biggest_long_type l((biggest_long_type)n); return call(sink, l, l, 0); } return call(sink, n, n, 0); } template static bool call(OutputIterator& sink, double n) { if (std::fabs(n) < max_long()) { biggest_long_type l((biggest_long_type)n); return call(sink, l, l, 0); } return call(sink, n, n, 0); } template static bool call(OutputIterator& sink, float n) { if (std::fabs(n) < max_long()) { biggest_long_type l((biggest_long_type)n); return call(sink, l, l, 0); } return call(sink, n, n, 0); } }; #undef BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX #undef BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX /////////////////////////////////////////////////////////////////////////// // // The uint_inserter template takes care of the conversion of any integer // to a string, while interpreting the number as an unsigned type. // /////////////////////////////////////////////////////////////////////////// template < unsigned Radix, typename CharEncoding = unused_type , typename Tag = unused_type> struct uint_inserter : int_inserter { typedef int_inserter base_type; // Common code for integer string representations template static bool call(OutputIterator& sink, T const& n) { typedef typename traits::absolute_value::type type; type un = type(n); return base_type::call(sink, un, un, 0); } }; /////////////////////////////////////////////////////////////////////////// // // The sign_inserter template generates a sign for a given numeric value. // // The parameter forcesign allows to generate a sign even for positive // numbers. // /////////////////////////////////////////////////////////////////////////// struct sign_inserter { template static bool call_noforce(OutputIterator& sink, bool is_zero, bool is_negative, bool sign_if_zero) { // generate a sign for negative numbers only if (is_negative || (is_zero && sign_if_zero)) { *sink = '-'; ++sink; } return true; } template static bool call_force(OutputIterator& sink, bool is_zero, bool is_negative, bool sign_if_zero) { // generate a sign for all numbers except zero if (!is_zero || sign_if_zero) *sink = is_negative ? '-' : '+'; else *sink = ' '; ++sink; return true; } template static bool call(OutputIterator& sink, bool is_zero, bool is_negative , bool forcesign, bool sign_if_zero = false) { return forcesign ? call_force(sink, is_zero, is_negative, sign_if_zero) : call_noforce(sink, is_zero, is_negative, sign_if_zero); } }; /////////////////////////////////////////////////////////////////////////// // These are helper functions for the real policies allowing to generate // a single character and a string /////////////////////////////////////////////////////////////////////////// template struct char_inserter { template static bool call(OutputIterator& sink, Char c) { return detail::generate_to(sink, c, CharEncoding(), Tag()); } }; template struct string_inserter { template static bool call(OutputIterator& sink, String str) { return detail::string_generate(sink, str, CharEncoding(), Tag()); } }; }}} #endif