22 Commits

Author SHA1 Message Date
ec70a5bba1 Merge branch 'master' into feature/no_std_lib 2022-02-19 19:21:34 +01:00
1263dfee98 Merge pull request 'Added cmake-build-relwithdebinfo to gitignore' (#8) from fix/gitignore_builddir into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/8
2022-02-19 18:18:51 +00:00
52992e255e Added cmake-build-relwithdebinfo to gitignore 2022-02-19 19:13:54 +01:00
8526ae1d91 First version of std::array 2022-02-18 23:31:15 +01:00
b8f59710d3 Merge pull request 'Updated README.md' (#7) from fix/README_wording into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/7
2022-02-15 13:54:04 +00:00
184815c75b Updated README.md 2022-02-15 13:53:47 +00:00
74c4a4d582 Merge pull request 'feature/int_hex' (#6) from feature/int_hex into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/6
2022-02-15 10:35:17 +00:00
2933676ea2 Fixed bug in hex formatting, wrote tests for hex int formatting 2022-02-15 11:34:49 +01:00
7115e09aca Implemented count_digits for hex and started implementing digits2_base 2022-02-15 11:13:15 +01:00
f9099ce6ee Added tests for count_digits_base, decimal, binary and hex 2022-02-15 11:12:19 +01:00
4c3024e978 Merge pull request 'Reintroduced previously erroneously removed memcpy' (#5) from fix/memcpy into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/5
2022-02-15 09:29:55 +00:00
a921676b77 Reintroduced previously erroneously removed memcpy 2022-02-15 10:29:23 +01:00
3b9d9775bf Merge pull request 'Replaced <cstdint> with <stdint.h>' (#4) from fix/stdint into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/4
2022-02-15 09:17:58 +00:00
39c1636858 Replaced <cstdint> with <stdint.h> 2022-02-15 10:01:55 +01:00
fc080a8ba0 Merge pull request 'Removed memcpy and <cstring>' (#3) from feature/no_cstring into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/3
2022-02-15 08:59:58 +00:00
e4ebd0163b Removed memcpy and <cstring> 2022-02-15 09:58:47 +01:00
1d2dab93bd Merge pull request 'feature/int_binary' (#2) from feature/int_float_binary into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/2
2022-02-15 08:50:35 +00:00
5e4f242796 Renamed functions dedicated to decimal to better reflect their function 2022-02-15 09:47:28 +01:00
fa0fef37db Rewrote format_impl.h functions to work with both decimal and binary 2022-02-15 09:37:41 +01:00
c3eb1e2909 Wrote tests for binary int formatting 2022-02-15 09:35:36 +01:00
313ca5e981 Merge pull request 'Added static_assert to check for string validity' (#1) from feature/compile_time_string_validity into master
Reviewed-on: http://git.mercurial-manifold.eu/an.tsouchlos/const_fmt/pulls/1
2022-02-14 22:25:16 +00:00
8241045158 Added static_assert to check for string validity 2022-02-14 22:36:43 +01:00
11 changed files with 351 additions and 57 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
build build
cmake-build-debug cmake-build-debug
cmake-build-release cmake-build-release
cmake-build-relwithdebinfo
.idea .idea

View File

@@ -11,8 +11,7 @@ During compile-time, the string to be formatted is preprocessed to the point onl
have to be written (If they are not available at compile time). have to be written (If they are not available at compile time).
For example `One number: {:03}; And another one: {:05.3}` is preprocessed into `One number: 000; And another one: 00.000`. For example `One number: {:03}; And another one: {:05.3}` is preprocessed into `One number: 000; And another one: 00.000`.
This is returned as a `std::array<char, N>`, where `N` is automatically evaluated. The only code executed at compile This is returned as a `std::array<char, N>`, where `N` is automatically evaluated. The only code executed at runtime then formats the numbers and writes them into their places in the array.
time then formats the numbers and writes them into their place in the array.
Disclaimer: The actual formatting code is largely shamelessly stolen from `fmtlib`. Disclaimer: The actual formatting code is largely shamelessly stolen from `fmtlib`.
@@ -48,8 +47,11 @@ $ ctest --test-dir build/
## Limitations ## Limitations
For the compile time preprocessing of format strings non non-type template parameters are heavily relied upon,
which means C++20 is required.
Only a relatively limited subset of the `fmtlib` syntax is recognized (for now anyway). In particular, Only a relatively limited subset of the `fmtlib` syntax is recognized (for now anyway). In particular,
there is no support for positional arguments, alignment, chrono format specs and custom const_format specifications. float formatting in decimal and integer formatting in decimal, binary and hexadecimal are supported.
By nature of the library design, which forces compile-time preprocessing of the const_format string, no dynamic width or By nature of the library design, which forces compile-time preprocessing of the const_format string, no dynamic width or
dynamic precision can be implemented. dynamic precision can be implemented.

View File

@@ -2,8 +2,6 @@
#define LOGGER_FORMAT_H #define LOGGER_FORMAT_H
#include <cstring>
#include "format_impl.h" #include "format_impl.h"
#include "parse.h" #include "parse.h"
#include "utility.h" #include "utility.h"
@@ -42,12 +40,12 @@ constexpr inline void check_fmt_params() {
template <fmt_data_t fmt_data, std::integral arg_t> template <fmt_data_t fmt_data, std::integral arg_t>
constexpr inline void format_arg(char* dest, arg_t arg) { constexpr inline void format_arg(char* dest, arg_t arg) {
const_fmt_detail::format_int<arg_t, fmt_data>(dest, arg); const_fmt_detail::format_int<fmt_data>(dest, arg);
}; };
template <fmt_data_t fmt_data, std::floating_point arg_t> template <fmt_data_t fmt_data, std::floating_point arg_t>
constexpr inline void format_arg(char* dest, arg_t arg){ constexpr inline void format_arg(char* dest, arg_t arg){
const_fmt_detail::format_float<arg_t, fmt_data>(dest, arg); const_fmt_detail::format_float<fmt_data>(dest, arg);
}; };
// TODO: Error handling // TODO: Error handling
@@ -115,10 +113,12 @@ namespace const_fmt {
template <const_fmt_detail::ConstString s, typename... args_t> template <const_fmt_detail::ConstString s, typename... args_t>
constexpr inline auto const_format(args_t... args) { constexpr inline auto const_format(args_t... args) {
constexpr auto ast = const_fmt_detail::parse_string<s>().value; constexpr auto ast = const_fmt_detail::parse_string<s>();
constexpr auto fmt_data = const_fmt_detail::get_fmt_data<ast>(); constexpr auto fmt_data = const_fmt_detail::get_fmt_data<ast.value>();
auto result = const_fmt_detail::get_preproc_string<ast>(); static_assert(ast.is_valid, "Invalid format string");
auto result = const_fmt_detail::get_preproc_string<ast.value>();
const_fmt_detail::format_args<fmt_data>(result.begin(), args...); const_fmt_detail::format_args<fmt_data>(result.begin(), args...);

View File

@@ -10,8 +10,7 @@
* *
*/ */
#include <stdint.h>
#include <cstdint>
#include "utility.h" #include "utility.h"
@@ -32,7 +31,7 @@ namespace const_fmt { namespace const_fmt_detail {
(factor)*1000000000 (factor)*1000000000
template <typename T> template <typename T>
constexpr int count_digits_fallback(T n) { constexpr int count_digits_decimal_fallback(T n) {
int count = 1; int count = 1;
for (;;) { for (;;) {
if (n < 10) return count; if (n < 10) return count;
@@ -44,7 +43,7 @@ constexpr int count_digits_fallback(T n) {
} }
} }
inline int do_count_digits(uint64_t n) { inline int do_count_digits_decimal(uint64_t n) {
// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
static constexpr uint8_t bsr2log10[] = { static constexpr uint8_t bsr2log10[] = {
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
@@ -58,22 +57,63 @@ inline int do_count_digits(uint64_t n) {
return t - (n < zero_or_powers_of_10[t]); return t - (n < zero_or_powers_of_10[t]);
} }
constexpr inline auto count_digits(uint64_t n) -> int { template <FormatType t_format_type>
if (!std::is_constant_evaluated()) { constexpr inline auto count_digits_base(uint64_t n) -> int {
return do_count_digits(n); if constexpr (t_format_type == FormatType::b) {
int result = 0;
while (n) {
n = n >> 1;
result += 1;
}
return result;
} else {
if constexpr (t_format_type == FormatType::x) {
int result = 0;
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);
}
} }
return count_digits_fallback(n);
} }
// Converts value in the range [0, 100) to a string. // Converts value in the range [0, base^2) to a string.
constexpr inline const char* digits2(size_t value) { template <FormatType t_format_type>
constexpr inline const char* digits2_base(size_t value) {
// GCC generates slightly better code when value is pointer-size. // GCC generates slightly better code when value is pointer-size.
return &"0001020304050607080910111213141516171819" if constexpr (t_format_type == FormatType::b) {
"2021222324252627282930313233343536373839" return &"00011011"[value * 2];
"4041424344454647484950515253545556575859" } else {
"6061626364656667686970717273747576777879" if constexpr (t_format_type == FormatType::x) {
"8081828384858687888990919293949596979899"[value * 2]; // clang-format off
return &"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"
"202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"
"404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"
"606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"
"808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"[value * 2];
// clang-format on
} else {
return &"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899"[value * 2];
}
}
} }
@@ -86,9 +126,24 @@ constexpr inline void copy2(char* dst, const char* src) {
*dst = static_cast<char>(*src); *dst = static_cast<char>(*src);
} }
template <typename uint_t> template <FormatType t_format_type>
constexpr inline void format_decimal(char* out, uint_t value, int n_digits, consteval inline unsigned get_base_divisor() {
int size) { 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>
constexpr inline void format_base(char* out, uint_t value, int n_digits,
int size) {
constexpr unsigned divisor = get_base_divisor<t_format_type>();
constexpr unsigned square_divisor = const_pow(divisor, 2);
if (n_digits > size) { if (n_digits > size) {
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
*(out++) = 'f'; *(out++) = 'f';
@@ -97,21 +152,23 @@ constexpr inline void format_decimal(char* out, uint_t value, int n_digits,
} }
out += size; out += size;
while (value >= 100) { while (value >= square_divisor) {
out -= 2; out -= 2;
copy2(out, digits2(static_cast<size_t>(value % 100))); copy2(out, digits2_base<t_format_type>(
value /= 100; static_cast<size_t>(value % square_divisor)));
value /= square_divisor;
} }
if (value < 10) { if (value < divisor) {
*--out = static_cast<char>('0' + value); *--out = digits2_base<t_format_type>(value*divisor)[0];
return; return;
} }
out -= 2; out -= 2;
copy2(out, digits2(static_cast<size_t>(value))); copy2(out, digits2_base<t_format_type>(static_cast<size_t>(value)));
} }
// returns {abs_value, was_negative} // returns {abs_value, was_negative}
template <std::signed_integral int_t> template <std::signed_integral int_t>
constexpr std::pair<typename std::make_unsigned<int_t>::type, bool> constexpr std::pair<typename std::make_unsigned<int_t>::type, bool>
@@ -139,19 +196,22 @@ constexpr std::pair<int_t, bool> get_abs_value(int_t value) {
*/ */
template <std::unsigned_integral uint_t, fmt_data_t t_fmt_node> 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,
count_digits_base<t_fmt_node.type>(value),
t_fmt_node.length);
} }
template <std::signed_integral int_t, fmt_data_t t_fmt_node>
template <fmt_data_t t_fmt_node, std::signed_integral int_t>
constexpr inline void format_int(char* out, int_t value) { constexpr inline void format_int(char* out, int_t value) {
const auto [abs_value, negative] = get_abs_value(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<t_fmt_node.type>(abs_value);
format_decimal(out + 1 * (negative), abs_value, n_digits, format_base<t_fmt_node.type>(out + 1 * (negative), abs_value, n_digits,
t_fmt_node.length - 1 * (negative)); t_fmt_node.length - 1 * (negative));
if constexpr (t_fmt_node.has_zero_padding) { if constexpr (t_fmt_node.has_zero_padding) {
if (negative) *(out) = '-'; if (negative) *(out) = '-';
@@ -169,21 +229,21 @@ constexpr inline void format_int(char* out, int_t value) {
*/ */
template <std::floating_point float_t, fmt_data_t t_fmt_node> template <fmt_data_t t_fmt_node, std::floating_point float_t>
constexpr inline void format_float(char* out, float_t value) { constexpr inline void format_float(char* out, float_t value) {
// clang-format off // clang-format off
constexpr fmt_data_t fmt_node_integral = { constexpr fmt_data_t fmt_node_integral = {
t_fmt_node.has_zero_padding, // has_zero_padding t_fmt_node.has_zero_padding, // has_zero_padding
t_fmt_node.length - t_fmt_node.precision - 1, // length t_fmt_node.length - t_fmt_node.precision - 1, // length
t_fmt_node.precision, // ignored t_fmt_node.precision, // ignored
t_fmt_node.type, // ignored FormatType::d, // type
t_fmt_node.position // ignored t_fmt_node.position // ignored
}; };
constexpr fmt_data_t fmt_node_fractional = { constexpr fmt_data_t fmt_node_fractional = {
true, // has_zero_padding true, // has_zero_padding
t_fmt_node.precision, // length t_fmt_node.precision, // length
t_fmt_node.precision, // ignored t_fmt_node.precision, // ignored
t_fmt_node.type, // ignored FormatType::d, // type
t_fmt_node.position // ignored t_fmt_node.position // ignored
}; };
// clang-format on // clang-format on
@@ -198,8 +258,8 @@ constexpr inline void format_float(char* out, float_t value) {
const auto [fractional_abs, fractional_negative] = const auto [fractional_abs, fractional_negative] =
get_abs_value(fractional); get_abs_value(fractional);
format_int<int, fmt_node_integral>(out, integral); format_int<fmt_node_integral, int>(out, integral);
format_int<uint16_t, fmt_node_fractional>( format_int<fmt_node_fractional, uint16_t>(
out + t_fmt_node.length - t_fmt_node.precision, fractional_abs); out + t_fmt_node.length - t_fmt_node.precision, fractional_abs);
} }

71
const_fmt/std_lib.h Normal file
View File

@@ -0,0 +1,71 @@
#ifndef CONST_FMT_STD_LIB_H
#define CONST_FMT_STD_LIB_H
#ifdef CONST_FMT_NO_STD_LIB
#include <stdint.h>
namespace std {
using size_t = uint16_t;
// TODO: Is std::size_t really the best bet here?
template <typename data_t, std::size_t t_size>
class array {
public:
// Constructors
array() = default;
array(const array& other) = default;
array(array&& other) = default;
// Operators
array operator=(const array& other) = default;
array operator=(array&& other) = default;
// Element access
data_t& operator[](std::size_t index) {
return m_data[index];
}
const data_t& operator[](std::size_t index) const {
return m_data[index];
}
// Iterators
using iterator = data_t*;
using const_iterator = const data_t*;
iterator begin() {
return &(m_data[0]);
}
iterator end() {
return (&(m_data[t_size-1]) + 1);
}
const iterator cbegin() const {
return &(m_data[0]);
}
const iterator cend() const {
return (&(m_data[t_size-1]) + 1);
}
private:
data_t m_data[t_size];
};
} // namespace std
#endif
#endif // CONST_FMT_STD_LIB_H

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: {:08}, and this is a float: {:09.4}"_const_fmt(12345, -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,5 +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_test src/format.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)

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(FormatBinary, positive_int) {
constexpr std::array<char, 8> control1 = {'0', '0', '0', '0',
'0', '0', '1', '0'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08b}">(0b10);
constexpr std::array<char, 8> control2 = {' ', ' ', '1', '0',
'1', '0', '1', '0'};
constexpr std::array<char, 8> formatted2 = const_format<"{:8b}">(0b101010);
constexpr std::array<char, 8> control3 = {'0', '0', '0', '1',
'1', '0', '0', '1'};
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4b}">(0b11001);
constexpr std::array<char, 4> control4 = {'1', '0', '1', '1'};
constexpr std::array<char, 4> formatted4 = const_format<"{:4b}">(0b1011);
constexpr std::array<char, 4> control5 = {'f', 'f', 'f', 'f'};
constexpr std::array<char, 4> formatted5 = const_format<"{:4b}">(0b10011);
EXPECT_EQ(control1, formatted1);
EXPECT_EQ(control2, formatted2);
EXPECT_EQ(control3, formatted3);
EXPECT_EQ(control4, formatted4);
EXPECT_EQ(control5, formatted5);
}
TEST(FormatBinary, negative_int) {
constexpr std::array<char, 8> control1 = {'-', '0', '0', '0',
'0', '0', '1', '0'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08b}">(-0b10);
constexpr std::array<char, 8> control2 = {' ', '-', '1', '0',
'1', '0', '1', '0'};
constexpr std::array<char, 8> formatted2 = const_format<"{:8b}">(-0b101010);
constexpr std::array<char, 8> control3 = {'-', '0', '0', '1',
'0', '0', '1', '1'};
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4b}">(-0b10011);
constexpr std::array<char, 5> control4 = {'-', '1', '1', '0', '1'};
constexpr std::array<char, 5> formatted4 = const_format<"{:5b}">(-0b1101);
constexpr std::array<char, 5> control5 = {'-', 'f', 'f', 'f', 'f'};
constexpr std::array<char, 5> formatted5 = const_format<"{:05b}">(-0b10101);
EXPECT_EQ(control1, formatted1);
EXPECT_EQ(control2, formatted2);
EXPECT_EQ(control3, formatted3);
EXPECT_EQ(control4, formatted4);
EXPECT_EQ(control5, formatted5);
}

View File

@@ -6,7 +6,7 @@ using namespace const_fmt;
using namespace const_fmt::const_fmt_detail; using namespace const_fmt::const_fmt_detail;
TEST(Format, positive_int) { TEST(FormatDecimal, positive_int) {
constexpr std::array<char, 8> control1 = {'0', '0', '0', '0', constexpr std::array<char, 8> control1 = {'0', '0', '0', '0',
'0', '0', '0', '2'}; '0', '0', '0', '2'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08}">(2); constexpr std::array<char, 8> formatted1 = const_format<"{:08}">(2);
@@ -32,7 +32,7 @@ TEST(Format, positive_int) {
EXPECT_EQ(control5, formatted5); EXPECT_EQ(control5, formatted5);
} }
TEST(Format, negative_int) { TEST(FormatDecimal, negative_int) {
constexpr std::array<char, 8> control1 = {'-', '0', '0', '0', constexpr std::array<char, 8> control1 = {'-', '0', '0', '0',
'0', '0', '0', '2'}; '0', '0', '0', '2'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08}">(-2); constexpr std::array<char, 8> formatted1 = const_format<"{:08}">(-2);
@@ -58,7 +58,7 @@ TEST(Format, negative_int) {
EXPECT_EQ(control5, formatted5); EXPECT_EQ(control5, formatted5);
} }
TEST(Format, positive_float) { TEST(FormatDecimal, positive_float) {
constexpr std::array<char, 8> control1 = {'0', '0', '2', '.', constexpr std::array<char, 8> control1 = {'0', '0', '2', '.',
'3', '4', '5', '6'}; '3', '4', '5', '6'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(2.3456); constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(2.3456);
@@ -82,7 +82,7 @@ TEST(Format, positive_float) {
EXPECT_EQ(control4, formatted4); EXPECT_EQ(control4, formatted4);
} }
TEST(Format, negative_float) { TEST(FormatDecimal, negative_float) {
constexpr std::array<char, 8> control1 = {'-', '0', '2', '.', constexpr std::array<char, 8> control1 = {'-', '0', '2', '.',
'3', '4', '5', '6'}; '3', '4', '5', '6'};
constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(-2.3456); constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(-2.3456);
@@ -101,8 +101,3 @@ TEST(Format, negative_float) {
EXPECT_EQ(control2, formatted2); EXPECT_EQ(control2, formatted2);
EXPECT_EQ(control3, formatted3); EXPECT_EQ(control3, formatted3);
} }
//
// TEST(Format, string) {
// // TODO
// EXPECT_EQ(true, false);
//}

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);
}