Compare commits

...

4 Commits

5 changed files with 151 additions and 13 deletions

View File

@ -69,11 +69,21 @@ constexpr inline auto count_digits_base(uint64_t n) -> int {
return result; return result;
} else { } else {
if (!std::is_constant_evaluated()) { if constexpr (t_format_type == FormatType::x) {
return do_count_digits_decimal(n); int result = 0;
}
return count_digits_decimal_fallback(n); while (n) {
n = n >> 4;
result += 1;
}
return (result + count_digits_base<FormatType::b>(n));
} else {
if (!std::is_constant_evaluated()) {
return do_count_digits_decimal(n);
}
return count_digits_decimal_fallback(n);
}
} }
} }
@ -85,11 +95,24 @@ constexpr inline const char* digits2_base(size_t value) {
if constexpr (t_format_type == FormatType::b) { if constexpr (t_format_type == FormatType::b) {
return &"00011011"[value * 2]; return &"00011011"[value * 2];
} else { } else {
return &"0001020304050607080910111213141516171819" if constexpr (t_format_type == FormatType::x) {
"2021222324252627282930313233343536373839" // clang-format off
"4041424344454647484950515253545556575859" return &"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"
"6061626364656667686970717273747576777879" "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"
"8081828384858687888990919293949596979899"[value * 2]; "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"
"606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"
"808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"[value * 2];
// clang-format on
} else {
return &"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899"[value * 2];
}
} }
} }
@ -103,11 +126,22 @@ constexpr inline void copy2(char* dst, const char* src) {
*dst = static_cast<char>(*src); *dst = static_cast<char>(*src);
} }
template <FormatType t_format_type>
consteval inline unsigned get_base_divisor() {
switch (t_format_type) {
case FormatType::b:
return 2;
case FormatType::x:
return 16;
default:
return 10;
}
}
template <FormatType t_format_type, typename uint_t> template <FormatType t_format_type, typename uint_t>
constexpr inline void format_base(char* out, uint_t value, int n_digits, constexpr inline void format_base(char* out, uint_t value, int n_digits,
int size) { int size) {
constexpr unsigned divisor = (t_format_type == FormatType::b) ? 2 : 10; constexpr unsigned divisor = get_base_divisor<t_format_type>();
constexpr unsigned square_divisor = const_pow(divisor, 2); constexpr unsigned square_divisor = const_pow(divisor, 2);
if (n_digits > size) { if (n_digits > size) {
@ -126,7 +160,7 @@ constexpr inline void format_base(char* out, uint_t value, int n_digits,
} }
if (value < divisor) { if (value < divisor) {
*--out = static_cast<char>('0' + value); *--out = digits2_base<t_format_type>(value*divisor)[0];
return; return;
} }
@ -164,7 +198,6 @@ constexpr std::pair<int_t, bool> get_abs_value(int_t value) {
template <fmt_data_t t_fmt_node, std::unsigned_integral uint_t> template <fmt_data_t t_fmt_node, std::unsigned_integral uint_t>
constexpr inline void format_int(char* out, uint_t value) { constexpr inline void format_int(char* out, uint_t value) {
// format_decimal(out, value, count_digits(value), t_fmt_node.length);
format_base<t_fmt_node.type>(out, value, format_base<t_fmt_node.type>(out, value,
count_digits_base<t_fmt_node.type>(value), count_digits_base<t_fmt_node.type>(value),
t_fmt_node.length); t_fmt_node.length);

View File

@ -5,7 +5,7 @@
using namespace const_fmt; using namespace const_fmt;
int main() { 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(122u, -86.2);
// Convert s (with a type of 'std::array<char, N>') into something // Convert s (with a type of 'std::array<char, N>') into something
// writable to std::cout // writable to std::cout

View File

@ -25,6 +25,8 @@ endmacro()
package_add_test(utility_test src/utility.cpp) package_add_test(utility_test src/utility.cpp)
package_add_test(parse_test src/parse.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_decimal_test src/format_decimal.cpp)
package_add_test(format_binary_test src/format_binary.cpp) package_add_test(format_binary_test src/format_binary.cpp)
package_add_test(format_hex_test src/format_hex.cpp)

59
test/src/format_hex.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <const_fmt/format.h>
#include <gtest/gtest.h>
using namespace const_fmt;
using namespace const_fmt::const_fmt_detail;
TEST(FormatHex, positive_int) {
constexpr std::array<char, 8> control1 = {'0', '0', '0', '0',
'0', '0', '1', '0'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08x}">(0x10);
constexpr std::array<char, 8> control2 = {' ', ' ', ' ', 'F',
'F', 'A', '7', '6'};
constexpr std::array<char, 8> formatted2 = const_format<"{:8x}">(0xffa76);
constexpr std::array<char, 8> control3 = {'0', '0', '0', '0',
'B', 'C', 'E', 'F'};
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4x}">(0xbcef);
constexpr std::array<char, 4> control4 = {'A', 'D', '0', '1'};
constexpr std::array<char, 4> formatted4 = const_format<"{:4x}">(0xad01);
constexpr std::array<char, 4> control5 = {'f', 'f', 'f', 'f'};
constexpr std::array<char, 4> 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<char, 8> control1 = {'-', '0', '0', '0',
'0', '0', '1', '0'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08x}">(-0x10);
constexpr std::array<char, 8> control2 = {' ', ' ', '-', 'F',
'F', 'A', '7', '6'};
constexpr std::array<char, 8> formatted2 = const_format<"{:8x}">(-0xffa76);
constexpr std::array<char, 8> control3 = {'-', '0', '0', '0',
'B', 'C', 'E', 'F'};
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4x}">(-0xbcef);
constexpr std::array<char, 4> control4 = {'-', 'A', 'D', '1'};
constexpr std::array<char, 4> formatted4 = const_format<"{:4x}">(-0xad1);
constexpr std::array<char, 4> control5 = {'-', 'f', 'f', 'f'};
constexpr std::array<char, 4> 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);
}

View File

@ -0,0 +1,44 @@
#include <const_fmt/format_impl.h>
#include <limits>
#include <gtest/gtest.h>
using namespace const_fmt;
using namespace const_fmt::const_fmt_detail;
TEST(FormatUtility, count_digits_base_decimal) {
constexpr unsigned length1 = count_digits_base<FormatType::d>(123);
constexpr unsigned length2 = count_digits_base<FormatType::d>(std::numeric_limits<uint64_t>::max());
constexpr unsigned length3 = count_digits_base<FormatType::d>(10000011);
constexpr unsigned length4 = count_digits_base<FormatType::d>(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<FormatType::b>(0b1001);
constexpr unsigned length2 = count_digits_base<FormatType::b>(std::numeric_limits<uint64_t>::max());
constexpr unsigned length3 = count_digits_base<FormatType::b>(0b10000001);
constexpr unsigned length4 = count_digits_base<FormatType::b>(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<FormatType::x>(0x123);
constexpr unsigned length2 = count_digits_base<FormatType::x>(std::numeric_limits<uint64_t>::max());
constexpr unsigned length3 = count_digits_base<FormatType::x>(0x1000000f);
constexpr unsigned length4 = count_digits_base<FormatType::x>(0x01);
EXPECT_EQ(length1, 3);
EXPECT_EQ(length2, 16);
EXPECT_EQ(length3, 8);
EXPECT_EQ(length4, 1);
}