From f9099ce6ee857298cd26007b750f56523fb3d932 Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Tue, 15 Feb 2022 11:12:19 +0100 Subject: [PATCH 1/3] Added tests for count_digits_base, decimal, binary and hex --- test/CMakeLists.txt | 1 + test/src/format_utility.cpp | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/src/format_utility.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e53938b..c2818fe 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ endmacro() package_add_test(utility_test src/utility.cpp) package_add_test(parse_test src/parse.cpp) +package_add_test(format_utility_test src/format_utility.cpp) package_add_test(format_decimal_test src/format_decimal.cpp) package_add_test(format_binary_test src/format_binary.cpp) diff --git a/test/src/format_utility.cpp b/test/src/format_utility.cpp new file mode 100644 index 0000000..6a93193 --- /dev/null +++ b/test/src/format_utility.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + + +using namespace const_fmt; +using namespace const_fmt::const_fmt_detail; + + +TEST(FormatUtility, count_digits_base_decimal) { + constexpr unsigned length1 = count_digits_base(123); + constexpr unsigned length2 = count_digits_base(std::numeric_limits::max()); + constexpr unsigned length3 = count_digits_base(10000011); + constexpr unsigned length4 = count_digits_base(1); + + EXPECT_EQ(length1, 3); + EXPECT_EQ(length2, 20); + EXPECT_EQ(length3, 8); + EXPECT_EQ(length4, 1); +} + +TEST(FormatUtility, count_digits_base_binary) { + constexpr unsigned length1 = count_digits_base(0b1001); + constexpr unsigned length2 = count_digits_base(std::numeric_limits::max()); + constexpr unsigned length3 = count_digits_base(0b10000001); + constexpr unsigned length4 = count_digits_base(0b01); + + EXPECT_EQ(length1, 4); + EXPECT_EQ(length2, 64); + EXPECT_EQ(length3, 8); + EXPECT_EQ(length4, 1); +} + +TEST(FormatUtility, count_digits_base_hex) { + constexpr unsigned length1 = count_digits_base(0x123); + constexpr unsigned length2 = count_digits_base(std::numeric_limits::max()); + constexpr unsigned length3 = count_digits_base(0x1000000f); + constexpr unsigned length4 = count_digits_base(0x01); + + EXPECT_EQ(length1, 3); + EXPECT_EQ(length2, 16); + EXPECT_EQ(length3, 8); + EXPECT_EQ(length4, 1); +} From 7115e09acaa348e92011bac0b694d1cbfc9d1677 Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Tue, 15 Feb 2022 11:13:15 +0100 Subject: [PATCH 2/3] Implemented count_digits for hex and started implementing digits2_base --- const_fmt/format_impl.h | 55 +++++++++++++++++++++++++++++++-------- examples/src/examples.cpp | 2 +- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/const_fmt/format_impl.h b/const_fmt/format_impl.h index 26a6f1a..2bbc9be 100644 --- a/const_fmt/format_impl.h +++ b/const_fmt/format_impl.h @@ -70,11 +70,21 @@ constexpr inline auto count_digits_base(uint64_t n) -> int { return result; } else { - if (!std::is_constant_evaluated()) { - return do_count_digits_decimal(n); - } + if constexpr (t_format_type == FormatType::x) { + int result = 0; - return count_digits_decimal_fallback(n); + while (n) { + n = n >> 4; + result += 1; + } + + return (result + count_digits_base(n)); + } else { + if (!std::is_constant_evaluated()) { + return do_count_digits_decimal(n); + } + return count_digits_decimal_fallback(n); + } } } @@ -86,11 +96,24 @@ constexpr inline const char* digits2_base(size_t value) { if constexpr (t_format_type == FormatType::b) { return &"00011011"[value * 2]; } else { - return &"0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"[value * 2]; + if constexpr (t_format_type == FormatType::x) { + // clang-format off + return &"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" + "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" + "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F" + "606162636465666768696A6B6C6D6E6F707172737475767778796A6B6C6D6E6F" + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F" + "A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF" + "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"[value * 2]; + // clang-format on + } else { + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; + } } } @@ -104,11 +127,22 @@ constexpr inline void copy2(char* dst, const char* src) { *dst = static_cast(*src); } +template +consteval inline unsigned get_base_divisor() { + switch (t_format_type) { + case FormatType::b: + return 2; + case FormatType::x: + return 16; + default: + return 10; + } +} 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 divisor = get_base_divisor(); constexpr unsigned square_divisor = const_pow(divisor, 2); if (n_digits > size) { @@ -165,7 +199,6 @@ constexpr std::pair get_abs_value(int_t value) { template constexpr inline void format_int(char* out, uint_t value) { - // format_decimal(out, value, count_digits(value), t_fmt_node.length); format_base(out, value, count_digits_base(value), t_fmt_node.length); diff --git a/examples/src/examples.cpp b/examples/src/examples.cpp index 5259663..911f63c 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: {:08b}, and this is a float: {:09.4b}"_const_fmt(125u, -86.2); + constexpr auto s = "This is an integer: {:08x}, 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 From 2933676ea26d24ae0e2597b138335e3b50d6af57 Mon Sep 17 00:00:00 2001 From: Andreas Tsouchlos Date: Tue, 15 Feb 2022 11:34:49 +0100 Subject: [PATCH 3/3] Fixed bug in hex formatting, wrote tests for hex int formatting --- const_fmt/format_impl.h | 4 +-- examples/src/examples.cpp | 2 +- test/CMakeLists.txt | 1 + test/src/format_hex.cpp | 59 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 test/src/format_hex.cpp diff --git a/const_fmt/format_impl.h b/const_fmt/format_impl.h index 2bbc9be..8ca5143 100644 --- a/const_fmt/format_impl.h +++ b/const_fmt/format_impl.h @@ -101,7 +101,7 @@ constexpr inline const char* digits2_base(size_t value) { return &"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F" - "606162636465666768696A6B6C6D6E6F707172737475767778796A6B6C6D6E6F" + "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F" "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F" "A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF" @@ -161,7 +161,7 @@ constexpr inline void format_base(char* out, uint_t value, int n_digits, } if (value < divisor) { - *--out = static_cast('0' + value); + *--out = digits2_base(value*divisor)[0]; return; } diff --git a/examples/src/examples.cpp b/examples/src/examples.cpp index 911f63c..e955122 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: {:08x}, and this is a float: {:09.4b}"_const_fmt(125u, -86.2); + constexpr auto s = "This is an integer: {:08x}, and this is a float: {:09.4b}"_const_fmt(122u, -86.2); // Convert s (with a type of 'std::array') into something // writable to std::cout diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c2818fe..13950f3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,4 +28,5 @@ package_add_test(parse_test src/parse.cpp) package_add_test(format_utility_test src/format_utility.cpp) package_add_test(format_decimal_test src/format_decimal.cpp) package_add_test(format_binary_test src/format_binary.cpp) +package_add_test(format_hex_test src/format_hex.cpp) diff --git a/test/src/format_hex.cpp b/test/src/format_hex.cpp new file mode 100644 index 0000000..6735fd5 --- /dev/null +++ b/test/src/format_hex.cpp @@ -0,0 +1,59 @@ +#include +#include + + +using namespace const_fmt; +using namespace const_fmt::const_fmt_detail; + + +TEST(FormatHex, positive_int) { + constexpr std::array control1 = {'0', '0', '0', '0', + '0', '0', '1', '0'}; + constexpr std::array formatted1 = const_format<"{:08x}">(0x10); + + constexpr std::array control2 = {' ', ' ', ' ', 'F', + 'F', 'A', '7', '6'}; + constexpr std::array formatted2 = const_format<"{:8x}">(0xffa76); + + constexpr std::array control3 = {'0', '0', '0', '0', + 'B', 'C', 'E', 'F'}; + constexpr std::array formatted3 = const_format<"{:08.4x}">(0xbcef); + + constexpr std::array control4 = {'A', 'D', '0', '1'}; + constexpr std::array formatted4 = const_format<"{:4x}">(0xad01); + + constexpr std::array control5 = {'f', 'f', 'f', 'f'}; + constexpr std::array formatted5 = const_format<"{:4x}">(0x12345); + + EXPECT_EQ(control1, formatted1); + EXPECT_EQ(control2, formatted2); + EXPECT_EQ(control3, formatted3); + EXPECT_EQ(control4, formatted4); + EXPECT_EQ(control5, formatted5); +} + +TEST(FormatHex, negative_int) { + constexpr std::array control1 = {'-', '0', '0', '0', + '0', '0', '1', '0'}; + constexpr std::array formatted1 = const_format<"{:08x}">(-0x10); + + constexpr std::array control2 = {' ', ' ', '-', 'F', + 'F', 'A', '7', '6'}; + constexpr std::array formatted2 = const_format<"{:8x}">(-0xffa76); + + constexpr std::array control3 = {'-', '0', '0', '0', + 'B', 'C', 'E', 'F'}; + constexpr std::array formatted3 = const_format<"{:08.4x}">(-0xbcef); + + constexpr std::array control4 = {'-', 'A', 'D', '1'}; + constexpr std::array formatted4 = const_format<"{:4x}">(-0xad1); + + constexpr std::array control5 = {'-', 'f', 'f', 'f'}; + constexpr std::array formatted5 = const_format<"{:04x}">(-0x1234); + + EXPECT_EQ(control1, formatted1); + EXPECT_EQ(control2, formatted2); + EXPECT_EQ(control3, formatted3); + EXPECT_EQ(control4, formatted4); + EXPECT_EQ(control5, formatted5); +}