diff --git a/const_fmt/format.h b/const_fmt/format.h index e300e78..091864c 100644 --- a/const_fmt/format.h +++ b/const_fmt/format.h @@ -42,12 +42,12 @@ constexpr inline void check_fmt_params() { template constexpr inline void format_arg(char* dest, arg_t arg) { - const_fmt_detail::format_int(dest, arg); + const_fmt_detail::format_int(dest, arg); }; template constexpr inline void format_arg(char* dest, arg_t arg){ - const_fmt_detail::format_float(dest, arg); + const_fmt_detail::format_float(dest, arg); }; // TODO: Error handling diff --git a/const_fmt/format_impl.h b/const_fmt/format_impl.h index c91aa0f..fdbb6bd 100644 --- a/const_fmt/format_impl.h +++ b/const_fmt/format_impl.h @@ -58,22 +58,40 @@ inline int do_count_digits(uint64_t n) { return t - (n < zero_or_powers_of_10[t]); } -constexpr inline auto count_digits(uint64_t n) -> int { - if (!std::is_constant_evaluated()) { - return do_count_digits(n); +template +constexpr inline auto count_digits_base(uint64_t n) -> int { + if constexpr (t_format_type == FormatType::b) { + int result = 0; + + while (n) { + n = n >> 1; + result += 1; + } + + return result; + } else { + if (!std::is_constant_evaluated()) { + return do_count_digits(n); + } + + return count_digits_fallback(n); } - return count_digits_fallback(n); } -// Converts value in the range [0, 100) to a string. -constexpr inline const char* digits2(size_t value) { +// Converts value in the range [0, base^2) to a string. +template +constexpr inline const char* digits2_base(size_t value) { // GCC generates slightly better code when value is pointer-size. - return &"0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"[value * 2]; + if constexpr (t_format_type == FormatType::b) { + return &"00011011"[value * 2]; + } else { + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; + } } @@ -86,9 +104,13 @@ constexpr inline void copy2(char* dst, const char* src) { *dst = static_cast(*src); } -template -constexpr inline void format_decimal(char* out, uint_t value, int n_digits, - int size) { + +template +constexpr inline void format_base(char* out, uint_t value, int n_digits, + int size) { + constexpr unsigned divisor = (t_format_type == FormatType::b) ? 2 : 10; + constexpr unsigned square_divisor = const_pow(divisor, 2); + if (n_digits > size) { for (int i = 0; i < size; ++i) { *(out++) = 'f'; @@ -97,19 +119,20 @@ constexpr inline void format_decimal(char* out, uint_t value, int n_digits, } out += size; - while (value >= 100) { + while (value >= square_divisor) { out -= 2; - copy2(out, digits2(static_cast(value % 100))); - value /= 100; + copy2(out, digits2_base( + static_cast(value % square_divisor))); + value /= square_divisor; } - if (value < 10) { + if (value < divisor) { *--out = static_cast('0' + value); return; } out -= 2; - copy2(out, digits2(static_cast(value))); + copy2(out, digits2_base(static_cast(value))); } // returns {abs_value, was_negative} @@ -139,19 +162,22 @@ constexpr std::pair get_abs_value(int_t value) { */ -template +template constexpr inline void format_int(char* out, uint_t value) { - format_decimal(out, value, count_digits(value), t_fmt_node.length); + // format_decimal(out, value, count_digits(value), t_fmt_node.length); + format_base(out, value, count_digits_base(value), + t_fmt_node.length); } -template + +template constexpr inline void format_int(char* out, int_t value) { const auto [abs_value, negative] = get_abs_value(value); - const std::size_t n_digits = count_digits(abs_value); + const std::size_t n_digits = count_digits_base(abs_value); - format_decimal(out + 1 * (negative), abs_value, n_digits, - t_fmt_node.length - 1 * (negative)); + format_base(out + 1 * (negative), abs_value, n_digits, + t_fmt_node.length - 1 * (negative)); if constexpr (t_fmt_node.has_zero_padding) { if (negative) *(out) = '-'; @@ -169,21 +195,21 @@ constexpr inline void format_int(char* out, int_t value) { */ -template +template constexpr inline void format_float(char* out, float_t value) { // clang-format off constexpr fmt_data_t fmt_node_integral = { t_fmt_node.has_zero_padding, // has_zero_padding t_fmt_node.length - t_fmt_node.precision - 1, // length t_fmt_node.precision, // ignored - t_fmt_node.type, // ignored + FormatType::d, // type t_fmt_node.position // ignored }; constexpr fmt_data_t fmt_node_fractional = { true, // has_zero_padding t_fmt_node.precision, // length t_fmt_node.precision, // ignored - t_fmt_node.type, // ignored + FormatType::d, // type t_fmt_node.position // ignored }; // clang-format on @@ -198,8 +224,8 @@ constexpr inline void format_float(char* out, float_t value) { const auto [fractional_abs, fractional_negative] = get_abs_value(fractional); - format_int(out, integral); - format_int( + format_int(out, integral); + format_int( out + t_fmt_node.length - t_fmt_node.precision, fractional_abs); } diff --git a/examples/src/examples.cpp b/examples/src/examples.cpp index 5edb7ff..5259663 100644 --- a/examples/src/examples.cpp +++ b/examples/src/examples.cpp @@ -5,7 +5,7 @@ using namespace const_fmt; int main() { - constexpr auto s = "This is an integer: {:08}, and this is a float: {:09.4}"_const_fmt(12345, -86.2); + constexpr auto s = "This is an integer: {:08b}, and this is a float: {:09.4b}"_const_fmt(125u, -86.2); // Convert s (with a type of 'std::array') into something // writable to std::cout diff --git a/test/src/format.cpp b/test/src/format.cpp deleted file mode 100644 index d60712a..0000000 --- a/test/src/format.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include - - -using namespace const_fmt; -using namespace const_fmt::const_fmt_detail; - - -TEST(FormatDecimal, positive_int) { - constexpr std::array control1 = {'0', '0', '0', '0', - '0', '0', '0', '2'}; - constexpr std::array formatted1 = const_format<"{:08}">(2); - - constexpr std::array control2 = {' ', ' ', ' ', '2', - '2', '2', '2', '2'}; - constexpr std::array formatted2 = const_format<"{:8}">(22222); - - constexpr std::array control3 = {'0', '0', '0', '1', - '2', '3', '4', '5'}; - constexpr std::array formatted3 = const_format<"{:08.4}">(12345); - - constexpr std::array control4 = {'6', '7', '8', '9'}; - constexpr std::array formatted4 = const_format<"{:4}">(6789); - - constexpr std::array control5 = {'f', 'f', 'f', 'f'}; - constexpr std::array formatted5 = const_format<"{:4}">(67895); - - EXPECT_EQ(control1, formatted1); - EXPECT_EQ(control2, formatted2); - EXPECT_EQ(control3, formatted3); - EXPECT_EQ(control4, formatted4); - EXPECT_EQ(control5, formatted5); -} - -TEST(FormatDecimal, negative_int) { - constexpr std::array control1 = {'-', '0', '0', '0', - '0', '0', '0', '2'}; - constexpr std::array formatted1 = const_format<"{:08}">(-2); - - constexpr std::array control2 = {' ', ' ', '-', '2', - '2', '2', '2', '2'}; - constexpr std::array formatted2 = const_format<"{:8}">(-22222); - - constexpr std::array control3 = {'-', '0', '0', '1', - '2', '3', '4', '5'}; - constexpr std::array formatted3 = const_format<"{:08.4}">(-12345); - - constexpr std::array control4 = {'-', '6', '7', '8', '9'}; - constexpr std::array formatted4 = const_format<"{:5}">(-6789); - - constexpr std::array control5 = {'-', 'f', 'f', 'f', 'f'}; - constexpr std::array formatted5 = const_format<"{:05}">(-66789); - - EXPECT_EQ(control1, formatted1); - EXPECT_EQ(control2, formatted2); - EXPECT_EQ(control3, formatted3); - EXPECT_EQ(control4, formatted4); - EXPECT_EQ(control5, formatted5); -} - -TEST(FormatDecimal, positive_float) { - constexpr std::array control1 = {'0', '0', '2', '.', - '3', '4', '5', '6'}; - constexpr std::array formatted1 = const_format<"{:08.4}">(2.3456); - - // Float error: 2323.2 -> 2323.1 - constexpr std::array control2 = {' ', ' ', '2', '3', - '2', '3', '.', '1'}; - constexpr std::array formatted2 = const_format<"{:8.1}">(2323.2); - - constexpr std::array control3 = {'1', '2', '3', '4', - '.', '5', '0', '0'}; - constexpr std::array formatted3 = const_format<"{:08.3}">(1234.5); - - // Float error: .9 -> .8 - constexpr std::array control4 = {'f', 'f', '.', '8'}; - constexpr std::array formatted4 = const_format<"{:4.1}">(678.9); - - EXPECT_EQ(control1, formatted1); - EXPECT_EQ(control2, formatted2); - EXPECT_EQ(control3, formatted3); - EXPECT_EQ(control4, formatted4); -} - -TEST(FormatDecimal, negative_float) { - constexpr std::array control1 = {'-', '0', '2', '.', - '3', '4', '5', '6'}; - constexpr std::array formatted1 = const_format<"{:08.4}">(-2.3456); - - // Float error: 2323.2 -> 2323.1 - constexpr std::array control2 = {' ', '-', '2', '3', - '2', '3', '.', '1'}; - constexpr std::array formatted2 = const_format<"{:8.1}">(-2323.2); - - constexpr std::array control3 = {'-', 'f', 'f', 'f', - '.', '5', '0', '0'}; - constexpr std::array formatted3 = const_format<"{:08.3}">(-1234.5); - - - EXPECT_EQ(control1, formatted1); - EXPECT_EQ(control2, formatted2); - EXPECT_EQ(control3, formatted3); -} \ No newline at end of file diff --git a/test/src/format_binary.cpp b/test/src/format_binary.cpp index c5873b2..c8456fc 100644 --- a/test/src/format_binary.cpp +++ b/test/src/format_binary.cpp @@ -1,4 +1,4 @@ -#include +#include #include