alternative form

main
Brett 2025-03-04 01:26:33 -05:00
parent b2c3820ed0
commit 25187319ab
6 changed files with 133 additions and 72 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 5.1.3) set(BLT_VERSION 5.1.4)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

View File

@ -34,7 +34,8 @@ namespace blt::logging
COLON, COLON,
DOT, DOT,
MINUS, MINUS,
PLUS PLUS,
POUND
}; };
enum class fmt_sign_t : u8 enum class fmt_sign_t : u8
@ -66,6 +67,7 @@ namespace blt::logging
fmt_sign_t sign = fmt_sign_t::MINUS; fmt_sign_t sign = fmt_sign_t::MINUS;
bool leading_zeros = false; bool leading_zeros = false;
bool uppercase = false; bool uppercase = false;
bool alternate_form = false;
}; };
struct fmt_token_t struct fmt_token_t
@ -121,10 +123,15 @@ namespace blt::logging
private: private:
void parse_fmt_field(); void parse_fmt_field();
void parse_arg_id(); void parse_arg_id();
void parse_fmt_spec_stage_1();
void parse_fmt_spec_stage_2(); void parse_fmt_spec();
void parse_fmt_spec_stage_3(); void parse_fmt_spec_sign();
void parse_fmt_spec_form();
void parse_fmt_spec_width();
void parse_fmt_spec_precision();
void parse_sign(); void parse_sign();
void parse_form();
void parse_width(); void parse_width();
void parse_precision(); void parse_precision();
void parse_type(); void parse_type();

View File

@ -68,7 +68,7 @@ namespace blt::logging
case fmt_sign_t::SPACE: case fmt_sign_t::SPACE:
if constexpr (std::is_arithmetic_v<T>) if constexpr (std::is_arithmetic_v<T>)
{ {
if (t >= 0) if (type.type != fmt_type_t::BINARY && t >= 0)
stream << ' '; stream << ' ';
} }
break; break;
@ -90,7 +90,8 @@ namespace blt::logging
{ {
char buffer[sizeof(T)]; char buffer[sizeof(T)];
std::memcpy(buffer, &t, sizeof(T)); std::memcpy(buffer, &t, sizeof(T));
stream << '0' << (type.uppercase ? 'B' : 'b'); if (type.alternate_form)
stream << '0' << (type.uppercase ? 'B' : 'b');
for (size_t i = 0; i < sizeof(T); ++i) for (size_t i = 0; i < sizeof(T); ++i)
{ {
for (size_t j = 0; j < 8; ++j) for (size_t j = 0; j < 8; ++j)
@ -127,7 +128,7 @@ namespace blt::logging
} }
break; break;
default: default:
handle_type(stream, type.type); handle_type(stream, type);
stream << t; stream << t;
} }
}; };
@ -135,7 +136,7 @@ namespace blt::logging
void setup_stream(const fmt_spec_t& spec); void setup_stream(const fmt_spec_t& spec);
void process_strings(); void process_strings();
static void handle_type(std::ostream& stream, fmt_type_t type); static void handle_type(std::ostream& stream, const fmt_spec_t& spec);
static void exponential(std::ostream& stream); static void exponential(std::ostream& stream);
static void fixed(std::ostream& stream); static void fixed(std::ostream& stream);

View File

