basic logger works
parent
74878d6b43
commit
b2c3820ed0
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 5.1.2)
|
||||
set(BLT_VERSION 5.1.3)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -21,12 +21,18 @@
|
|||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <blt/meta/meta.h>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <blt/logging/fmt_tokenizer.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
}
|
||||
|
||||
struct logger_t
|
||||
{
|
||||
explicit logger_t() = default;
|
||||
|
@ -36,83 +42,116 @@ namespace blt::logging
|
|||
{
|
||||
compile(std::move(fmt));
|
||||
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
|
||||
while (auto pair = consume_until_fmt())
|
||||
{
|
||||
auto [begin, end] = *pair;
|
||||
if (end - begin > 0)
|
||||
{
|
||||
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();
|
||||
m_arg_print_funcs.clear();
|
||||
m_arg_print_funcs.resize(sizeof...(Args));
|
||||
create_conv_funcs(sequence, std::forward<Args>(args)...);
|
||||
process_strings();
|
||||
return to_string();
|
||||
}
|
||||
|
||||
std::string to_string();
|
||||
|
||||
private:
|
||||
template <typename Func, typename... Args, size_t... Indexes>
|
||||
void apply_func(const Func& func, const size_t arg, std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
||||
template <typename... Args, size_t... Indexes>
|
||||
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>
|
||||
void handle_func(const Func& func, const size_t arg, T&& t)
|
||||
template <size_t index, typename T>
|
||||
void handle_func(const T& t)
|
||||
{
|
||||
if (index == arg)
|
||||
func(std::forward<T>(t));
|
||||
m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type)
|
||||
{
|
||||
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();
|
||||
void fixed();
|
||||
static void exponential(std::ostream& stream);
|
||||
static void fixed(std::ostream& stream);
|
||||
|
||||
void compile(std::string fmt);
|
||||
|
||||
std::optional<std::pair<size_t, size_t>> consume_until_fmt();
|
||||
|
||||
void finish();
|
||||
std::optional<std::pair<size_t, size_t>> consume_to_next_fmt();
|
||||
|
||||
std::string m_fmt;
|
||||
std::stringstream m_stream;
|
||||
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_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/>.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <blt/logging/fmt_tokenizer.h>
|
||||
|
||||
namespace blt::logging
|
||||
|
@ -97,10 +98,7 @@ namespace blt::logging
|
|||
void fmt_parser_t::parse_fmt_field()
|
||||
{
|
||||
if (!has_next())
|
||||
{
|
||||
std::cerr << "Expected token when parsing format field" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
throw std::runtime_error("Expected token when parsing format field");
|
||||
const auto [type, value] = peek();
|
||||
if (type == fmt_token_type::COLON)
|
||||
{
|
||||
|
@ -118,16 +116,14 @@ namespace blt::logging
|
|||
parse_fmt_spec_stage_1();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Expected ':' when parsing format field after arg id!" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
throw std::runtime_error("Expected ':' when parsing format field after arg id!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Expected unknown token '" << static_cast<u8>(type) << "' value '" << value << "' when parsing format field" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
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();
|
||||
|
@ -136,15 +132,13 @@ namespace blt::logging
|
|||
void fmt_parser_t::parse_arg_id()
|
||||
{
|
||||
if (!has_next())
|
||||
{
|
||||
std::cerr << "Missing token when parsing arg id" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
throw std::runtime_error("Missing token when parsing arg id");
|
||||
const auto [type, value] = next();
|
||||
if (type != fmt_token_type::NUMBER)
|
||||
{
|
||||
std::cerr << "Expected number when parsing arg id, unexpected value '" << value << '\'' << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
std::stringstream ss;
|
||||
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));
|
||||
}
|
||||
|
@ -159,8 +153,11 @@ namespace blt::logging
|
|||
{
|
||||
case fmt_token_type::STRING:
|
||||
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:
|
||||
parse_width();
|
||||
parse_fmt_spec_stage_3();
|
||||
|
@ -191,8 +188,11 @@ namespace blt::logging
|
|||
case fmt_token_type::MINUS:
|
||||
case fmt_token_type::PLUS:
|
||||
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:
|
||||
parse_width();
|
||||
parse_fmt_spec_stage_3();
|
||||
|
@ -217,8 +217,11 @@ namespace blt::logging
|
|||
case fmt_token_type::PLUS:
|
||||
case fmt_token_type::SPACE:
|
||||
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:
|
||||
consume();
|
||||
parse_precision();
|
||||
|
@ -231,8 +234,9 @@ namespace blt::logging
|
|||
auto [_, value] = next();
|
||||
if (value.size() > 1)
|
||||
{
|
||||
std::cerr << "Sign contains more than one character, we are not sure how to interpret this. Value '" << value << "'\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
std::stringstream ss;
|
||||
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])
|
||||
{
|
||||
|
@ -246,8 +250,11 @@ namespace blt::logging
|
|||
m_spec.sign = fmt_sign_t::SPACE;
|
||||
break;
|
||||
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()
|
||||
{
|
||||
if (!has_next())
|
||||
{
|
||||
std::cerr << "Missing token when parsing precision" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
throw std::runtime_error("Missing token when parsing precision");
|
||||
auto [_, value] = next();
|
||||
m_spec.precision = std::stoll(std::string(value));
|
||||
}
|
||||
|
@ -273,15 +277,13 @@ namespace blt::logging
|
|||
void fmt_parser_t::parse_type()
|
||||
{
|
||||
if (!has_next())
|
||||
{
|
||||
std::cerr << "Missing token when parsing type" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
throw std::runtime_error("Missing token when parsing type");
|
||||
auto [_, value] = next();
|
||||
if (value.size() != 1)
|
||||
{
|
||||
std::cerr << "Type contains more than one character, we are not sure how to interpret this value '" << value << "'\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
std::stringstream ss;
|
||||
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());
|
||||
switch (value.front())
|
||||
|
@ -320,8 +322,9 @@ namespace blt::logging
|
|||
m_spec.type = fmt_type_t::GENERAL;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Invalid type " << value << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
std::stringstream ss;
|
||||
ss << "Invalid type " << value;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,122 +23,147 @@
|
|||
|
||||
namespace blt::logging
|
||||
{
|
||||
struct logging_thread_context_t
|
||||
{
|
||||
logger_t logger;
|
||||
};
|
||||
struct logging_thread_context_t
|
||||
{
|
||||
logger_t logger;
|
||||
};
|
||||
|
||||
std::string logger_t::to_string()
|
||||
{
|
||||
auto str = m_stream.str();
|
||||
m_stream.str("");
|
||||
m_stream.clear();
|
||||
return str;
|
||||
}
|
||||
std::string logger_t::to_string()
|
||||
{
|
||||
auto str = m_stream.str();
|
||||
m_stream.str("");
|
||||
m_stream.clear();
|
||||
return str;
|
||||
}
|
||||
|
||||
std::pair<i64, std::optional<fmt_type_t>> logger_t::handle_fmt(const std::string_view fmt)
|
||||
{
|
||||
const auto spec = m_parser.parse(fmt);
|
||||
if (spec.leading_zeros)
|
||||
m_stream << std::setfill('0');
|
||||
else
|
||||
m_stream << std::setfill(' ');
|
||||
if (spec.width > 0)
|
||||
m_stream << std::setw(static_cast<i32>(spec.width));
|
||||
else
|
||||
m_stream << std::setw(0);
|
||||
if (spec.precision > 0)
|
||||
m_stream << std::setprecision(static_cast<i32>(spec.precision));
|
||||
else
|
||||
m_stream << std::setprecision(2);
|
||||
if (spec.uppercase)
|
||||
m_stream << std::uppercase;
|
||||
else
|
||||
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::setup_stream(const fmt_spec_t& spec)
|
||||
{
|
||||
if (spec.leading_zeros)
|
||||
m_stream << std::setfill('0');
|
||||
else
|
||||
m_stream << std::setfill(' ');
|
||||
if (spec.width > 0)
|
||||
m_stream << std::setw(static_cast<i32>(spec.width));
|
||||
else
|
||||
m_stream << std::setw(0);
|
||||
if (spec.precision > 0)
|
||||
m_stream << std::setprecision(static_cast<i32>(spec.precision));
|
||||
else
|
||||
m_stream << std::setprecision(static_cast<int>(std::cout.precision()));
|
||||
if (spec.uppercase)
|
||||
m_stream << std::uppercase;
|
||||
else
|
||||
m_stream << std::nouppercase;
|
||||
}
|
||||
|
||||
void logger_t::exponential()
|
||||
{
|
||||
m_stream << std::scientific;
|
||||
}
|
||||
void logger_t::process_strings()
|
||||
{
|
||||
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()
|
||||
{
|
||||
m_stream << std::fixed;
|
||||
}
|
||||
setup_stream(*spec_it);
|
||||
m_arg_print_funcs[arg_pos](m_stream, *spec_it);
|
||||
}
|
||||
m_stream << *str_it;
|
||||
}
|
||||
|
||||
void logger_t::compile(std::string fmt)
|
||||
{
|
||||
m_fmt = std::move(fmt);
|
||||
m_last_fmt_pos = 0;
|
||||
m_arg_pos = 0;
|
||||
m_stream.str("");
|
||||
m_stream.clear();
|
||||
}
|
||||
void logger_t::handle_type(std::ostream& stream, const fmt_type_t type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case fmt_type_t::DECIMAL:
|
||||
stream << std::dec;
|
||||
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()
|
||||
{
|
||||
const auto begin = m_fmt.find('{', m_last_fmt_pos);
|
||||
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::exponential(std::ostream& stream)
|
||||
{
|
||||
stream << std::scientific;
|
||||
}
|
||||
|
||||
void logger_t::finish()
|
||||
{
|
||||
m_stream << std::string_view(m_fmt.data() + static_cast<ptrdiff_t>(m_last_fmt_pos), m_fmt.size() - m_last_fmt_pos);
|
||||
m_last_fmt_pos = m_fmt.size();
|
||||
}
|
||||
void logger_t::fixed(std::ostream& stream)
|
||||
{
|
||||
stream << std::fixed;
|
||||
}
|
||||
|
||||
logger_t& get_global_logger()
|
||||
{
|
||||
thread_local logging_thread_context_t context;
|
||||
return context.logger;
|
||||
}
|
||||
void logger_t::compile(std::string fmt)
|
||||
{
|
||||
m_fmt = std::move(fmt);
|
||||
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::cout << fmt;
|
||||
}
|
||||
std::optional<std::pair<size_t, size_t>> logger_t::consume_to_next_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()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
logger_t& get_global_logger()
|
||||
{
|
||||
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("This is a println!");
|
||||
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 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 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 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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue