diff --git a/sprout/string/float_to_string.hpp b/sprout/string/float_to_string.hpp index 545694ef..b4e7a909 100644 --- a/sprout/string/float_to_string.hpp +++ b/sprout/string/float_to_string.hpp @@ -2,14 +2,11 @@ #define SPROUT_STRING_FLOAT_TO_STRING_HPP #include -#include #include #include #include #include #include -#include -#include #include #include @@ -25,113 +22,84 @@ namespace sprout { struct printed_float_digits : public std::integral_constant< std::size_t, - /*std::numeric_limits::max_exponent10 + sprout::detail::decimal_places_length + 3*/ - sprout::integer_digits::value + sprout::detail::decimal_places_length + 3 + std::numeric_limits::max_exponent10 + sprout::detail::decimal_places_length + 2 > {}; namespace detail { template - inline SPROUT_CONSTEXPR unsigned float_extract_rounded_impl(FloatType val) { - return static_cast(val * 1000000) - + (static_cast(val * 10000000) % 10 >= 5 ? 1 : 0) + inline SPROUT_CONSTEXPR FloatType + float_pow10(int exponent) { + return exponent ? FloatType(10) * sprout::detail::float_pow10(exponent - 1) + : FloatType(1) + ; + } + + template + inline SPROUT_CONSTEXPR int + float_digits_impl(FloatType val) { + return !(val < 1 && val > -1) ? 1 + sprout::detail::float_digits_impl(val / 10) + : 0 ; } template - inline SPROUT_CONSTEXPR unsigned float_extract_rounded(FloatType val) { + inline SPROUT_CONSTEXPR int + float_digits(FloatType val) { + return !(val < 1 && val > -1) ? 1 + sprout::detail::float_digits_impl(val / 10) + : 1 + ; + } + + template + inline SPROUT_CONSTEXPR int + float_digit_of_impl(FloatType val) { using std::floor; - return sprout::detail::float_extract_rounded_impl(val - floor(val)); + return static_cast((val - floor(val)) * 10); } - - template< - typename Elem, - typename FloatType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) == sprout::printed_float_digits::value - 1)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string_impl_1(FloatType val, bool negative, Args... args) { - return negative ? sprout::make_string_as(static_cast('-'), args...) - : sprout::make_string_as(args...) - ; - } - template< - typename Elem, - typename FloatType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) < sprout::printed_float_digits::value - 1)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string_impl_1(FloatType val, bool negative, Args... args) { - return !(val < 1) ? sprout::detail::float_to_string_impl_1( - val / 10, - negative, - sprout::detail::int_to_char(static_cast(val) % 10), - args... - ) - : negative ? sprout::make_string_as(static_cast('-'), args...) - : sprout::make_string_as(args...) + template + inline SPROUT_CONSTEXPR int + float_digit_of(FloatType val, int digits) { + return digits < 0 ? sprout::detail::float_digit_of_impl(val * sprout::detail::float_pow10(-digits - 1)) + : sprout::detail::float_digit_of_impl(val / sprout::detail::float_pow10(digits + 1)) ; } - template< - typename Elem, - typename FloatType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) == sprout::printed_float_digits::value - 3)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string_impl(FloatType val, bool negative, unsigned temp, std::size_t decimal_digits, Args... args) { - return negative ? sprout::make_string_as(static_cast('-'), static_cast('0'), static_cast('.'), args...) - : sprout::make_string_as(static_cast('0'), static_cast('.'), args...) - ; + template + inline SPROUT_CONSTEXPR FloatType + float_round_impl(FloatType val, FloatType p10) { + using std::round; + return round(val * p10) / p10; } - template< - typename Elem, - typename FloatType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) < sprout::printed_float_digits::value - 3)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string_impl(FloatType val, bool negative, unsigned temp, std::size_t decimal_digits, Args... args) { - return decimal_digits ? sprout::detail::float_to_string_impl( - val, - negative, - temp / 10, - decimal_digits - 1, - sprout::detail::int_to_char(temp % 10), - args... - ) - : !(val < 1) ? sprout::detail::float_to_string_impl_1( - val, - negative, - static_cast('.'), - args... - ) - : negative ? sprout::make_string_as(static_cast('-'), static_cast('0'), static_cast('.'), args...) - : sprout::make_string_as(static_cast('0'), static_cast('.'), args...) - ; + template + inline SPROUT_CONSTEXPR FloatType + float_round(FloatType val, int digits) { + return sprout::detail::float_round_impl(val, sprout::detail::float_pow10(digits)); } - template< - typename Elem, - typename FloatType - > + template inline SPROUT_CONSTEXPR sprout::basic_string::value> - float_to_string(FloatType val) { - using std::floor; - return val < 0 ? sprout::detail::float_to_string_impl( - -val, - true, - sprout::detail::float_extract_rounded(-val), - sprout::detail::decimal_places_length - ) - : sprout::detail::float_to_string_impl( - val, - false, - sprout::detail::float_extract_rounded(val), - sprout::detail::decimal_places_length - ) + float_to_string(FloatType val, bool negative, int digits, sprout::index_tuple) { + return negative ? sprout::basic_string::value>{ + { + static_cast('-'), + (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::float_digit_of(val, digits - 1 - Indexes)) + : Indexes == digits ? static_cast('.') + : Indexes < digits + 1 + sprout::detail::decimal_places_length ? sprout::detail::int_to_char(sprout::detail::float_digit_of(val, digits - Indexes)) + : Elem() + )... + }, + static_cast(digits + 2 + sprout::detail::decimal_places_length) + } + : sprout::basic_string::value>{ + { + (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::float_digit_of(val, digits - 1 - Indexes)) + : Indexes == digits ? static_cast('.') + : Indexes < digits + 1 + sprout::detail::decimal_places_length ? sprout::detail::int_to_char(sprout::detail::float_digit_of(val, digits - Indexes)) + : Elem() + )... + }, + static_cast(digits + 1 + sprout::detail::decimal_places_length) + } ; } } // namespace detail @@ -146,7 +114,12 @@ namespace sprout { > inline SPROUT_CONSTEXPR sprout::basic_string::value> float_to_string(FloatType val) { - return sprout::detail::float_to_string(val); + return sprout::detail::float_to_string( + sprout::detail::float_round(val < 0 ? -val : val, sprout::detail::decimal_places_length), + val < 0, + sprout::detail::float_digits(val), + sprout::index_range<0, sprout::printed_float_digits::value - 1>::make() + ); } // diff --git a/sprout/string/int_to_string.hpp b/sprout/string/int_to_string.hpp index 36c9cb6a..c9edbb67 100644 --- a/sprout/string/int_to_string.hpp +++ b/sprout/string/int_to_string.hpp @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -23,82 +23,34 @@ namespace sprout { {}; namespace detail { - template< - typename Elem, - int Base, - typename IntType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) == sprout::printed_integer_digits::value - 1)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - int_to_string_impl_1(IntType val, bool negative, Args... args) { - return negative ? sprout::make_string_as(static_cast('-'), args...) - : sprout::make_string_as(args...) - ; - } - template< - typename Elem, - int Base, - typename IntType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) < sprout::printed_integer_digits::value - 1)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - int_to_string_impl_1(IntType val, bool negative, Args... args) { - return val == 0 - ? (negative ? sprout::make_string_as(static_cast('-'), args...) - : sprout::make_string_as(args...) - ) - : sprout::detail::int_to_string_impl_1( - val / Base, - negative, - sprout::detail::int_to_char(negative ? -(val % Base) : val % Base, Base), - args... - ) - ; - } - template - inline SPROUT_CONSTEXPR sprout::basic_string::value> - int_to_string_impl(IntType val) { - return val == 0 ? sprout::make_string_as(static_cast('0')) - : sprout::detail::int_to_string_impl_1(val, val < 0) + template + inline SPROUT_CONSTEXPR IntType + int_pow(int exponent) { + return exponent ? Base * sprout::detail::int_pow(exponent - 1) + : 1 ; } - template< - typename Elem, - int Base, - typename UIntType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) == sprout::printed_integer_digits::value)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - uint_to_string_impl_1(UIntType val, Args... args) { - return sprout::make_string_as(args...); - } - template< - typename Elem, - int Base, - typename UIntType, - typename... Args, - typename sprout::enabler_if<(sizeof...(Args) < sprout::printed_integer_digits::value)>::type = sprout::enabler - > - inline SPROUT_CONSTEXPR sprout::basic_string::value> - uint_to_string_impl_1(UIntType val, Args... args) { - return val == 0 - ? sprout::make_string_as(args...) - : sprout::detail::uint_to_string_impl_1( - val / Base, - sprout::detail::int_to_char(val % Base, Base), - args... - ) + template + inline SPROUT_CONSTEXPR int + int_digits_impl(IntType val) { + return val ? 1 + sprout::detail::int_digits_impl(val / Base) + : 0 ; } - template - inline SPROUT_CONSTEXPR sprout::basic_string::value> - uint_to_string_impl(UIntType val) { - return val == 0 ? sprout::make_string_as(static_cast('0')) - : sprout::detail::uint_to_string_impl_1(val) + template + inline SPROUT_CONSTEXPR int + int_digits(IntType val) { + return val ? 1 + sprout::detail::int_digits_impl(val / Base) + : 1 + ; + } + + template + inline SPROUT_CONSTEXPR int + int_digit_of(IntType val, int digits) { + return val < 0 ? -((val / sprout::detail::int_pow(digits)) % Base) + : (val / sprout::detail::int_pow(digits)) % Base ; } @@ -106,21 +58,47 @@ namespace sprout { typename Elem, int Base, typename IntType, + sprout::index_t... Indexes, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR sprout::basic_string::value> - int_to_string(IntType val) { - return sprout::detail::int_to_string_impl(val); + int_to_string(IntType val, int digits, sprout::index_tuple) { + return val < 0 ? sprout::basic_string::value>{ + { + static_cast('-'), + (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::int_digit_of(val, digits - 1 - Indexes)) + : Elem() + )... + }, + static_cast(digits + 1) + } + : sprout::basic_string::value>{ + { + (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::int_digit_of(val, digits - 1 - Indexes)) + : Elem() + )... + }, + static_cast(digits) + } + ; } template< typename Elem, int Base, typename IntType, + sprout::index_t... Indexes, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR sprout::basic_string::value> - int_to_string(IntType val) { - return sprout::detail::uint_to_string_impl(val); + int_to_string(IntType val, int digits, sprout::index_tuple) { + return sprout::basic_string::value>{ + { + (Indexes < digits ? sprout::detail::int_to_char(sprout::detail::int_digit_of(val, digits - 1 - Indexes)) + : Elem() + )... + }, + static_cast(digits) + }; } } // namespace detail @@ -135,7 +113,11 @@ namespace sprout { > inline SPROUT_CONSTEXPR sprout::basic_string::value> int_to_string(IntType val) { - return sprout::detail::int_to_string(val); + return sprout::detail::int_to_string( + val, + sprout::detail::int_digits(val), + sprout::index_range<0, sprout::integer_digits::value>::make() + ); } //