diff --git a/src/web/WebUtils.C b/src/web/WebUtils.C index 904c5ac..58093be 100644 --- a/src/web/WebUtils.C +++ b/src/web/WebUtils.C @@ -24,6 +24,11 @@ #include #endif // WIN32 +#ifndef WT_NO_SPIRIT +#include +#include +#endif // WT_NO_SPIRIT + namespace Wt { namespace Utils { @@ -177,34 +182,91 @@ char *pad_itoa(int value, int length, char *result) { return result; } -char *round_str(double d, int digits, char *buf) { - static const int exp[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; - - long long i = static_cast(d * exp[digits] + (d > 0 ? 0.49 : -0.49)); - lltoa(i, buf); - char *num = buf; - - if (num[0] == '-') - ++num; - int len = std::strlen(num); - - if (len <= digits) { - int shift = digits + 1 - len; - for (int i = digits + 1; i >= 0; --i) { - if (i >= shift) - num[i] = num[i - shift]; - else - num[i] = '0'; +#ifndef WT_NO_SPIRIT +namespace { + using namespace boost::spirit; + using namespace boost::spirit::karma; + + // adjust rendering of nan and infinity: nan -> NaN; inf -> Infinity + template + struct JavaScriptPolicy : karma::real_policies + { + template + static bool nan (OutputIterator& sink, T n, bool force_sign) + { + return sign_inserter::call( + sink, false, traits::test_negative(n), force_sign) && + string_inserter::call(sink, "NaN"); } - len = digits + 1; - } - int dotPos = (std::max)(len - digits, 0); - for (int i = digits + 1; i >= 0; --i) - num[dotPos + i + 1] = num[dotPos + i]; - num[dotPos] = '.'; + template + static bool inf (OutputIterator& sink, T n, bool force_sign) + { + return sign_inserter::call( + sink, false, traits::test_negative(n), force_sign) && + string_inserter::call(sink, "Infinity"); + } + }; + + typedef real_generator > KarmaJavaScriptDouble; + +} + +static inline char *generic_double_to_str(double d, char *buf) +{ + using namespace boost::spirit; + using namespace boost::spirit::karma; + char *p = buf; + generate(p, KarmaJavaScriptDouble(), d); + *p = '\0'; return buf; } +#else +static inline char *generic_double_to_str(double d, char *buf) +{ + sprintf(buf, "%f", (float)d); + return buf; +} +#endif + +char *round_str(double d, int digits, char *buf) { +#ifndef WT_NO_SPIRIT + return generic_double_to_str(d, buf); +#else + if (((d > 1 && d < 1000000) || (d < -1 && d > -1000000)) && digits < 7) { + // range where a very fast float->string converter works + // mainly intended to render floats for 2D drawing canvas + static const int exp[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; + + long long i = static_cast(d * exp[digits] + (d > 0 ? 0.49 : -0.49)); + lltoa(i, buf); + char *num = buf; + + if (num[0] == '-') + ++num; + int len = std::strlen(num); + + if (len <= digits) { + int shift = digits + 1 - len; + for (int i = digits + 1; i >= 0; --i) { + if (i >= shift) + num[i] = num[i - shift]; + else + num[i] = '0'; + } + len = digits + 1; + } + int dotPos = (std::max)(len - digits, 0); + for (int i = digits + 1; i >= 0; --i) + num[dotPos + i + 1] = num[dotPos + i]; + num[dotPos] = '.'; + return buf; + } else { + // an implementation that covers everything + return generic_double_to_str(d, buf); + } +#endif +} std::string urlEncode(const std::string& url, const std::string& allowed) {