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)
include(cmake/color.cmake)
set(BLT_VERSION 5.1.3)
set(BLT_VERSION 5.1.4)
set(BLT_TARGET BLT)

View File

@ -34,7 +34,8 @@ namespace blt::logging
COLON,
DOT,
MINUS,
PLUS
PLUS,
POUND
};
enum class fmt_sign_t : u8
@ -66,6 +67,7 @@ namespace blt::logging
fmt_sign_t sign = fmt_sign_t::MINUS;
bool leading_zeros = false;
bool uppercase = false;
bool alternate_form = false;
};
struct fmt_token_t
@ -121,10 +123,15 @@ namespace blt::logging
private:
void parse_fmt_field();
void parse_arg_id();
void parse_fmt_spec_stage_1();
void parse_fmt_spec_stage_2();
void parse_fmt_spec_stage_3();
void parse_fmt_spec();
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_form();
void parse_width();
void parse_precision();
void parse_type();

View File

@ -68,7 +68,7 @@ namespace blt::logging
case fmt_sign_t::SPACE:
if constexpr (std::is_arithmetic_v<T>)
{
if (t >= 0)
if (type.type != fmt_type_t::BINARY && t >= 0)
stream << ' ';
}
break;
@ -90,7 +90,8 @@ namespace blt::logging
{
char buffer[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 j = 0; j < 8; ++j)
@ -127,7 +128,7 @@ namespace blt::logging
}
break;
default:
handle_type(stream, type.type);
handle_type(stream, type);
stream << t;
}
};
@ -135,7 +136,7 @@ namespace blt::logging
void setup_stream(const fmt_spec_t& spec);
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 fixed(std::ostream& stream);

View File

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

View File

@ -73,20 +73,26 @@ namespace blt::logging
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:
stream << std::dec;
break;
case fmt_type_t::OCTAL:
if (spec.alternate_form)
stream << "0";
stream << std::oct;
break;
case fmt_type_t::HEX:
if (spec.alternate_form)
stream << (spec.uppercase ? "0X" : "0x");
stream << std::hex;
break;
case fmt_type_t::HEX_FLOAT:
if (spec.alternate_form)
stream << (spec.uppercase ? "0X" : "0x");
stream << std::hexfloat;
break;
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 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 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");
}