@ -46,6 +46,8 @@ namespace blt::logging
return fmt_token_type::COLON; return fmt_token_type::COLON;
case ' ': case ' ':
return fmt_token_type::SPACE; return fmt_token_type::SPACE;
case '#':
return fmt_token_type::POUND;
default: default:
return fmt_token_type::STRING; return fmt_token_type::STRING;
} }
@ -62,6 +64,7 @@ namespace blt::logging
case fmt_token_type::MINUS: case fmt_token_type::MINUS:
case fmt_token_type::DOT: case fmt_token_type::DOT:
case fmt_token_type::COLON: case fmt_token_type::COLON:
case fmt_token_type::POUND:
return fmt_token_t{base_type, std::string_view{m_fmt.data() + m_pos++, 1}}; return fmt_token_t{base_type, std::string_view{m_fmt.data() + m_pos++, 1}};
default: default:
{ {
@ -100,30 +103,32 @@ namespace blt::logging
if (!has_next()) if (!has_next())
throw std::runtime_error("Expected token when parsing format field"); throw std::runtime_error("Expected token when parsing format field");
const auto [type, value] = peek(); const auto [type, value] = peek();
if (type == fmt_token_type::COLON) switch (type)
{
consume();
parse_fmt_spec_stage_1();
}
else if (type == fmt_token_type::NUMBER)
{ {
case fmt_token_type::NUMBER:
parse_arg_id(); parse_arg_id();
if (has_next()) if (has_next())
{ {
if (peek().type == fmt_token_type::COLON) if (peek().type == fmt_token_type::COLON)
{ parse_fmt_spec();
consume();
parse_fmt_spec_stage_1();
}
else else
throw std::runtime_error("Expected ':' when parsing format field after arg id!"); throw std::runtime_error("Expected ':' when parsing format field after arg id!");
} }
} break;
else case fmt_token_type::COLON:
{ parse_fmt_spec();
std::stringstream ss; break;
ss << "Expected unknown token '" << static_cast<u8>(type) << "' value '" << value << "' when parsing format field"; case fmt_token_type::STRING:
throw std::runtime_error(ss.str()); case fmt_token_type::SPACE:
case fmt_token_type::DOT:
case fmt_token_type::MINUS:
case fmt_token_type::PLUS:
case fmt_token_type::POUND:
{
std::stringstream ss;
ss << "Expected unknown token '" << static_cast<u8>(type) << "' value '" << value << "' when parsing format field";
throw std::runtime_error(ss.str());
}
} }
if (has_next()) if (has_next())
parse_type(); parse_type();
@ -131,8 +136,6 @@ namespace blt::logging
void fmt_parser_t::parse_arg_id() void fmt_parser_t::parse_arg_id()
{ {
if (!has_next())
throw std::runtime_error("Missing token when parsing arg id");
const auto [type, value] = next(); const auto [type, value] = next();
if (type != fmt_token_type::NUMBER) if (type != fmt_token_type::NUMBER)
{ {
@ -143,11 +146,10 @@ namespace blt::logging
m_spec.arg_id = std::stoll(std::string(value)); m_spec.arg_id = std::stoll(std::string(value));
} }
// handle start of fmt, with sign void fmt_parser_t::parse_fmt_spec()
void fmt_parser_t::parse_fmt_spec_stage_1()
{ {
if (!has_next()) // consume :
return; consume();
auto [type, value] = peek(); auto [type, value] = peek();
switch (type) switch (type)
{ {
@ -155,29 +157,89 @@ namespace blt::logging
case fmt_token_type::COLON: case fmt_token_type::COLON:
{ {
std::stringstream ss; std::stringstream ss;
ss << "(Stage 1) Invalid token type " << static_cast<u8>(type) << " value " << value; ss << "(Stage (Begin)) Invalid token type " << static_cast<u8>(type) << " value " << value;
throw std::runtime_error(ss.str()); throw std::runtime_error(ss.str());
} }
case fmt_token_type::NUMBER: case fmt_token_type::NUMBER:
parse_width(); parse_fmt_spec_width();
parse_fmt_spec_stage_3();
break; break;
case fmt_token_type::DOT: case fmt_token_type::DOT:
consume(); parse_fmt_spec_precision();
parse_precision();
break; break;
case fmt_token_type::SPACE: case fmt_token_type::SPACE:
case fmt_token_type::MINUS: case fmt_token_type::MINUS:
case fmt_token_type::PLUS: case fmt_token_type::PLUS:
parse_sign(); parse_fmt_spec_sign();
parse_fmt_spec_stage_2(); break;
case fmt_token_type::POUND:
parse_fmt_spec_form();
break;
}
}
// handle start of fmt, with sign
void fmt_parser_t::parse_fmt_spec_sign()
{
parse_sign();
if (!has_next())
return;
auto [type, value] = peek();
switch (type)
{
case fmt_token_type::SPACE:
case fmt_token_type::MINUS:
case fmt_token_type::PLUS:
case fmt_token_type::STRING:
case fmt_token_type::COLON:
{
std::stringstream ss;
ss << "(Stage (Sign)) Invalid token type " << static_cast<u8>(type) << " value " << value;
throw std::runtime_error(ss.str());
}
case fmt_token_type::NUMBER:
parse_fmt_spec_width();
break;
case fmt_token_type::DOT:
parse_fmt_spec_precision();
break;
case fmt_token_type::POUND:
parse_fmt_spec_form();
break;
}
}
void fmt_parser_t::parse_fmt_spec_form()
{
parse_form();
if (!has_next())
return;
auto [type, value] = peek();
switch (type)
{
case fmt_token_type::STRING:
case fmt_token_type::SPACE:
case fmt_token_type::COLON:
case fmt_token_type::MINUS:
case fmt_token_type::PLUS:
case fmt_token_type::POUND:
{
std::stringstream ss;
ss << "(Stage (Form)) Invalid token type " << static_cast<u8>(type) << " value " << value;
throw std::runtime_error(ss.str());
}
case fmt_token_type::NUMBER:
parse_fmt_spec_width();
break;
case fmt_token_type::DOT:
parse_fmt_spec_precision();
break; break;
} }
} }
// handle width parsing // handle width parsing
void fmt_parser_t::parse_fmt_spec_stage_2() void fmt_parser_t::parse_fmt_spec_width()
{ {
parse_width();
if (!has_next()) if (!has_next())
return; return;
auto [type, value] = peek(); auto [type, value] = peek();
@ -188,45 +250,24 @@ namespace blt::logging
case fmt_token_type::MINUS: case fmt_token_type::MINUS:
case fmt_token_type::PLUS: case fmt_token_type::PLUS:
case fmt_token_type::SPACE: case fmt_token_type::SPACE:
case fmt_token_type::POUND:
case fmt_token_type::NUMBER:
{ {
std::stringstream ss; std::stringstream ss;
ss << "(Stage 2) Invalid token type " << static_cast<u8>(type) << " value " << value; ss << "(Stage (Width)) Invalid token type " << static_cast<u8>(type) << " value " << value;
throw std::runtime_error(ss.str()); throw std::runtime_error(ss.str());
} }
case fmt_token_type::NUMBER:
parse_width();
parse_fmt_spec_stage_3();
break;
case fmt_token_type::DOT: case fmt_token_type::DOT:
consume(); parse_fmt_spec_precision();
parse_precision();
break; break;
} }
} }
void fmt_parser_t::parse_fmt_spec_stage_3() void fmt_parser_t::parse_fmt_spec_precision()
{ {
if (!has_next()) // consume .
return; consume();
auto [type, value] = peek(); parse_precision();
switch (type)
{
case fmt_token_type::STRING:
case fmt_token_type::COLON:
case fmt_token_type::MINUS:
case fmt_token_type::PLUS:
case fmt_token_type::SPACE:
case fmt_token_type::NUMBER:
{
std::stringstream ss;
ss << "(Stage 3) Invalid token type " << static_cast<u8>(type) << " value " << value;
throw std::runtime_error(ss.str());
}
case fmt_token_type::DOT:
consume();
parse_precision();
break;
}
} }
void fmt_parser_t::parse_sign() void fmt_parser_t::parse_sign()
@ -258,6 +299,12 @@ namespace blt::logging
} }
} }
void fmt_parser_t::parse_form()
{
consume();
m_spec.alternate_form = true;
}
void fmt_parser_t::parse_width() void fmt_parser_t::parse_width()
{ {
auto [_, value] = next(); auto [_, value] = next();
@ -276,8 +323,6 @@ namespace blt::logging
void fmt_parser_t::parse_type() void fmt_parser_t::parse_type()
{ {
if (!has_next())
throw std::runtime_error("Missing token when parsing type");
auto [_, value] = next(); auto [_, value] = next();
if (value.size() != 1) if (value.size() != 1)
{ {

View File

@ -73,20 +73,26 @@ namespace blt::logging
m_stream << *str_it; m_stream << *str_it;
} }
void logger_t::handle_type(std::ostream& stream, const fmt_type_t type) void logger_t::handle_type(std::ostream& stream, const fmt_spec_t& spec)
{ {
switch (type) switch (spec.type)
{ {
case fmt_type_t::DECIMAL: case fmt_type_t::DECIMAL:
stream << std::dec; stream << std::dec;
break; break;
case fmt_type_t::OCTAL: case fmt_type_t::OCTAL:
if (spec.alternate_form)
stream << "0";
stream << std::oct; stream << std::oct;
break; break;
case fmt_type_t::HEX: case fmt_type_t::HEX:
if (spec.alternate_form)
stream << (spec.uppercase ? "0X" : "0x");
stream << std::hex; stream << std::hex;
break; break;
case fmt_type_t::HEX_FLOAT: case fmt_type_t::HEX_FLOAT:
if (spec.alternate_form)
stream << (spec.uppercase ? "0X" : "0x");
stream << std::hexfloat; stream << std::hexfloat;
break; break;
case fmt_type_t::EXPONENT: case fmt_type_t::EXPONENT:

View File

@ -36,5 +36,7 @@ int main()
blt::logging::println("This is a println with a with {:10}", 4120); blt::logging::println("This is a println with a with {:10}", 4120);
blt::logging::println("This is a println with a with leading zeros {:010}", 4120); blt::logging::println("This is a println with a with leading zeros {:010}", 4120);
blt::logging::println("This is a println with a precision {:.10f}", 42.232342349); blt::logging::println("This is a println with a precision {:.10f}", 42.232342349);
blt::logging::println("This is a println with hex {:.10x}", 4250);
blt::logging::println("This is a println with hex with leading {:#.10x}", 4250);
// blt::logging::println("This is println {}\twith a std::endl in the middle of it"); // blt::logging::println("This is println {}\twith a std::endl in the middle of it");
} }