mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-24 19:52:37 +01:00
Fmt/Log fixes
This commit is contained in:
parent
98f09e4f27
commit
d646fbb94f
@ -56,7 +56,7 @@ namespace logs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode level, current thread name, channel name and write log message
|
// Encode level, current thread name, channel name and write log message
|
||||||
virtual void log(const message& msg) override;
|
virtual void log(const message& msg, const std::string& prefix, const std::string& text) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static file_listener* get_logger()
|
static file_listener* get_logger()
|
||||||
@ -88,27 +88,18 @@ void logs::listener::add(logs::listener* _new)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void logs::channel::broadcast(const logs::channel& ch, logs::level sev, const char* fmt, const fmt::supplementary_info* sup, const u64* args)
|
void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||||
{
|
{
|
||||||
std::string text; fmt::raw_append(text, fmt, sup, args);
|
std::string text; fmt::raw_append(text, fmt, sup, args);
|
||||||
std::string prefix(g_tls_log_prefix ? g_tls_log_prefix() : "");
|
std::string prefix(g_tls_log_prefix ? g_tls_log_prefix() : "");
|
||||||
|
|
||||||
// Prepare message information
|
|
||||||
message msg;
|
|
||||||
msg.ch = &ch;
|
|
||||||
msg.sev = sev;
|
|
||||||
msg.text = text.data();
|
|
||||||
msg.text_size = text.size();
|
|
||||||
msg.prefix = prefix.data();
|
|
||||||
msg.prefix_size = prefix.size();
|
|
||||||
|
|
||||||
// Get first (main) listener
|
// Get first (main) listener
|
||||||
listener* lis = get_logger();
|
listener* lis = get_logger();
|
||||||
|
|
||||||
// Send message to all listeners
|
// Send message to all listeners
|
||||||
while (lis)
|
while (lis)
|
||||||
{
|
{
|
||||||
lis->log(msg);
|
lis->log(*this, prefix, text);
|
||||||
lis = lis->m_next;
|
lis = lis->m_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,9 +126,9 @@ void logs::file_writer::log(const char* text, std::size_t size)
|
|||||||
m_file.write(text, size);
|
m_file.write(text, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logs::file_listener::log(const logs::message& msg)
|
void logs::file_listener::log(const logs::message& msg, const std::string& prefix, const std::string& _text)
|
||||||
{
|
{
|
||||||
std::string text; text.reserve(msg.text_size + msg.prefix_size + 200);
|
std::string text; text.reserve(prefix.size() + _text.size() + 200);
|
||||||
|
|
||||||
// Used character: U+00B7 (Middle Dot)
|
// Used character: U+00B7 (Middle Dot)
|
||||||
switch (msg.sev)
|
switch (msg.sev)
|
||||||
@ -154,9 +145,11 @@ void logs::file_listener::log(const logs::message& msg)
|
|||||||
|
|
||||||
// TODO: print time?
|
// TODO: print time?
|
||||||
|
|
||||||
if (msg.prefix_size > 0)
|
if (prefix.size() > 0)
|
||||||
{
|
{
|
||||||
text += fmt::format("{%s} ", msg.prefix);
|
text += "{";
|
||||||
|
text += prefix;
|
||||||
|
text += "} ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.ch->name)
|
if (msg.ch->name)
|
||||||
@ -169,7 +162,7 @@ void logs::file_listener::log(const logs::message& msg)
|
|||||||
text += "TODO: ";
|
text += "TODO: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
text += msg.text;
|
text += _text;
|
||||||
text += '\n';
|
text += '\n';
|
||||||
|
|
||||||
file_writer::log(text.data(), text.size());
|
file_writer::log(text.data(), text.size());
|
||||||
|
@ -27,10 +27,8 @@ namespace logs
|
|||||||
const channel* ch;
|
const channel* ch;
|
||||||
level sev;
|
level sev;
|
||||||
|
|
||||||
const char* prefix;
|
// Send log message to global logger instance
|
||||||
std::size_t prefix_size;
|
void broadcast(const char*, const fmt_type_info*, const u64*);
|
||||||
const char* text;
|
|
||||||
std::size_t text_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class listener
|
class listener
|
||||||
@ -38,7 +36,7 @@ namespace logs
|
|||||||
// Next listener (linked list)
|
// Next listener (linked list)
|
||||||
atomic_t<listener*> m_next{};
|
atomic_t<listener*> m_next{};
|
||||||
|
|
||||||
friend struct channel;
|
friend struct message;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr listener() = default;
|
constexpr listener() = default;
|
||||||
@ -46,7 +44,7 @@ namespace logs
|
|||||||
virtual ~listener() = default;
|
virtual ~listener() = default;
|
||||||
|
|
||||||
// Process log message
|
// Process log message
|
||||||
virtual void log(const message& msg) = 0;
|
virtual void log(const message& msg, const std::string& prefix, const std::string& text) = 0;
|
||||||
|
|
||||||
// Add new listener
|
// Add new listener
|
||||||
static void add(listener*);
|
static void add(listener*);
|
||||||
@ -69,11 +67,11 @@ namespace logs
|
|||||||
|
|
||||||
// Formatting function
|
// Formatting function
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
SAFE_BUFFERS void format(level sev, const char* fmt, const Args&... args) const
|
SAFE_BUFFERS FORCE_INLINE void format(level sev, const char* fmt, const Args&... args) const
|
||||||
{
|
{
|
||||||
if (UNLIKELY(sev <= enabled))
|
if (UNLIKELY(sev <= enabled))
|
||||||
{
|
{
|
||||||
broadcast(*this, sev, fmt, fmt::arg_type_info::get<typename fmt_unveil<Args>::type...>(), fmt::args_t<Args...>{::fmt_unveil<Args>::get(args)...});
|
message{this, sev}.broadcast(fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,9 +91,6 @@ namespace logs
|
|||||||
GEN_LOG_METHOD(trace)
|
GEN_LOG_METHOD(trace)
|
||||||
|
|
||||||
#undef GEN_LOG_METHOD
|
#undef GEN_LOG_METHOD
|
||||||
private:
|
|
||||||
// Send log message to global logger instance
|
|
||||||
static void broadcast(const channel& ch, level sev, const char*, const fmt::supplementary_info*, const u64*);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Small set of predefined channels */
|
/* Small set of predefined channels */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "StrFmt.h"
|
#include "StrFmt.h"
|
||||||
#include "BEType.h"
|
#include "BEType.h"
|
||||||
#include "StrUtil.h"
|
#include "StrUtil.h"
|
||||||
|
#include "Macro.h"
|
||||||
#include "cfmt.h"
|
#include "cfmt.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -10,6 +11,12 @@ void fmt_class_string<const void*>::format(std::string& out, u64 arg)
|
|||||||
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void fmt_class_string<std::nullptr_t>::format(std::string& out, u64 arg)
|
||||||
|
{
|
||||||
|
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
||||||
|
}
|
||||||
|
|
||||||
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
|
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
|
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
|
||||||
@ -97,13 +104,13 @@ void fmt_class_string<ullong>::format(std::string& out, u64 arg)
|
|||||||
template<>
|
template<>
|
||||||
void fmt_class_string<float>::format(std::string& out, u64 arg)
|
void fmt_class_string<float>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%f", static_cast<float>(reinterpret_cast<f64&>(arg)));
|
fmt::append(out, "%gf", static_cast<float>(reinterpret_cast<f64&>(arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void fmt_class_string<double>::format(std::string& out, u64 arg)
|
void fmt_class_string<double>::format(std::string& out, u64 arg)
|
||||||
{
|
{
|
||||||
fmt::append(out, "%f", reinterpret_cast<f64&>(arg));
|
fmt::append(out, "%g", reinterpret_cast<f64&>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -127,24 +134,21 @@ namespace fmt
|
|||||||
// Temporary implementation
|
// Temporary implementation
|
||||||
struct fmt::cfmt_src
|
struct fmt::cfmt_src
|
||||||
{
|
{
|
||||||
const fmt::supplementary_info* sup;
|
const fmt_type_info* sup;
|
||||||
const u64* args;
|
const u64* args;
|
||||||
|
|
||||||
bool test(std::size_t index = 0)
|
bool test(std::size_t index) const
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i <= index; i++)
|
if (!sup[index].fmt_string)
|
||||||
{
|
{
|
||||||
if (!sup[i].fmt_string)
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T get(std::size_t index = 0)
|
T get(std::size_t index) const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<const T&>(args[index]);
|
return reinterpret_cast<const T&>(args[index]);
|
||||||
}
|
}
|
||||||
@ -155,20 +159,44 @@ struct fmt::cfmt_src
|
|||||||
++args += extra;
|
++args += extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t fmt_string(std::string& out)
|
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
||||||
{
|
{
|
||||||
const std::size_t start = out.size();
|
const std::size_t start = out.size();
|
||||||
sup->fmt_string(out, args[0]);
|
sup[extra].fmt_string(out, args[extra]);
|
||||||
return out.size() - start;
|
return out.size() - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns type size (0 if unknown, pointer, assumed max)
|
||||||
|
std::size_t type(std::size_t extra) const
|
||||||
|
{
|
||||||
|
// Hack: use known function pointers to determine type
|
||||||
|
#define TYPE(type)\
|
||||||
|
if (sup[extra].fmt_string == &fmt_class_string<type>::format) return sizeof(type);
|
||||||
|
|
||||||
|
TYPE(char);
|
||||||
|
TYPE(schar);
|
||||||
|
TYPE(uchar);
|
||||||
|
TYPE(short);
|
||||||
|
TYPE(ushort);
|
||||||
|
TYPE(int);
|
||||||
|
TYPE(uint);
|
||||||
|
TYPE(long);
|
||||||
|
TYPE(ulong);
|
||||||
|
TYPE(llong);
|
||||||
|
TYPE(ullong);
|
||||||
|
|
||||||
|
#undef TYPE
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void fmt::raw_append(std::string& out, const char* fmt, const fmt::supplementary_info* sup, const u64* args) noexcept
|
void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
|
||||||
{
|
{
|
||||||
cfmt_append(out, fmt, cfmt_src{sup, args});
|
cfmt_append(out, fmt, cfmt_src{sup, args});
|
||||||
}
|
}
|
||||||
|
|
||||||
char* fmt::alloc_format(const char* fmt, const fmt::supplementary_info* sup, const u64* args) noexcept
|
char* fmt::alloc_format(const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
raw_append(str, fmt, sup, args);
|
raw_append(str, fmt, sup, args);
|
||||||
|
@ -155,48 +155,49 @@ struct fmt_class_string<char*, void> : fmt_class_string<const char*>
|
|||||||
// Classify char* as const char*
|
// Classify char* as const char*
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fmt_type_info
|
||||||
|
{
|
||||||
|
decltype(&fmt_class_string<int>::format) fmt_string;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr fmt_type_info make()
|
||||||
|
{
|
||||||
|
return fmt_type_info
|
||||||
|
{
|
||||||
|
&fmt_class_string<T>::format,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static inline const fmt_type_info* get()
|
||||||
|
{
|
||||||
|
// Constantly initialized null-terminated list of type-specific information
|
||||||
|
static constexpr fmt_type_info result[sizeof...(Args) + 1]
|
||||||
|
{
|
||||||
|
make<Args>()...
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Arg>
|
||||||
|
using fmt_unveil_t = typename fmt_unveil<Arg>::type;
|
||||||
|
|
||||||
|
// Argument array type (each element generated via fmt_unveil<>)
|
||||||
|
template<typename... Args>
|
||||||
|
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
|
||||||
|
|
||||||
namespace fmt
|
namespace fmt
|
||||||
{
|
{
|
||||||
// Argument array type (each element generated via fmt_unveil<>)
|
|
||||||
template<typename... Args>
|
|
||||||
using args_t = const u64(&&)[sizeof...(Args) + 1];
|
|
||||||
|
|
||||||
using supplementary_info = const struct arg_type_info;
|
|
||||||
|
|
||||||
struct arg_type_info
|
|
||||||
{
|
|
||||||
decltype(&fmt_class_string<int>::format) fmt_string;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static constexpr arg_type_info make()
|
|
||||||
{
|
|
||||||
return arg_type_info
|
|
||||||
{
|
|
||||||
&fmt_class_string<T>::format,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
static inline const supplementary_info* get()
|
|
||||||
{
|
|
||||||
// Constantly initialized null-terminated list of type-specific information
|
|
||||||
static constexpr arg_type_info result[sizeof...(Args) + 1]
|
|
||||||
{
|
|
||||||
make<Args>()...
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Internal formatting function
|
// Internal formatting function
|
||||||
void raw_append(std::string& out, const char*, const supplementary_info*, const u64*) noexcept;
|
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
||||||
|
|
||||||
// Formatting function
|
// Formatting function
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static SAFE_BUFFERS void append(std::string& out, const char* fmt, const Args&... args)
|
static SAFE_BUFFERS void append(std::string& out, const char* fmt, const Args&... args)
|
||||||
{
|
{
|
||||||
raw_append(out, fmt, arg_type_info::get<typename fmt_unveil<Args>::type...>(), args_t<Args...>{::fmt_unveil<Args>::get(args)...});
|
raw_append(out, fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatting function
|
// Formatting function
|
||||||
@ -209,7 +210,7 @@ namespace fmt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal helper function
|
// Internal helper function
|
||||||
char* alloc_format(const char*, const supplementary_info*, const u64*) noexcept;
|
char* alloc_format(const char*, const fmt_type_info*, const u64*) noexcept;
|
||||||
|
|
||||||
// Exception type with formatting constructor
|
// Exception type with formatting constructor
|
||||||
template<typename Base>
|
template<typename Base>
|
||||||
@ -220,7 +221,7 @@ namespace fmt
|
|||||||
public:
|
public:
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
SAFE_BUFFERS exception_t(const char* fmt, const Args&... args)
|
SAFE_BUFFERS exception_t(const char* fmt, const Args&... args)
|
||||||
: base((fmt = alloc_format(fmt, arg_type_info::get<typename fmt_unveil<Args>::type...>(), args_t<Args...>{::fmt_unveil<Args>::get(args)...})))
|
: base((fmt = alloc_format(fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...})))
|
||||||
{
|
{
|
||||||
std::free(const_cast<char*>(fmt));
|
std::free(const_cast<char*>(fmt));
|
||||||
}
|
}
|
||||||
|
329
Utilities/cfmt.h
329
Utilities/cfmt.h
@ -3,17 +3,18 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
C-style format parser. Appends formatted string to `out`, returns number of characters written.
|
C-style format parser. Appends formatted string to `out`, returns number of characters written.
|
||||||
Arguments are provided via `src`. TODO
|
`out`: mutable reference to std::string, std::vector<char> or other compatible container
|
||||||
|
`fmt`: null-terminated string of `Char` type (char or constructible from char)
|
||||||
|
`src`: rvalue reference to argument provider.
|
||||||
*/
|
*/
|
||||||
template<typename Src, typename Size = std::size_t>
|
template<typename Dst, typename Char, typename Src>
|
||||||
Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||||
{
|
{
|
||||||
const std::size_t old_size = out.size();
|
const std::size_t start_pos = out.size();
|
||||||
|
|
||||||
out.reserve(old_size + 992);
|
|
||||||
|
|
||||||
struct cfmt_context
|
struct cfmt_context
|
||||||
{
|
{
|
||||||
@ -37,14 +38,13 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
// Error handling: print untouched sequence, stop further formatting
|
// Error handling: print untouched sequence, stop further formatting
|
||||||
const auto drop_sequence = [&]
|
const auto drop_sequence = [&]
|
||||||
{
|
{
|
||||||
out.append(fmt - ctx.size, ctx.size);
|
out.insert(out.end(), fmt - ctx.size, fmt);
|
||||||
ctx.size = -1;
|
ctx.size = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: check overflow
|
|
||||||
const auto read_decimal = [&](uint result) -> uint
|
const auto read_decimal = [&](uint result) -> uint
|
||||||
{
|
{
|
||||||
while (fmt[0] >= '0' && fmt[0] <= '9')
|
while (fmt[0] >= '0' && fmt[0] <= '9' && result <= (UINT_MAX / 10))
|
||||||
{
|
{
|
||||||
result = result * 10 + (fmt[0] - '0');
|
result = result * 10 + (fmt[0] - '0');
|
||||||
fmt++, ctx.size++;
|
fmt++, ctx.size++;
|
||||||
@ -53,24 +53,48 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remove this
|
const auto write_octal = [&](u64 value, u64 min_num)
|
||||||
const auto fallback = [&]()
|
|
||||||
{
|
{
|
||||||
const std::string _fmt(fmt - ctx.size, fmt);
|
out.resize(out.size() + std::max<u64>(min_num, 66 / 3 - (cntlz64(value | 1) + 2) / 3), '0');
|
||||||
|
|
||||||
const u64 arg0 = src.template get<u64>();
|
// Write in reversed order
|
||||||
const int arg1 = ctx.args >= 1 ? src.template get<int>(1) : 0;
|
for (auto i = out.rbegin(); value; i++, value /= 8)
|
||||||
const int arg2 = ctx.args >= 2 ? src.template get<int>(2) : 0;
|
|
||||||
|
|
||||||
if (const std::size_t _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
|
|
||||||
{
|
{
|
||||||
out.resize(out.size() + _size);
|
*i = value % 8 + '0';
|
||||||
std::snprintf(&out.front() + out.size() - _size, _size + 1, _fmt.c_str(), arg0, arg1, arg2);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto write_hex = [&](u64 value, bool upper, u64 min_num)
|
||||||
|
{
|
||||||
|
out.resize(out.size() + std::max<u64>(min_num, 64 / 4 - cntlz64(value | 1) / 4), '0');
|
||||||
|
|
||||||
|
// Write in reversed order
|
||||||
|
for (auto i = out.rbegin(); value; i++, value /= 16)
|
||||||
|
{
|
||||||
|
*i = (upper ? "0123456789ABCDEF" : "0123456789abcdef")[value % 16];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto write_decimal = [&](u64 value, s64 min_size)
|
||||||
|
{
|
||||||
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
out.push_back(value % 10 + '0');
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
while (0 < --min_size || value);
|
||||||
|
|
||||||
|
// Revert written characters
|
||||||
|
for (std::size_t i = start, j = out.size() - 1; i < j; i++, j--)
|
||||||
|
{
|
||||||
|
std::swap(out[i], out[j]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single pass over fmt string (null-terminated), TODO: check correct order
|
// Single pass over fmt string (null-terminated), TODO: check correct order
|
||||||
while (const char ch = *fmt++) if (ctx.size == 0)
|
while (const Char ch = *fmt++) if (ctx.size == 0)
|
||||||
{
|
{
|
||||||
if (ch == '%')
|
if (ch == '%')
|
||||||
{
|
{
|
||||||
@ -78,17 +102,17 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out += ch;
|
out.push_back(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ctx.size == 1 && ch == '%')
|
else if (ctx.size == 1 && ch == '%')
|
||||||
{
|
{
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
out += ch;
|
out.push_back(ch);
|
||||||
}
|
}
|
||||||
else if (ctx.size == -1)
|
else if (ctx.size == -1)
|
||||||
{
|
{
|
||||||
out += ch;
|
out.push_back(ch);
|
||||||
}
|
}
|
||||||
else switch (ctx.size++, ch)
|
else switch (ctx.size++, ch)
|
||||||
{
|
{
|
||||||
@ -108,43 +132,58 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
{
|
{
|
||||||
ctx.width = read_decimal(ch - '0');
|
if (UNLIKELY(ctx.width))
|
||||||
|
{
|
||||||
|
drop_sequence();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.width = read_decimal(ch - '0');
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
{
|
{
|
||||||
if (!src.test(++ctx.args))
|
if (UNLIKELY(ctx.width || !src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
const int warg = src.template get<int>(ctx.args);
|
{
|
||||||
ctx.width = std::abs(warg);
|
const int warg = src.template get<int>(ctx.args++);
|
||||||
ctx.left |= warg < 0;
|
ctx.width = std::abs(warg);
|
||||||
|
ctx.left |= warg < 0;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
{
|
{
|
||||||
if (*fmt >= '0' && *fmt <= '9') // TODO: does it allow '0'?
|
if (UNLIKELY(ctx.dot || ctx.prec))
|
||||||
|
{
|
||||||
|
drop_sequence();
|
||||||
|
}
|
||||||
|
else if (*fmt >= '0' && *fmt <= '9') // TODO: does it allow '0'?
|
||||||
{
|
{
|
||||||
ctx.prec = read_decimal(0);
|
ctx.prec = read_decimal(0);
|
||||||
ctx.dot = true;
|
ctx.dot = true;
|
||||||
}
|
}
|
||||||
else if (*fmt == '*')
|
else if (*fmt == '*')
|
||||||
{
|
{
|
||||||
if (!src.test(++ctx.args))
|
if (UNLIKELY(!src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
fmt++, ctx.size++;
|
{
|
||||||
const int parg = src.template get<int>(ctx.args);
|
fmt++, ctx.size++;
|
||||||
ctx.prec = parg;
|
const int parg = src.template get<int>(ctx.args++);
|
||||||
ctx.dot = parg >= 0;
|
ctx.prec = std::max(parg, 0);
|
||||||
|
ctx.dot = parg >= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -157,7 +196,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
{
|
{
|
||||||
if (ctx.type)
|
if (UNLIKELY(ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
}
|
}
|
||||||
@ -176,7 +215,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
{
|
||||||
if (ctx.type)
|
if (UNLIKELY(ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
}
|
}
|
||||||
@ -195,7 +234,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'z':
|
case 'z':
|
||||||
{
|
{
|
||||||
if (ctx.type)
|
if (UNLIKELY(ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
}
|
}
|
||||||
@ -209,7 +248,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'j':
|
case 'j':
|
||||||
{
|
{
|
||||||
if (ctx.type)
|
if (UNLIKELY(ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
}
|
}
|
||||||
@ -223,7 +262,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
{
|
{
|
||||||
if (ctx.type)
|
if (UNLIKELY(ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
}
|
}
|
||||||
@ -237,19 +276,19 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
{
|
{
|
||||||
if (ctx.type || !src.test())
|
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t start = out.size();
|
const std::size_t start = out.size();
|
||||||
out += src.template get<char>(0);
|
out.push_back(src.template get<Char>(ctx.args));
|
||||||
|
|
||||||
if (1 < ctx.width)
|
if (1 < ctx.width)
|
||||||
{
|
{
|
||||||
// Add spaces if necessary
|
// Add spaces if necessary
|
||||||
out.insert(start + ctx.left, ctx.width - 1, ' ');
|
out.insert(out.begin() + start + ctx.left, ctx.width - 1, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
@ -259,14 +298,14 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
{
|
{
|
||||||
if (ctx.type || !src.test())
|
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t start = out.size();
|
const std::size_t start = out.size();
|
||||||
const std::size_t size1 = src.fmt_string(out);
|
const std::size_t size1 = src.fmt_string(out, ctx.args);
|
||||||
|
|
||||||
if (ctx.dot && size1 > ctx.prec)
|
if (ctx.dot && size1 > ctx.prec)
|
||||||
{
|
{
|
||||||
@ -274,13 +313,12 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
out.resize(start + ctx.prec);
|
out.resize(start + ctx.prec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: how it works if precision and width specified simultaneously?
|
|
||||||
const std::size_t size2 = out.size() - start;
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
if (size2 < ctx.width)
|
if (size2 < ctx.width)
|
||||||
{
|
{
|
||||||
// Add spaces if necessary
|
// Add spaces if necessary
|
||||||
out.insert(ctx.left ? out.size() : start, ctx.width - size2, ' ');
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
@ -291,7 +329,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
@ -299,10 +337,48 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
if (!ctx.type)
|
if (!ctx.type)
|
||||||
{
|
{
|
||||||
ctx.type = sizeof(int);
|
ctx.type = (u8)src.type(ctx.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign-extended argument expected: no special conversion
|
||||||
|
const u64 val = src.template get<u64>(ctx.args);
|
||||||
|
const s64 sval = val;
|
||||||
|
|
||||||
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
if (!ctx.dot || ctx.prec)
|
||||||
|
{
|
||||||
|
if (sval < 0)
|
||||||
|
{
|
||||||
|
out.push_back('-');
|
||||||
|
}
|
||||||
|
else if (ctx.sign)
|
||||||
|
{
|
||||||
|
out.push_back('+');
|
||||||
|
}
|
||||||
|
else if (ctx.space)
|
||||||
|
{
|
||||||
|
out.push_back(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
write_decimal(sval < 0 ? 0 - val : val, ctx.prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
|
if (size2 < ctx.width)
|
||||||
|
{
|
||||||
|
// Add padding if necessary
|
||||||
|
if (ctx.zeros && !ctx.left && !ctx.dot)
|
||||||
|
{
|
||||||
|
out.insert(out.begin() + start + (sval < 0 || ctx.sign || ctx.space), ctx.width - size2, '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback(); // TODO
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -310,7 +386,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
@ -318,10 +394,40 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
if (!ctx.type)
|
if (!ctx.type)
|
||||||
{
|
{
|
||||||
ctx.type = sizeof(int);
|
ctx.type = (u8)src.type(ctx.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 mask =
|
||||||
|
ctx.type == 1 ? 0xffull :
|
||||||
|
ctx.type == 2 ? 0xffffull :
|
||||||
|
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||||
|
|
||||||
|
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||||
|
|
||||||
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
if (ctx.alter)
|
||||||
|
{
|
||||||
|
out.push_back('0');
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
write_octal(val, ctx.prec ? ctx.prec - 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!ctx.dot || ctx.prec)
|
||||||
|
{
|
||||||
|
write_octal(val, ctx.prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
|
if (size2 < ctx.width)
|
||||||
|
{
|
||||||
|
// Add padding if necessary
|
||||||
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ctx.zeros && !ctx.left && !ctx.dot ? '0' : ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback(); // TODO
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -330,7 +436,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
@ -338,10 +444,48 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
if (!ctx.type)
|
if (!ctx.type)
|
||||||
{
|
{
|
||||||
ctx.type = sizeof(int);
|
ctx.type = (u8)src.type(ctx.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 mask =
|
||||||
|
ctx.type == 1 ? 0xffull :
|
||||||
|
ctx.type == 2 ? 0xffffull :
|
||||||
|
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||||
|
|
||||||
|
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||||
|
|
||||||
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
if (ctx.alter)
|
||||||
|
{
|
||||||
|
out.push_back('0');
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
out.push_back(ch); // Prepend 0x or 0X
|
||||||
|
write_hex(val, ch == 'X', ctx.prec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!ctx.dot || ctx.prec)
|
||||||
|
{
|
||||||
|
write_hex(val, ch == 'X', ctx.prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
|
if (size2 < ctx.width)
|
||||||
|
{
|
||||||
|
// Add padding if necessary
|
||||||
|
if (ctx.zeros && !ctx.left && !ctx.dot)
|
||||||
|
{
|
||||||
|
out.insert(out.begin() + start + (ctx.alter && val ? 2 : 0), ctx.width - size2, '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback(); // TODO
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -349,7 +493,7 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args)))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
@ -357,10 +501,31 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
if (!ctx.type)
|
if (!ctx.type)
|
||||||
{
|
{
|
||||||
ctx.type = sizeof(int);
|
ctx.type = (u8)src.type(ctx.args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 mask =
|
||||||
|
ctx.type == 1 ? 0xffull :
|
||||||
|
ctx.type == 2 ? 0xffffull :
|
||||||
|
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||||
|
|
||||||
|
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||||
|
|
||||||
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
if (!ctx.dot || ctx.prec)
|
||||||
|
{
|
||||||
|
write_decimal(val, ctx.prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
|
if (size2 < ctx.width)
|
||||||
|
{
|
||||||
|
// Add padding if necessary
|
||||||
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ctx.zeros && !ctx.left && !ctx.dot ? '0' : ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback(); // TODO
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -368,19 +533,26 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.type)
|
const u64 val = src.template get<u64>(ctx.args);
|
||||||
{
|
|
||||||
drop_sequence();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fallback(); // TODO
|
const std::size_t start = out.size();
|
||||||
|
|
||||||
|
write_hex(val, false, sizeof(void*) * 2);
|
||||||
|
|
||||||
|
const std::size_t size2 = out.size() - start;
|
||||||
|
|
||||||
|
if (size2 < ctx.width)
|
||||||
|
{
|
||||||
|
// Add padding if necessary
|
||||||
|
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -395,19 +567,26 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
{
|
{
|
||||||
if (!src.test())
|
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
drop_sequence();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.type)
|
// Fallback (TODO)
|
||||||
|
|
||||||
|
const std::string _fmt(fmt - ctx.size, fmt);
|
||||||
|
|
||||||
|
const u64 arg0 = src.template get<u64>(0);
|
||||||
|
const u64 arg1 = ctx.args >= 1 ? src.template get<u64>(1) : 0;
|
||||||
|
const u64 arg2 = ctx.args >= 2 ? src.template get<u64>(2) : 0;
|
||||||
|
|
||||||
|
if (const std::size_t _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
|
||||||
{
|
{
|
||||||
drop_sequence();
|
out.resize(out.size() + _size);
|
||||||
break;
|
std::snprintf(&out.front() + out.size() - _size, _size + 1, _fmt.c_str(), arg0, arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback(); // TODO
|
|
||||||
src.skip(ctx.args);
|
src.skip(ctx.args);
|
||||||
ctx = {0};
|
ctx = {0};
|
||||||
break;
|
break;
|
||||||
@ -427,5 +606,5 @@ Size cfmt_append(std::string& out, const char* fmt, Src&& src)
|
|||||||
fmt--, drop_sequence();
|
fmt--, drop_sequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<Size>(out.size() - old_size);
|
return out.size() - start_pos;
|
||||||
}
|
}
|
||||||
|
@ -46,16 +46,18 @@ struct gui_listener : logs::listener
|
|||||||
delete read;
|
delete read;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(const logs::message& msg)
|
void log(const logs::message& msg, const std::string& prefix, const std::string& text)
|
||||||
{
|
{
|
||||||
if (msg.sev <= enabled)
|
if (msg.sev <= enabled)
|
||||||
{
|
{
|
||||||
const auto _new = new packet;
|
const auto _new = new packet;
|
||||||
_new->sev = msg.sev;
|
_new->sev = msg.sev;
|
||||||
|
|
||||||
if (msg.prefix_size > 0)
|
if (prefix.size() > 0)
|
||||||
{
|
{
|
||||||
_new->msg = fmt::format("{%s} ", msg.prefix);
|
_new->msg += "{";
|
||||||
|
_new->msg += prefix;
|
||||||
|
_new->msg += "} ";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.ch->name)
|
if (msg.ch->name)
|
||||||
@ -68,7 +70,7 @@ struct gui_listener : logs::listener
|
|||||||
_new->msg += "TODO: ";
|
_new->msg += "TODO: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
_new->msg += msg.text;
|
_new->msg += text;
|
||||||
_new->msg += '\n';
|
_new->msg += '\n';
|
||||||
|
|
||||||
last = last->next = _new;
|
last = last->next = _new;
|
||||||
|
Loading…
Reference in New Issue
Block a user