File indexing completed on 2025-01-19 09:47:37
0001
0002
0003
0004
0005
0006 #if !defined(BOOST_SPIRIT_KARMA_NUMERIC_UTILS_FEB_23_2007_0841PM)
0007 #define BOOST_SPIRIT_KARMA_NUMERIC_UTILS_FEB_23_2007_0841PM
0008
0009 #if defined(_MSC_VER)
0010 #pragma once
0011 #endif
0012
0013 #include <boost/config.hpp>
0014 #include <boost/config/no_tr1/cmath.hpp>
0015 #include <boost/limits.hpp>
0016
0017 #include <boost/type_traits/is_integral.hpp>
0018 #include <boost/spirit/home/support/char_class.hpp>
0019 #include <boost/spirit/home/support/unused.hpp>
0020 #include <boost/spirit/home/support/numeric_traits.hpp>
0021 #include <boost/spirit/home/support/detail/pow10.hpp>
0022 #include <boost/spirit/home/karma/detail/generate_to.hpp>
0023 #include <boost/spirit/home/karma/detail/string_generate.hpp>
0024
0025 #include <boost/core/cmath.hpp>
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #if !defined(BOOST_KARMA_NUMERICS_LOOP_UNROLL)
0038 #define BOOST_KARMA_NUMERICS_LOOP_UNROLL 6
0039 #endif
0040
0041 #if BOOST_KARMA_NUMERICS_LOOP_UNROLL < 0
0042 #error "Please set the BOOST_KARMA_NUMERICS_LOOP_UNROLL to a non-negative value!"
0043 #endif
0044
0045 namespace boost { namespace spirit { namespace traits
0046 {
0047
0048
0049
0050
0051
0052
0053 template <typename T, typename Enable>
0054 struct absolute_value
0055 {
0056 typedef T type;
0057 static T call (T n)
0058 {
0059
0060 using namespace std;
0061 return fabs(n);
0062 }
0063 };
0064
0065 #define BOOST_SPIRIT_ABSOLUTE_VALUE(signedtype, unsignedtype) \
0066 template <> \
0067 struct absolute_value<signedtype> \
0068 { \
0069 typedef unsignedtype type; \
0070 static type call(signedtype n) \
0071 { \
0072 \
0073 \
0074 \
0075 return (n >= 0) ? static_cast<type>(n) \
0076 : -static_cast<type>(n); \
0077 } \
0078 } \
0079
0080 #define BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsignedtype) \
0081 template <> \
0082 struct absolute_value<unsignedtype> \
0083 { \
0084 typedef unsignedtype type; \
0085 static type call(unsignedtype n) \
0086 { \
0087 return n; \
0088 } \
0089 } \
0090
0091
0092 #if defined(BOOST_MSVC)
0093 # pragma warning(push)
0094
0095 # pragma warning(disable: 4146)
0096 #endif
0097 BOOST_SPIRIT_ABSOLUTE_VALUE(signed char, unsigned char);
0098 BOOST_SPIRIT_ABSOLUTE_VALUE(char, unsigned char);
0099 BOOST_SPIRIT_ABSOLUTE_VALUE(short, unsigned short);
0100 BOOST_SPIRIT_ABSOLUTE_VALUE(int, unsigned int);
0101 BOOST_SPIRIT_ABSOLUTE_VALUE(long, unsigned long);
0102 BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned char);
0103 BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned short);
0104 BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned int);
0105 BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(unsigned long);
0106 #ifdef BOOST_HAS_LONG_LONG
0107 BOOST_SPIRIT_ABSOLUTE_VALUE(boost::long_long_type, boost::ulong_long_type);
0108 BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED(boost::ulong_long_type);
0109 #endif
0110 #if defined(BOOST_MSVC)
0111 # pragma warning(pop)
0112 #endif
0113
0114 #undef BOOST_SPIRIT_ABSOLUTE_VALUE
0115 #undef BOOST_SPIRIT_ABSOLUTE_VALUE_UNSIGNED
0116
0117 template <>
0118 struct absolute_value<float>
0119 {
0120 typedef float type;
0121 static type call(float n)
0122 {
0123 return (std::fabs)(n);
0124 }
0125 };
0126
0127 template <>
0128 struct absolute_value<double>
0129 {
0130 typedef double type;
0131 static type call(double n)
0132 {
0133 return (std::fabs)(n);
0134 }
0135 };
0136
0137 template <>
0138 struct absolute_value<long double>
0139 {
0140 typedef long double type;
0141 static type call(long double n)
0142 {
0143 return (std::fabs)(n);
0144 }
0145 };
0146
0147
0148 template <typename T>
0149 struct absolute_value<T*>
0150 {
0151 typedef std::size_t type;
0152 static type call (T* p)
0153 {
0154 return std::size_t(p);
0155 }
0156 };
0157
0158 template <typename T>
0159 inline typename absolute_value<T>::type
0160 get_absolute_value(T n)
0161 {
0162 return absolute_value<T>::call(n);
0163 }
0164
0165
0166 template <typename T, typename Enable>
0167 struct is_negative
0168 {
0169 static bool call(T n)
0170 {
0171 return (n < 0) ? true : false;
0172 }
0173 };
0174
0175 template <>
0176 struct is_negative<float>
0177 {
0178 static bool call(float n)
0179 {
0180 return (core::signbit)(n) ? true : false;
0181 }
0182 };
0183
0184 template <>
0185 struct is_negative<double>
0186 {
0187 static bool call(double n)
0188 {
0189 return (core::signbit)(n) ? true : false;
0190 }
0191 };
0192
0193 template <>
0194 struct is_negative<long double>
0195 {
0196 static bool call(long double n)
0197 {
0198 return (core::signbit)(n) ? true : false;
0199 }
0200 };
0201
0202 template <typename T>
0203 inline bool test_negative(T n)
0204 {
0205 return is_negative<T>::call(n);
0206 }
0207
0208
0209 template <typename T, typename Enable>
0210 struct is_zero
0211 {
0212 static bool call(T n)
0213 {
0214 return (n == 0) ? true : false;
0215 }
0216 };
0217
0218 template <>
0219 struct is_zero<float>
0220 {
0221 static bool call(float n)
0222 {
0223 return (core::fpclassify)(n) == core::fp_zero;
0224 }
0225 };
0226
0227 template <>
0228 struct is_zero<double>
0229 {
0230 static bool call(double n)
0231 {
0232 return (core::fpclassify)(n) == core::fp_zero;
0233 }
0234 };
0235
0236 template <>
0237 struct is_zero<long double>
0238 {
0239 static bool call(long double n)
0240 {
0241 return (core::fpclassify)(n) == core::fp_zero;
0242 }
0243 };
0244
0245 template <typename T>
0246 inline bool test_zero(T n)
0247 {
0248 return is_zero<T>::call(n);
0249 }
0250
0251
0252 template <typename T, typename Enable>
0253 struct is_nan
0254 {
0255 static bool call(T n)
0256 {
0257
0258 return (n != n) ? true : false;
0259 }
0260 };
0261
0262 template <>
0263 struct is_nan<float>
0264 {
0265 static bool call(float n)
0266 {
0267 return (core::fpclassify)(n) == core::fp_nan;
0268 }
0269 };
0270
0271 template <>
0272 struct is_nan<double>
0273 {
0274 static bool call(double n)
0275 {
0276 return (core::fpclassify)(n) == core::fp_nan;
0277 }
0278 };
0279
0280 template <>
0281 struct is_nan<long double>
0282 {
0283 static bool call(long double n)
0284 {
0285 return (core::fpclassify)(n) == core::fp_nan;
0286 }
0287 };
0288
0289 template <typename T>
0290 inline bool test_nan(T n)
0291 {
0292 return is_nan<T>::call(n);
0293 }
0294
0295
0296 template <typename T, typename Enable>
0297 struct is_infinite
0298 {
0299 static bool call(T n)
0300 {
0301 return std::numeric_limits<T>::has_infinity
0302 && n == std::numeric_limits<T>::infinity();
0303 }
0304 };
0305
0306 template <>
0307 struct is_infinite<float>
0308 {
0309 static bool call(float n)
0310 {
0311 return (core::fpclassify)(n) == core::fp_infinite;
0312 }
0313 };
0314
0315 template <>
0316 struct is_infinite<double>
0317 {
0318 static bool call(double n)
0319 {
0320 return (core::fpclassify)(n) == core::fp_infinite;
0321 }
0322 };
0323
0324 template <>
0325 struct is_infinite<long double>
0326 {
0327 static bool call(long double n)
0328 {
0329 return (core::fpclassify)(n) == core::fp_infinite;
0330 }
0331 };
0332
0333 template <typename T>
0334 inline bool test_infinite(T n)
0335 {
0336 return is_infinite<T>::call(n);
0337 }
0338
0339
0340 struct cast_to_long
0341 {
0342 static long call(float n, mpl::false_)
0343 {
0344 return static_cast<long>(std::floor(n));
0345 }
0346
0347 static long call(double n, mpl::false_)
0348 {
0349 return static_cast<long>(std::floor(n));
0350 }
0351
0352 static long call(long double n, mpl::false_)
0353 {
0354 return static_cast<long>(std::floor(n));
0355 }
0356
0357 template <typename T>
0358 static long call(T n, mpl::false_)
0359 {
0360
0361
0362 using namespace std;
0363 return lround(floor(n));
0364 }
0365
0366 template <typename T>
0367 static long call(T n, mpl::true_)
0368 {
0369 return static_cast<long>(n);
0370 }
0371
0372 template <typename T>
0373 static long call(T n)
0374 {
0375 return call(n, mpl::bool_<is_integral<T>::value>());
0376 }
0377 };
0378
0379
0380 struct truncate_to_long
0381 {
0382 static long call(float n, mpl::false_)
0383 {
0384 return test_negative(n) ? static_cast<long>(std::ceil(n)) :
0385 static_cast<long>(std::floor(n));
0386 }
0387
0388 static long call(double n, mpl::false_)
0389 {
0390 return test_negative(n) ? static_cast<long>(std::ceil(n)) :
0391 static_cast<long>(std::floor(n));
0392 }
0393
0394 static long call(long double n, mpl::false_)
0395 {
0396 return test_negative(n) ? static_cast<long>(std::ceil(n)) :
0397 static_cast<long>(std::floor(n));
0398 }
0399
0400 template <typename T>
0401 static long call(T n, mpl::false_)
0402 {
0403
0404 using namespace std;
0405 return ltrunc(n);
0406 }
0407
0408 template <typename T>
0409 static long call(T n, mpl::true_)
0410 {
0411 return static_cast<long>(n);
0412 }
0413
0414 template <typename T>
0415 static long call(T n)
0416 {
0417 return call(n, mpl::bool_<is_integral<T>::value>());
0418 }
0419 };
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 namespace detail
0432 {
0433 template <typename CharEncoding, typename Tag, bool radix_less_than_10>
0434 struct convert_digit
0435 {
0436 static int call(unsigned n)
0437 {
0438 if (n <= 9)
0439 return n + '0';
0440
0441 using spirit::char_class::convert;
0442 return convert<CharEncoding>::to(Tag(), n - 10 + 'a');
0443 }
0444 };
0445
0446 template <>
0447 struct convert_digit<unused_type, unused_type, false>
0448 {
0449 static int call(unsigned n)
0450 {
0451 if (n <= 9)
0452 return n + '0';
0453 return n - 10 + 'a';
0454 }
0455 };
0456
0457 template <typename CharEncoding, typename Tag>
0458 struct convert_digit<CharEncoding, Tag, true>
0459 {
0460 static int call(unsigned n)
0461 {
0462 return n + '0';
0463 }
0464 };
0465 }
0466
0467 template <unsigned Radix, typename CharEncoding, typename Tag>
0468 struct convert_digit
0469 : detail::convert_digit<CharEncoding, Tag, (Radix <= 10) ? true : false>
0470 {};
0471
0472
0473 template <unsigned Radix>
0474 struct divide
0475 {
0476 template <typename T>
0477 static T call(T& n, mpl::true_)
0478 {
0479 return n / Radix;
0480 }
0481
0482 template <typename T>
0483 static T call(T& n, mpl::false_)
0484 {
0485
0486 using namespace std;
0487 return floor(n / Radix);
0488 }
0489
0490 template <typename T>
0491 static T call(T& n, T const&, int)
0492 {
0493 return call(n, mpl::bool_<is_integral<T>::value>());
0494 }
0495
0496 template <typename T>
0497 static T call(T& n)
0498 {
0499 return call(n, mpl::bool_<is_integral<T>::value>());
0500 }
0501 };
0502
0503
0504 template <>
0505 struct divide<10>
0506 {
0507 template <typename T>
0508 static T call(T& n, T, int, mpl::true_)
0509 {
0510 return n / 10;
0511 }
0512
0513 template <typename T>
0514 static T call(T, T& num, int exp, mpl::false_)
0515 {
0516
0517 using namespace std;
0518 return floor(num / spirit::traits::pow10<T>(exp));
0519 }
0520
0521 template <typename T>
0522 static T call(T& n, T& num, int exp)
0523 {
0524 return call(n, num, exp, mpl::bool_<is_integral<T>::value>());
0525 }
0526
0527 template <typename T>
0528 static T call(T& n)
0529 {
0530 return call(n, n, 1, mpl::bool_<is_integral<T>::value>());
0531 }
0532 };
0533
0534
0535 template <unsigned Radix>
0536 struct remainder
0537 {
0538 template <typename T>
0539 static long call(T n, mpl::true_)
0540 {
0541
0542
0543 return static_cast<long>(n % Radix);
0544 }
0545
0546 template <typename T>
0547 static long call(T n, mpl::false_)
0548 {
0549
0550 using namespace std;
0551 return cast_to_long::call(fmod(n, T(Radix)));
0552 }
0553
0554 template <typename T>
0555 static long call(T n)
0556 {
0557 return call(n, mpl::bool_<is_integral<T>::value>());
0558 }
0559 };
0560 }}}
0561
0562 namespace boost { namespace spirit { namespace karma
0563 {
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575 #define BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX(z, x, data) \
0576 if (!traits::test_zero(n)) { \
0577 int ch_##x = radix_type::call(remainder_type::call(n)); \
0578 n = divide_type::call(n, num, ++exp); \
0579
0580
0581 #define BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX(z, x, n_rolls_sub1) \
0582 *sink = char(BOOST_PP_CAT(ch_, BOOST_PP_SUB(n_rolls_sub1, x))); \
0583 ++sink; \
0584 } \
0585
0586
0587 template <
0588 unsigned Radix, typename CharEncoding = unused_type
0589 , typename Tag = unused_type>
0590 struct int_inserter
0591 {
0592 typedef traits::convert_digit<Radix, CharEncoding, Tag> radix_type;
0593 typedef traits::divide<Radix> divide_type;
0594 typedef traits::remainder<Radix> remainder_type;
0595
0596 template <typename OutputIterator, typename T>
0597 static bool
0598 call(OutputIterator& sink, T n, T& num, int exp)
0599 {
0600
0601 int ch = radix_type::call(remainder_type::call(n));
0602 n = divide_type::call(n, num, ++exp);
0603
0604 BOOST_PP_REPEAT(
0605 BOOST_KARMA_NUMERICS_LOOP_UNROLL,
0606 BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX, _);
0607
0608 if (!traits::test_zero(n))
0609 call(sink, n, num, exp);
0610
0611 BOOST_PP_REPEAT(
0612 BOOST_KARMA_NUMERICS_LOOP_UNROLL,
0613 BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX,
0614 BOOST_PP_DEC(BOOST_KARMA_NUMERICS_LOOP_UNROLL));
0615
0616 *sink = char(ch);
0617 ++sink;
0618 return true;
0619 }
0620
0621
0622 template <typename OutputIterator, typename T>
0623 static bool
0624 call(OutputIterator& sink, T n)
0625 {
0626 return call(sink, n, n, 0);
0627 }
0628
0629 private:
0630
0631
0632
0633 #if defined(BOOST_HAS_LONG_LONG)
0634 typedef boost::long_long_type biggest_long_type;
0635 #else
0636 typedef long biggest_long_type;
0637 #endif
0638
0639 static biggest_long_type max_long()
0640 {
0641 return (std::numeric_limits<biggest_long_type>::max)();
0642 }
0643
0644 public:
0645
0646
0647
0648
0649 template <typename OutputIterator>
0650 static bool
0651 call(OutputIterator& sink, long double n)
0652 {
0653 if (std::fabs(n) < max_long())
0654 {
0655 biggest_long_type l((biggest_long_type)n);
0656 return call(sink, l, l, 0);
0657 }
0658 return call(sink, n, n, 0);
0659 }
0660 template <typename OutputIterator>
0661 static bool
0662 call(OutputIterator& sink, double n)
0663 {
0664 if (std::fabs(n) < max_long())
0665 {
0666 biggest_long_type l((biggest_long_type)n);
0667 return call(sink, l, l, 0);
0668 }
0669 return call(sink, n, n, 0);
0670 }
0671 template <typename OutputIterator>
0672 static bool
0673 call(OutputIterator& sink, float n)
0674 {
0675 if (std::fabs(n) < max_long())
0676 {
0677 biggest_long_type l((biggest_long_type)n);
0678 return call(sink, l, l, 0);
0679 }
0680 return call(sink, n, n, 0);
0681 }
0682 };
0683
0684 #undef BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX
0685 #undef BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX
0686
0687
0688
0689
0690
0691
0692
0693 template <
0694 unsigned Radix, typename CharEncoding = unused_type
0695 , typename Tag = unused_type>
0696 struct uint_inserter : int_inserter<Radix, CharEncoding, Tag>
0697 {
0698 typedef int_inserter<Radix, CharEncoding, Tag> base_type;
0699
0700
0701 template <typename OutputIterator, typename T>
0702 static bool
0703 call(OutputIterator& sink, T const& n)
0704 {
0705 typedef typename traits::absolute_value<T>::type type;
0706 type un = type(n);
0707 return base_type::call(sink, un, un, 0);
0708 }
0709 };
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719 struct sign_inserter
0720 {
0721 template <typename OutputIterator>
0722 static bool
0723 call_noforce(OutputIterator& sink, bool is_zero, bool is_negative,
0724 bool sign_if_zero)
0725 {
0726
0727 if (is_negative || (is_zero && sign_if_zero)) {
0728 *sink = '-';
0729 ++sink;
0730 }
0731 return true;
0732 }
0733
0734 template <typename OutputIterator>
0735 static bool
0736 call_force(OutputIterator& sink, bool is_zero, bool is_negative,
0737 bool sign_if_zero)
0738 {
0739
0740 if (!is_zero || sign_if_zero)
0741 *sink = is_negative ? '-' : '+';
0742 else
0743 *sink = ' ';
0744
0745 ++sink;
0746 return true;
0747 }
0748
0749 template <typename OutputIterator>
0750 static bool
0751 call(OutputIterator& sink, bool is_zero, bool is_negative
0752 , bool forcesign, bool sign_if_zero = false)
0753 {
0754 return forcesign ?
0755 call_force(sink, is_zero, is_negative, sign_if_zero) :
0756 call_noforce(sink, is_zero, is_negative, sign_if_zero);
0757 }
0758 };
0759
0760
0761
0762
0763
0764 template <typename CharEncoding = unused_type, typename Tag = unused_type>
0765 struct char_inserter
0766 {
0767 template <typename OutputIterator, typename Char>
0768 static bool call(OutputIterator& sink, Char c)
0769 {
0770 return detail::generate_to(sink, c, CharEncoding(), Tag());
0771 }
0772 };
0773
0774 template <typename CharEncoding = unused_type, typename Tag = unused_type>
0775 struct string_inserter
0776 {
0777 template <typename OutputIterator, typename String>
0778 static bool call(OutputIterator& sink, String str)
0779 {
0780 return detail::string_generate(sink, str, CharEncoding(), Tag());
0781 }
0782 };
0783
0784 }}}
0785
0786 #endif