basic logger works
parent
74878d6b43
commit
b2c3820ed0
|
@ -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.2)
|
set(BLT_VERSION 5.1.3)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,18 @@
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <blt/meta/meta.h>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
#include <blt/logging/fmt_tokenizer.h>
|
#include <blt/logging/fmt_tokenizer.h>
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
struct logger_t
|
struct logger_t
|
||||||
{
|
{
|
||||||
explicit logger_t() = default;
|
explicit logger_t() = default;
|
||||||
|
@ -36,83 +42,116 @@ namespace blt::logging
|
||||||
{
|
{
|
||||||
compile(std::move(fmt));
|
compile(std::move(fmt));
|
||||||
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
|
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
|
||||||
while (auto pair = consume_until_fmt())
|
m_arg_print_funcs.clear();
|
||||||
{
|
m_arg_print_funcs.resize(sizeof...(Args));
|
||||||
auto [begin, end] = *pair;
|
create_conv_funcs(sequence, std::forward<Args>(args)...);
|
||||||
if (end - begin > 0)
|
process_strings();
|
||||||
{
|
|
||||||
auto format_data = handle_fmt(m_fmt.substr(begin + 1, begin - end - 1));
|
|
||||||
auto [arg_pos, fmt_type] = format_data;
|
|
||||||
if (arg_pos == -1)
|
|
||||||
arg_pos = static_cast<i64>(m_arg_pos++);
|
|
||||||
if (fmt_type)
|
|
||||||
{
|
|
||||||
if (fmt_type == fmt_type_t::GENERAL)
|
|
||||||
{
|
|
||||||
apply_func([this](auto&& value)
|
|
||||||
{
|
|
||||||
if (static_cast<u64>(value) > 0xFFFFFFFFFul)
|
|
||||||
exponential();
|
|
||||||
else
|
|
||||||
fixed();
|
|
||||||
m_stream << std::forward<decltype(value)>(value);
|
|
||||||
}, arg_pos, sequence, std::forward<Args>(args)...);
|
|
||||||
} else if (fmt_type == fmt_type_t::CHAR)
|
|
||||||
{
|
|
||||||
|
|
||||||
} else if (fmt_type == fmt_type_t::BINARY)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
apply_func([this](auto&& value)
|
|
||||||
{
|
|
||||||
m_stream << std::forward<decltype(value)>(value);
|
|
||||||
}, arg_pos, sequence, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
apply_func([this](auto&& value)
|
|
||||||
{
|
|
||||||
m_stream << std::forward<decltype(value)>(value);
|
|
||||||
}, m_arg_pos++, sequence, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
return to_string();
|
return to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string();
|
std::string to_string();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Func, typename... Args, size_t... Indexes>
|
template <typename... Args, size_t... Indexes>
|
||||||
void apply_func(const Func& func, const size_t arg, std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
void create_conv_funcs(std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
||||||
{
|
{
|
||||||
((handle_func<Indexes>(func, arg, std::forward<Args>(args))), ...);
|
((handle_func<Indexes>(std::forward<Args>(args))), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t index, typename Func, typename T>
|
template <size_t index, typename T>
|
||||||
void handle_func(const Func& func, const size_t arg, T&& t)
|
void handle_func(const T& t)
|
||||||
{
|
{
|
||||||
if (index == arg)
|
m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type)
|
||||||
func(std::forward<T>(t));
|
{
|
||||||
|
switch (type.sign)
|
||||||
|
{
|
||||||
|
case fmt_sign_t::SPACE:
|
||||||
|
if constexpr (std::is_arithmetic_v<T>)
|
||||||
|
{
|
||||||
|
if (t >= 0)
|
||||||
|
stream << ' ';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case fmt_sign_t::PLUS:
|
||||||
|
if constexpr (std::is_arithmetic_v<T>)
|
||||||
|
{
|
||||||
|
if (t >= 0)
|
||||||
|
stream << '+';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case fmt_sign_t::MINUS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (type.type)
|
||||||
|
{
|
||||||
|
case fmt_type_t::BINARY:
|
||||||
|
{
|
||||||
|
if constexpr (std::is_trivially_copyable_v<T>)
|
||||||
|
{
|
||||||
|
char buffer[sizeof(T)];
|
||||||
|
std::memcpy(buffer, &t, sizeof(T));
|
||||||
|
stream << '0' << (type.uppercase ? 'B' : 'b');
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < 8; ++j)
|
||||||
|
stream << ((buffer[i] & (1 << j)) ? '1' : '0');
|
||||||
|
if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1)
|
||||||
|
stream << ' ';
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
stream << t;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fmt_type_t::CHAR:
|
||||||
|
if constexpr (std::is_arithmetic_v<T> || std::is_convertible_v<T, char>)
|
||||||
|
{
|
||||||
|
stream << static_cast<char>(t);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
stream << t;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case fmt_type_t::GENERAL:
|
||||||
|
if constexpr (std::is_arithmetic_v<T>)
|
||||||
|
{
|
||||||
|
if (static_cast<u64>(t) > 10e12)
|
||||||
|
exponential(stream);
|
||||||
|
else
|
||||||
|
fixed(stream);
|
||||||
|
stream << t;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
stream << t;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
handle_type(stream, type.type);
|
||||||
|
stream << t;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::pair<i64, std::optional<fmt_type_t>> handle_fmt(std::string_view fmt);
|
void setup_stream(const fmt_spec_t& spec);
|
||||||
|
void process_strings();
|
||||||
|
static void handle_type(std::ostream& stream, fmt_type_t type);
|
||||||
|
|
||||||
void exponential();
|
static void exponential(std::ostream& stream);
|
||||||
void fixed();
|
static void fixed(std::ostream& stream);
|
||||||
|
|
||||||
void compile(std::string fmt);
|
void compile(std::string fmt);
|
||||||
|
|
||||||
std::optional<std::pair<size_t, size_t>> consume_until_fmt();
|
std::optional<std::pair<size_t, size_t>> consume_to_next_fmt();
|
||||||
|
|
||||||
void finish();
|
|
||||||
|
|
||||||
std::string m_fmt;
|
std::string m_fmt;
|
||||||
std::stringstream m_stream;
|
std::stringstream m_stream;
|
||||||
fmt_parser_t m_parser;
|
fmt_parser_t m_parser;
|
||||||
|
// normal sections of string
|
||||||
|
std::vector<std::string_view> m_string_sections;
|
||||||
|
// processed format specs
|
||||||
|
std::vector<fmt_spec_t> m_fmt_specs;
|
||||||
|
std::vector<std::function<void(std::ostream&, const fmt_spec_t&)>> m_arg_print_funcs;
|
||||||
size_t m_last_fmt_pos = 0;
|
size_t m_last_fmt_pos = 0;
|
||||||
size_t m_arg_pos = 0;
|
size_t m_arg_pos = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5
|
Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3
|
|
@ -16,6 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <blt/logging/fmt_tokenizer.h>
|
#include <blt/logging/fmt_tokenizer.h>
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
|
@ -97,10 +98,7 @@ namespace blt::logging
|
||||||
void fmt_parser_t::parse_fmt_field()
|
void fmt_parser_t::parse_fmt_field()
|
||||||
{
|
{
|
||||||
if (!has_next())
|
if (!has_next())
|
||||||
{
|
throw std::runtime_error("Expected token when parsing format field");
|
||||||
std::cerr << "Expected token when parsing format field" << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
const auto [type, value] = peek();
|
const auto [type, value] = peek();
|
||||||
if (type == fmt_token_type::COLON)
|
if (type == fmt_token_type::COLON)
|
||||||
{
|
{
|
||||||
|
@ -118,16 +116,14 @@ namespace blt::logging
|
||||||
parse_fmt_spec_stage_1();
|
parse_fmt_spec_stage_1();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
throw std::runtime_error("Expected ':' when parsing format field after arg id!");
|
||||||
std::cerr << "Expected ':' when parsing format field after arg id!" << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Expected unknown token '" << static_cast<u8>(type) << "' value '" << value << "' when parsing format field" << std::endl;
|
std::stringstream ss;
|
||||||
std::exit(EXIT_FAILURE);
|
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();
|
||||||
|
@ -136,15 +132,13 @@ namespace blt::logging
|
||||||
void fmt_parser_t::parse_arg_id()
|
void fmt_parser_t::parse_arg_id()
|
||||||
{
|
{
|
||||||
if (!has_next())
|
if (!has_next())
|
||||||
{
|
throw std::runtime_error("Missing token when parsing arg id");
|
||||||
std::cerr << "Missing token when parsing arg id" << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
const auto [type, value] = next();
|
const auto [type, value] = next();
|
||||||
if (type != fmt_token_type::NUMBER)
|
if (type != fmt_token_type::NUMBER)
|
||||||
{
|
{
|
||||||
std::cerr << "Expected number when parsing arg id, unexpected value '" << value << '\'' << std::endl;
|
std::stringstream ss;
|
||||||
std::exit(EXIT_FAILURE);
|
ss << "Expected number when parsing arg id, unexpected value '" << value << '\'';
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
m_spec.arg_id = std::stoll(std::string(value));
|
m_spec.arg_id = std::stoll(std::string(value));
|
||||||
}
|
}
|
||||||
|
@ -159,8 +153,11 @@ namespace blt::logging
|
||||||
{
|
{
|
||||||
case fmt_token_type::STRING:
|
case fmt_token_type::STRING:
|
||||||
case fmt_token_type::COLON:
|
case fmt_token_type::COLON:
|
||||||
std::cerr << "(Stage 1) Invalid token type " << static_cast<u8>(type) << " value " << value << std::endl;
|
{
|
||||||
std::exit(EXIT_FAILURE);
|
std::stringstream ss;
|
||||||
|
ss << "(Stage 1) Invalid token type " << static_cast<u8>(type) << " value " << value;
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
case fmt_token_type::NUMBER:
|
case fmt_token_type::NUMBER:
|
||||||
parse_width();
|
parse_width();
|
||||||
parse_fmt_spec_stage_3();
|
parse_fmt_spec_stage_3();
|
||||||
|
@ -191,8 +188,11 @@ 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:
|
||||||
std::cerr << "(Stage 2) Invalid token type " << static_cast<u8>(type) << " value " << value << std::endl;
|
{
|
||||||
std::exit(EXIT_FAILURE);
|
std::stringstream ss;
|
||||||
|
ss << "(Stage 2) Invalid token type " << static_cast<u8>(type) << " value " << value;
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
case fmt_token_type::NUMBER:
|
case fmt_token_type::NUMBER:
|
||||||
parse_width();
|
parse_width();
|
||||||
parse_fmt_spec_stage_3();
|
parse_fmt_spec_stage_3();
|
||||||
|
@ -217,8 +217,11 @@ namespace blt::logging
|
||||||
case fmt_token_type::PLUS:
|
case fmt_token_type::PLUS:
|
||||||
case fmt_token_type::SPACE:
|
case fmt_token_type::SPACE:
|
||||||
case fmt_token_type::NUMBER:
|
case fmt_token_type::NUMBER:
|
||||||
std::cerr << "(Stage 3) Invalid token type " << static_cast<u8>(type) << " value " << value << std::endl;
|
{
|
||||||
std::exit(EXIT_FAILURE);
|
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:
|
case fmt_token_type::DOT:
|
||||||
consume();
|
consume();
|
||||||
parse_precision();
|
parse_precision();
|
||||||
|
@ -231,8 +234,9 @@ namespace blt::logging
|
||||||
auto [_, value] = next();
|
auto [_, value] = next();
|
||||||
if (value.size() > 1)
|
if (value.size() > 1)
|
||||||
{
|
{
|
||||||
std::cerr << "Sign contains more than one character, we are not sure how to interpret this. Value '" << value << "'\n";
|
std::stringstream ss;
|
||||||
std::exit(EXIT_FAILURE);
|
ss << "Sign contains more than one character, we are not sure how to interpret this. Value '" << value << "'";
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
switch (value[0])
|
switch (value[0])
|
||||||
{
|
{
|
||||||
|
@ -246,8 +250,11 @@ namespace blt::logging
|
||||||
m_spec.sign = fmt_sign_t::SPACE;
|
m_spec.sign = fmt_sign_t::SPACE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cerr << "Invalid sign " << value[0] << std::endl;
|
{
|
||||||
std::exit(EXIT_FAILURE);
|
std::stringstream ss;
|
||||||
|
ss << "Invalid sign " << value[0];
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,10 +269,7 @@ namespace blt::logging
|
||||||
void fmt_parser_t::parse_precision()
|
void fmt_parser_t::parse_precision()
|
||||||
{
|
{
|
||||||
if (!has_next())
|
if (!has_next())
|
||||||
{
|
throw std::runtime_error("Missing token when parsing precision");
|
||||||
std::cerr << "Missing token when parsing precision" << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
auto [_, value] = next();
|
auto [_, value] = next();
|
||||||
m_spec.precision = std::stoll(std::string(value));
|
m_spec.precision = std::stoll(std::string(value));
|
||||||
}
|
}
|
||||||
|
@ -273,15 +277,13 @@ namespace blt::logging
|
||||||
void fmt_parser_t::parse_type()
|
void fmt_parser_t::parse_type()
|
||||||
{
|
{
|
||||||
if (!has_next())
|
if (!has_next())
|
||||||
{
|
throw std::runtime_error("Missing token when parsing type");
|
||||||
std::cerr << "Missing token when parsing type" << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
auto [_, value] = next();
|
auto [_, value] = next();
|
||||||
if (value.size() != 1)
|
if (value.size() != 1)
|
||||||
{
|
{
|
||||||
std::cerr << "Type contains more than one character, we are not sure how to interpret this value '" << value << "'\n";
|
std::stringstream ss;
|
||||||
std::exit(EXIT_FAILURE);
|
ss << "Type contains more than one character, we are not sure how to interpret this value '" << value << "'";
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
m_spec.uppercase = std::isupper(value.front());
|
m_spec.uppercase = std::isupper(value.front());
|
||||||
switch (value.front())
|
switch (value.front())
|
||||||
|
@ -320,8 +322,9 @@ namespace blt::logging
|
||||||
m_spec.type = fmt_type_t::GENERAL;
|
m_spec.type = fmt_type_t::GENERAL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cerr << "Invalid type " << value << std::endl;
|
std::stringstream ss;
|
||||||
std::exit(EXIT_FAILURE);
|
ss << "Invalid type " << value;
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,122 +23,147 @@
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
struct logging_thread_context_t
|
struct logging_thread_context_t
|
||||||
{
|
{
|
||||||
logger_t logger;
|
logger_t logger;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string logger_t::to_string()
|
std::string logger_t::to_string()
|
||||||
{
|
{
|
||||||
auto str = m_stream.str();
|
auto str = m_stream.str();
|
||||||
m_stream.str("");
|
m_stream.str("");
|
||||||
m_stream.clear();
|
m_stream.clear();
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<i64, std::optional<fmt_type_t>> logger_t::handle_fmt(const std::string_view fmt)
|
void logger_t::setup_stream(const fmt_spec_t& spec)
|
||||||
{
|
{
|
||||||
const auto spec = m_parser.parse(fmt);
|
if (spec.leading_zeros)
|
||||||
if (spec.leading_zeros)
|
m_stream << std::setfill('0');
|
||||||
m_stream << std::setfill('0');
|
else
|
||||||
else
|
m_stream << std::setfill(' ');
|
||||||
m_stream << std::setfill(' ');
|
if (spec.width > 0)
|
||||||
if (spec.width > 0)
|
m_stream << std::setw(static_cast<i32>(spec.width));
|
||||||
m_stream << std::setw(static_cast<i32>(spec.width));
|
else
|
||||||
else
|
m_stream << std::setw(0);
|
||||||
m_stream << std::setw(0);
|
if (spec.precision > 0)
|
||||||
if (spec.precision > 0)
|
m_stream << std::setprecision(static_cast<i32>(spec.precision));
|
||||||
m_stream << std::setprecision(static_cast<i32>(spec.precision));
|
else
|
||||||
else
|
m_stream << std::setprecision(static_cast<int>(std::cout.precision()));
|
||||||
m_stream << std::setprecision(2);
|
if (spec.uppercase)
|
||||||
if (spec.uppercase)
|
m_stream << std::uppercase;
|
||||||
m_stream << std::uppercase;
|
else
|
||||||
else
|
m_stream << std::nouppercase;
|
||||||
m_stream << std::nouppercase;
|
}
|
||||||
std::optional<fmt_type_t> type;
|
|
||||||
switch (spec.type)
|
|
||||||
{
|
|
||||||
case fmt_type_t::BINARY:
|
|
||||||
case fmt_type_t::CHAR:
|
|
||||||
case fmt_type_t::GENERAL:
|
|
||||||
type = spec.type;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::DECIMAL:
|
|
||||||
m_stream << std::dec;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::OCTAL:
|
|
||||||
m_stream << std::oct;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::HEX:
|
|
||||||
m_stream << std::hex;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::HEX_FLOAT:
|
|
||||||
m_stream << std::hexfloat;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::EXPONENT:
|
|
||||||
m_stream << std::scientific;
|
|
||||||
break;
|
|
||||||
case fmt_type_t::FIXED_POINT:
|
|
||||||
m_stream << std::fixed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {spec.arg_id, type};
|
|
||||||
}
|
|
||||||
|
|
||||||
void logger_t::exponential()
|
void logger_t::process_strings()
|
||||||
{
|
{
|
||||||
m_stream << std::scientific;
|
auto spec_it = m_fmt_specs.begin();
|
||||||
}
|
auto str_it = m_string_sections.begin();
|
||||||
|
for (; spec_it != m_fmt_specs.end(); ++spec_it, ++str_it)
|
||||||
|
{
|
||||||
|
m_stream << *str_it;
|
||||||
|
auto arg_pos = spec_it->arg_id;
|
||||||
|
if (arg_pos == -1)
|
||||||
|
arg_pos = static_cast<i64>(m_arg_pos++);
|
||||||
|
|
||||||
void logger_t::fixed()
|
setup_stream(*spec_it);
|
||||||
{
|
m_arg_print_funcs[arg_pos](m_stream, *spec_it);
|
||||||
m_stream << std::fixed;
|
}
|
||||||
}
|
m_stream << *str_it;
|
||||||
|
}
|
||||||
|
|
||||||
void logger_t::compile(std::string fmt)
|
void logger_t::handle_type(std::ostream& stream, const fmt_type_t type)
|
||||||
{
|
{
|
||||||
m_fmt = std::move(fmt);
|
switch (type)
|
||||||
m_last_fmt_pos = 0;
|
{
|
||||||
m_arg_pos = 0;
|
case fmt_type_t::DECIMAL:
|
||||||
m_stream.str("");
|
stream << std::dec;
|
||||||
m_stream.clear();
|
break;
|
||||||
}
|
case fmt_type_t::OCTAL:
|
||||||
|
stream << std::oct;
|
||||||
|
break;
|
||||||
|
case fmt_type_t::HEX:
|
||||||
|
stream << std::hex;
|
||||||
|
break;
|
||||||
|
case fmt_type_t::HEX_FLOAT:
|
||||||
|
stream << std::hexfloat;
|
||||||
|
break;
|
||||||
|
case fmt_type_t::EXPONENT:
|
||||||
|
stream << std::scientific;
|
||||||
|
break;
|
||||||
|
case fmt_type_t::FIXED_POINT:
|
||||||
|
stream << std::fixed;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::pair<size_t, size_t>> logger_t::consume_until_fmt()
|
void logger_t::exponential(std::ostream& stream)
|
||||||
{
|
{
|
||||||
const auto begin = m_fmt.find('{', m_last_fmt_pos);
|
stream << std::scientific;
|
||||||
if (begin == std::string::npos)
|
}
|
||||||
return {};
|
|
||||||
const auto end = m_fmt.find('}', begin);
|
|
||||||
if (end == std::string::npos)
|
|
||||||
{
|
|
||||||
std::cerr << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast<i64>(begin) - 5, 0l)) << std::endl;
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
m_stream << std::string_view(m_fmt.data() + static_cast<ptrdiff_t>(m_last_fmt_pos), begin - m_last_fmt_pos);\
|
|
||||||
m_last_fmt_pos = end + 1;
|
|
||||||
return std::pair{begin, end};
|
|
||||||
}
|
|
||||||
|
|
||||||
void logger_t::finish()
|
void logger_t::fixed(std::ostream& stream)
|
||||||
{
|
{
|
||||||
m_stream << std::string_view(m_fmt.data() + static_cast<ptrdiff_t>(m_last_fmt_pos), m_fmt.size() - m_last_fmt_pos);
|
stream << std::fixed;
|
||||||
m_last_fmt_pos = m_fmt.size();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger_t& get_global_logger()
|
void logger_t::compile(std::string fmt)
|
||||||
{
|
{
|
||||||
thread_local logging_thread_context_t context;
|
m_fmt = std::move(fmt);
|
||||||
return context.logger;
|
m_last_fmt_pos = 0;
|
||||||
}
|
m_arg_pos = 0;
|
||||||
|
m_stream.str("");
|
||||||
|
m_stream.clear();
|
||||||
|
m_string_sections.clear();
|
||||||
|
m_fmt_specs.clear();
|
||||||
|
ptrdiff_t last_pos = 0;
|
||||||
|
while (auto pair = consume_to_next_fmt())
|
||||||
|
{
|
||||||
|
const auto [begin, end] = *pair;
|
||||||
|
m_string_sections.emplace_back(m_fmt.data() + last_pos, begin - last_pos);
|
||||||
|
if (end - begin > 1)
|
||||||
|
m_fmt_specs.push_back(m_parser.parse(std::string_view{m_fmt.data() + static_cast<ptrdiff_t>(begin) + 1, end - begin - 1}));
|
||||||
|
else
|
||||||
|
m_fmt_specs.emplace_back();
|
||||||
|
last_pos = static_cast<ptrdiff_t>(end) + 1;
|
||||||
|
}
|
||||||
|
m_string_sections.emplace_back(m_fmt.data() + last_pos, m_fmt.size() - last_pos);
|
||||||
|
m_last_fmt_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void print(const std::string& fmt)
|
std::optional<std::pair<size_t, size_t>> logger_t::consume_to_next_fmt()
|
||||||
{
|
{
|
||||||
std::cout << fmt;
|
const auto begin = m_fmt.find('{', m_last_fmt_pos);
|
||||||
}
|
if (begin == std::string::npos)
|
||||||
|
return {};
|
||||||
|
const auto next_begin = m_fmt.find('{', begin + 1);
|
||||||
|
const auto end = m_fmt.find('}', begin);
|
||||||
|
if (end == std::string::npos || (next_begin != std::string::npos && next_begin < end))
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast<i64>(begin) - 5, 0l));
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
|
m_last_fmt_pos = end + 1;
|
||||||
|
return std::pair{begin, end};
|
||||||
|
}
|
||||||
|
|
||||||
void newline()
|
logger_t& get_global_logger()
|
||||||
{
|
{
|
||||||
std::cout << std::endl;
|
thread_local logging_thread_context_t context;
|
||||||
}
|
return context.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(const std::string& fmt)
|
||||||
|
{
|
||||||
|
std::cout << fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void newline()
|
||||||
|
{
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,16 @@ int main()
|
||||||
// blt::logging::println("{} | {} | {} | {}", blt::type_string<endl_t>());
|
// blt::logging::println("{} | {} | {} | {}", blt::type_string<endl_t>());
|
||||||
blt::logging::println("This is a println!");
|
blt::logging::println("This is a println!");
|
||||||
blt::logging::println("This is a println with args '{}'", 42);
|
blt::logging::println("This is a println with args '{}'", 42);
|
||||||
blt::logging::println("This is a println with multiple args '{}' '{}' '{}'", 42, 32.34231233, "Hello World!");
|
blt::logging::println("This is a println with multiple args '{}' '{:.100}' '{}'", 42, 32.34231233f, "Hello World!");
|
||||||
blt::logging::println("This is a '{1}' fmt string with positionals '{0}'", "I am a string!", "Well so am I except cooler :3");
|
blt::logging::println("This is a '{1}' fmt string with positionals '{0}'", "I am a string!", "Well so am I except cooler :3");
|
||||||
blt::logging::println("This is a println with a sign {:+}", 4120);
|
blt::logging::println("This is a println with a sign {:+}", 4120);
|
||||||
|
blt::logging::println("This is a println with a sign {:+}", -4120);
|
||||||
blt::logging::println("This is a println with a space {: }", 4120);
|
blt::logging::println("This is a println with a space {: }", 4120);
|
||||||
blt::logging::println("This is a println with a with {:3}", 4120);
|
blt::logging::println("This is a println with a space {: }", -4120);
|
||||||
|
blt::logging::println("This is a println with a minus {:-}", 4120);
|
||||||
|
blt::logging::println("This is a println with a minus {:-}", -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 {:.3}", 42.232342349);
|
blt::logging::println("This is a println with a precision {:.10f}", 42.232342349);
|
||||||
// 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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue