tokenizer, basic logging works
parent
ff2d77a1cd
commit
0490f50e3c
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 5.0.0)
|
||||
set(BLT_VERSION 5.1.0)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
/*
|
||||
* Copyright (C) 2024 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BLT_LOGGING_FMT_TOKENIZER_H
|
||||
#define BLT_LOGGING_FMT_TOKENIZER_H
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <blt/std/types.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
enum class fmt_token_type : u8
|
||||
{
|
||||
STRING,
|
||||
NUMBER,
|
||||
SPACE,
|
||||
COLON,
|
||||
DOT,
|
||||
MINUS,
|
||||
PLUS
|
||||
};
|
||||
|
||||
struct fmt_token_t
|
||||
{
|
||||
fmt_token_type type;
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
class fmt_tokenizer_t
|
||||
{
|
||||
public:
|
||||
explicit fmt_tokenizer_t(const std::string_view fmt): m_fmt(fmt)
|
||||
{}
|
||||
|
||||
static fmt_token_type get_type(char c);
|
||||
|
||||
std::optional<fmt_token_t> next();
|
||||
|
||||
std::vector<fmt_token_t> tokenize();
|
||||
|
||||
private:
|
||||
size_t pos = 0;
|
||||
std::string_view m_fmt;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //BLT_LOGGING_FMT_TOKENIZER_H
|
|
@ -19,11 +19,9 @@
|
|||
#ifndef BLT_LOGGING_LOGGING_H
|
||||
#define BLT_LOGGING_LOGGING_H
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <blt/std/utility.h>
|
||||
#include <vector>
|
||||
#include <blt/meta/meta.h>
|
||||
|
||||
namespace blt::logging
|
||||
|
@ -33,30 +31,56 @@ namespace blt::logging
|
|||
explicit logger_t() = default;
|
||||
|
||||
template <typename T>
|
||||
void print_value(T&& t)
|
||||
std::string print_value(T&& t)
|
||||
{
|
||||
static_assert(meta::is_streamable_v<T>, "T must be streamable in order to work with blt::logging!");
|
||||
m_stream.str("");
|
||||
m_stream.clear();
|
||||
m_stream << std::forward<T>(t);
|
||||
return m_stream.str();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string log(std::string fmt, Args&&... args)
|
||||
{
|
||||
compile(std::move(fmt));
|
||||
((consume_until_fmt(), print_value(std::forward<Args>(args))), ...);
|
||||
m_args_to_str.clear();
|
||||
m_args_to_str.resize(sizeof...(Args));
|
||||
insert(std::make_integer_sequence<size_t, sizeof...(Args)>{}, std::forward<Args>(args)...);
|
||||
finish();
|
||||
return to_string();
|
||||
}
|
||||
|
||||
std::string to_string();
|
||||
|
||||
private:
|
||||
template<typename... Args, size_t... Indexes>
|
||||
void insert(std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
||||
{
|
||||
((handle_insert<Indexes>(std::forward<Args>(args))), ...);
|
||||
}
|
||||
|
||||
template<size_t index, typename T>
|
||||
void handle_insert(T&& t)
|
||||
{
|
||||
m_args_to_str[index] = print_value(std::forward<T>(t));
|
||||
}
|
||||
|
||||
void handle_fmt(std::string_view fmt);
|
||||
|
||||
const std::string& get(size_t index);
|
||||
|
||||
void compile(std::string fmt);
|
||||
|
||||
void consume_until_fmt();
|
||||
bool consume_until_fmt();
|
||||
|
||||
void finish();
|
||||
|
||||
std::string m_fmt;
|
||||
std::stringstream m_stream;
|
||||
std::vector<std::string> m_args_to_str;
|
||||
size_t m_last_fmt_pos = 0;
|
||||
size_t m_arg_pos = 0;
|
||||
};
|
||||
|
||||
void print(const std::string& fmt);
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* <Short Description>
|
||||
* Copyright (C) 2025 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <blt/logging/fmt_tokenizer.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
fmt_token_type fmt_tokenizer_t::get_type(const char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return fmt_token_type::NUMBER;
|
||||
case '+':
|
||||
return fmt_token_type::PLUS;
|
||||
case '-':
|
||||
return fmt_token_type::MINUS;
|
||||
case '.':
|
||||
return fmt_token_type::DOT;
|
||||
case ':':
|
||||
return fmt_token_type::COLON;
|
||||
case ' ':
|
||||
return fmt_token_type::SPACE;
|
||||
default:
|
||||
return fmt_token_type::STRING;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<fmt_token_t> fmt_tokenizer_t::next()
|
||||
{
|
||||
if (pos >= m_fmt.size())
|
||||
return {};
|
||||
switch (const auto base_type = get_type(m_fmt[pos]))
|
||||
{
|
||||
case fmt_token_type::SPACE:
|
||||
case fmt_token_type::PLUS:
|
||||
case fmt_token_type::MINUS:
|
||||
case fmt_token_type::DOT:
|
||||
case fmt_token_type::COLON:
|
||||
return fmt_token_t{base_type, std::string_view{m_fmt.data() + pos++, 1}};
|
||||
default:
|
||||
{
|
||||
const auto begin = pos;
|
||||
for (; pos < m_fmt.size() && get_type(m_fmt[pos]) == base_type; ++pos)
|
||||
{}
|
||||
return fmt_token_t{base_type, std::string_view{m_fmt.data() + begin, pos - begin}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<fmt_token_t> fmt_tokenizer_t::tokenize()
|
||||
{
|
||||
std::vector<fmt_token_t> tokens;
|
||||
while (auto token = next())
|
||||
tokens.push_back(*token);
|
||||
return tokens;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
#include <blt/logging/logging.h>
|
||||
#include <blt/std/types.h>
|
||||
|
||||
|
@ -33,18 +35,67 @@ namespace blt::logging
|
|||
return str;
|
||||
}
|
||||
|
||||
void logger_t::handle_fmt(const std::string_view fmt)
|
||||
{
|
||||
std::cout << fmt << std::endl;
|
||||
}
|
||||
|
||||
const std::string& logger_t::get(const size_t index)
|
||||
{
|
||||
if (index >= m_args_to_str.size())
|
||||
{
|
||||
std::cerr << "Insufficient number of arguments provided to format string '" << m_fmt << "' got ";
|
||||
for (const auto& [i, arg] : enumerate(std::as_const(m_args_to_str)))
|
||||
{
|
||||
std::cerr << '\'' << arg << "'";
|
||||
if (i != m_args_to_str.size() - 1)
|
||||
std::cerr << " ";
|
||||
}
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
return m_args_to_str[index];
|
||||
}
|
||||
|
||||
void logger_t::compile(std::string fmt)
|
||||
{
|
||||
m_fmt = std::move(fmt);
|
||||
m_last_fmt_pos = 0;
|
||||
m_arg_pos = 0;
|
||||
}
|
||||
|
||||
void logger_t::consume_until_fmt()
|
||||
bool logger_t::consume_until_fmt()
|
||||
{
|
||||
const auto begin = m_fmt.find('{', m_last_fmt_pos);
|
||||
if (begin == std::string::npos)
|
||||
return false;
|
||||
const auto end = m_fmt.find('}', begin);
|
||||
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;
|
||||
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);\
|
||||
if (end - begin > 1)
|
||||
handle_fmt(std::string_view(m_fmt.data() + static_cast<ptrdiff_t>(begin + 1), end - begin - 1));
|
||||
else
|
||||
{
|
||||
// no arguments, must consume from args
|
||||
m_stream << get(m_arg_pos++);
|
||||
}
|
||||
m_last_fmt_pos = end + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void logger_t::finish()
|
||||
{
|
||||
m_stream.str("");
|
||||
m_stream.clear();
|
||||
|
||||
while (consume_until_fmt())
|
||||
{}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
logger_t& get_global_logger()
|
||||
|
|
|
@ -16,10 +16,16 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <blt/logging/logging.h>
|
||||
#include <blt/std/utility.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
using endl_t = decltype(static_cast<std::ostream& (*)(std::ostream&)>(std::endl));
|
||||
// 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 '{1}' fmt string with positionals '{0}'", "I am a string!", "Well so am I except cooler :3");
|
||||
// blt::logging::println("This is println {}\twith a std::endl in the middle of it");
|
||||
}
|
Loading…
Reference in New Issue