Compare commits
6 Commits
f47a23ffef
...
v1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 6666a25562 | |||
| 008c71381c | |||
| 9c22b2a084 | |||
| 9bf3e63058 | |||
| 4666b4e737 | |||
| 1338888e0b |
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright 2022 Andreas Tsouchlos
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -42,12 +42,12 @@ constexpr inline void check_fmt_params() {
|
||||
|
||||
template <fmt_data_t fmt_data, std::integral arg_t>
|
||||
constexpr inline void format_arg(char* dest, arg_t arg) {
|
||||
const_fmt_detail::format_int(dest, arg, fmt_data);
|
||||
const_fmt_detail::format_int<arg_t, fmt_data>(dest, arg);
|
||||
};
|
||||
|
||||
template <fmt_data_t fmt_data, std::floating_point arg_t>
|
||||
constexpr inline void format_arg(char* dest, arg_t arg){
|
||||
// const_fmt_detail::format_float(dest, arg, fmt_data);
|
||||
const_fmt_detail::format_float<arg_t, fmt_data>(dest, arg);
|
||||
};
|
||||
|
||||
// TODO: Error handling
|
||||
@@ -93,7 +93,6 @@ consteval inline auto get_preproc_string() {
|
||||
} else {
|
||||
for (int j = 0; j < ast_node.get_node().length; ++j)
|
||||
result[i++] = ast_node.get_node().has_zero_padding ? '0' : ' ';
|
||||
//i += ast_node.get_node().length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,8 +87,14 @@ constexpr inline void copy2(char* dst, const char* src) {
|
||||
}
|
||||
|
||||
template <typename uint_t>
|
||||
constexpr inline void format_decimal(char* out, uint_t value, int size) {
|
||||
if (count_digits(value) > size) return;
|
||||
constexpr inline void format_decimal(char* out, uint_t value, int n_digits,
|
||||
int size) {
|
||||
if (n_digits > size) {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
*(out++) = 'f';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
out += size;
|
||||
while (value >= 100) {
|
||||
@@ -106,6 +112,25 @@ constexpr inline void format_decimal(char* out, uint_t value, int size) {
|
||||
copy2(out, digits2(static_cast<size_t>(value)));
|
||||
}
|
||||
|
||||
// returns {abs_value, was_negative}
|
||||
template <std::signed_integral int_t>
|
||||
constexpr std::pair<typename std::make_unsigned<int_t>::type, bool>
|
||||
get_abs_value(int_t value) {
|
||||
using uint_t = typename std::make_unsigned<int_t>::type;
|
||||
|
||||
uint_t abs_value = static_cast<uint_t>(value);
|
||||
|
||||
const bool negative = value < 0;
|
||||
if (negative) abs_value = 0 - abs_value;
|
||||
|
||||
return {abs_value, negative};
|
||||
}
|
||||
|
||||
template <std::unsigned_integral int_t>
|
||||
constexpr std::pair<int_t, bool> get_abs_value(int_t value) {
|
||||
return {value, false};
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -114,21 +139,26 @@ constexpr inline void format_decimal(char* out, uint_t value, int size) {
|
||||
*/
|
||||
|
||||
|
||||
template <std::unsigned_integral uint_t>
|
||||
constexpr inline void format_int(char* out, uint_t value, fmt_data_t fmt_node) {
|
||||
format_decimal(out, value, fmt_node.length);
|
||||
template <std::unsigned_integral uint_t, fmt_data_t t_fmt_node>
|
||||
constexpr inline void format_int(char* out, uint_t value) {
|
||||
format_decimal(out, value, count_digits(value), t_fmt_node.length);
|
||||
}
|
||||
|
||||
template <std::signed_integral uint_t>
|
||||
constexpr inline void format_int(char* out, uint_t value, fmt_data_t fmt_node) {
|
||||
auto abs_value = static_cast<uint64_t>(value);
|
||||
const bool negative = value < 0;
|
||||
template <std::signed_integral int_t, fmt_data_t t_fmt_node>
|
||||
constexpr inline void format_int(char* out, int_t value) {
|
||||
const auto [abs_value, negative] = get_abs_value(value);
|
||||
|
||||
if (negative) abs_value = 0 - abs_value;
|
||||
format_decimal(out + 1 * (negative), abs_value,
|
||||
fmt_node.length - 1 * (negative));
|
||||
const std::size_t n_digits = count_digits(abs_value);
|
||||
|
||||
if (negative) *out = '-';
|
||||
format_decimal(out + 1 * (negative), abs_value, n_digits,
|
||||
t_fmt_node.length - 1 * (negative));
|
||||
|
||||
if constexpr (t_fmt_node.has_zero_padding) {
|
||||
if (negative) *(out) = '-';
|
||||
} else {
|
||||
if (n_digits < t_fmt_node.length)
|
||||
if (negative) *(out + t_fmt_node.length - n_digits - 1) = '-';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +169,38 @@ constexpr inline void format_int(char* out, uint_t value, fmt_data_t fmt_node) {
|
||||
*/
|
||||
|
||||
|
||||
template <std::floating_point float_t>
|
||||
constexpr inline void format_float(char* out, float_t value,
|
||||
fmt_data_t fmt_data) {
|
||||
template <std::floating_point float_t, fmt_data_t t_fmt_node>
|
||||
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
|
||||
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
|
||||
t_fmt_node.position // ignored
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
*(out) = 'f';
|
||||
*(out + fmt_data.length - fmt_data.precision - 1) = '.';
|
||||
*(out + t_fmt_node.length - t_fmt_node.precision - 1) = '.';
|
||||
|
||||
const int integral = static_cast<int>(value);
|
||||
|
||||
constexpr std::size_t factor = const_pow(10, t_fmt_node.precision);
|
||||
const int fractional = static_cast<int>((value - integral) * factor);
|
||||
|
||||
const auto [fractional_abs, fractional_negative] =
|
||||
get_abs_value(fractional);
|
||||
|
||||
format_int<int, fmt_node_integral>(out, integral);
|
||||
format_int<uint16_t, fmt_node_fractional>(
|
||||
out + t_fmt_node.length - t_fmt_node.precision, fractional_abs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using namespace const_fmt;
|
||||
|
||||
int main() {
|
||||
constexpr auto s = "abcdef {:04}"_const_fmt(123);
|
||||
constexpr auto s = "This is an integer: {:08}, and this is a float: {:09.4}"_const_fmt(12345, -86.2);
|
||||
|
||||
// Convert s (with a type of 'std::array<char, N>') into something
|
||||
// writable to std::cout
|
||||
|
||||
@@ -8,59 +8,101 @@ using namespace const_fmt::const_fmt_detail;
|
||||
|
||||
TEST(Format, positive_int) {
|
||||
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> control2 = {' ', ' ', ' ', '2',
|
||||
'2', '2', '2', '2'};
|
||||
'2', '2', '2', '2'};
|
||||
constexpr std::array<char, 8> formatted2 = const_format<"{:8}">(22222);
|
||||
|
||||
constexpr std::array<char, 8> control3 = {'0', '0', '0', '1',
|
||||
'2', '3', '4', '5'};
|
||||
'2', '3', '4', '5'};
|
||||
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4}">(12345);
|
||||
|
||||
constexpr std::array<char, 4> control4 = {'6', '7', '8', '9'};
|
||||
constexpr std::array<char, 4> formatted4 = const_format<"{:4}">(6789);
|
||||
|
||||
constexpr std::array<char, 4> control5 = {'f', 'f', 'f', 'f'};
|
||||
constexpr std::array<char, 4> 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(Format, negative_int) {
|
||||
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> control2 = {' ', ' ', '-', '2',
|
||||
'2', '2', '2', '2'};
|
||||
'2', '2', '2', '2'};
|
||||
constexpr std::array<char, 8> formatted2 = const_format<"{:8}">(-22222);
|
||||
|
||||
constexpr std::array<char, 8> control3 = {'-', '0', '0', '1',
|
||||
'2', '3', '4', '5'};
|
||||
'2', '3', '4', '5'};
|
||||
constexpr std::array<char, 8> formatted3 = const_format<"{:08.4}">(-12345);
|
||||
|
||||
constexpr std::array<char, 5> control4 = {'-', '6', '7', '8', '9'};
|
||||
constexpr std::array<char, 5> formatted4 = const_format<"{:5}">(-6789);
|
||||
|
||||
constexpr std::array<char, 5> control5 = {'-', 'f', 'f', 'f', 'f'};
|
||||
constexpr std::array<char, 5> 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(Format, positive_float) {
|
||||
constexpr std::array<char, 8> control1 = {'0', '0', '2', '.',
|
||||
'3', '4', '5', '6'};
|
||||
constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(2.3456);
|
||||
|
||||
// Float error: 2323.2 -> 2323.1
|
||||
constexpr std::array<char, 8> control2 = {' ', ' ', '2', '3',
|
||||
'2', '3', '.', '1'};
|
||||
constexpr std::array<char, 8> formatted2 = const_format<"{:8.1}">(2323.2);
|
||||
|
||||
constexpr std::array<char, 8> control3 = {'1', '2', '3', '4',
|
||||
'.', '5', '0', '0'};
|
||||
constexpr std::array<char, 8> formatted3 = const_format<"{:08.3}">(1234.5);
|
||||
|
||||
// Float error: .9 -> .8
|
||||
constexpr std::array<char, 4> control4 = {'f', 'f', '.', '8'};
|
||||
constexpr std::array<char, 4> formatted4 = const_format<"{:4.1}">(678.9);
|
||||
|
||||
EXPECT_EQ(control1, formatted1);
|
||||
EXPECT_EQ(control2, formatted2);
|
||||
EXPECT_EQ(control3, formatted3);
|
||||
EXPECT_EQ(control4, formatted4);
|
||||
}
|
||||
|
||||
TEST(Format, negative_float) {
|
||||
constexpr std::array<char, 8> control1 = {'-', '0', '2', '.',
|
||||
'3', '4', '5', '6'};
|
||||
constexpr std::array<char, 8> formatted1 = const_format<"{:08.4}">(-2.3456);
|
||||
|
||||
// Float error: 2323.2 -> 2323.1
|
||||
constexpr std::array<char, 8> control2 = {' ', '-', '2', '3',
|
||||
'2', '3', '.', '1'};
|
||||
constexpr std::array<char, 8> formatted2 = const_format<"{:8.1}">(-2323.2);
|
||||
|
||||
constexpr std::array<char, 8> control3 = {'-', 'f', 'f', 'f',
|
||||
'.', '5', '0', '0'};
|
||||
constexpr std::array<char, 8> formatted3 = const_format<"{:08.3}">(-1234.5);
|
||||
|
||||
|
||||
EXPECT_EQ(control1, formatted1);
|
||||
EXPECT_EQ(control2, formatted2);
|
||||
EXPECT_EQ(control3, formatted3);
|
||||
}
|
||||
//
|
||||
//TEST(Format, positive_float) {
|
||||
// // TODO
|
||||
// EXPECT_EQ(true, false);
|
||||
//}
|
||||
//
|
||||
//TEST(Format, negative_float) {
|
||||
// // TODO
|
||||
// EXPECT_EQ(true, false);
|
||||
//}
|
||||
//
|
||||
//TEST(Format, string) {
|
||||
// TEST(Format, string) {
|
||||
// // TODO
|
||||
// EXPECT_EQ(true, false);
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user