Add deref utilities & use them for log writer

This commit is contained in:
2025-02-04 00:37:08 +01:00
parent f2b1af8d3f
commit 3d5a45b283
5 changed files with 97 additions and 9 deletions

View File

@ -4,7 +4,7 @@
// @Todo Don't use internal get_stdout_writer, make console module // @Todo Don't use internal get_stdout_writer, make console module
static asl::log::DefaultLogger g_default_logger{asl::print_internals::get_stdout_writer()}; static asl::log::DefaultLogger<asl::Writer*> g_default_logger{asl::print_internals::get_stdout_writer()};
static asl::log::Logger* g_head = &g_default_logger; static asl::log::Logger* g_head = &g_default_logger;
static constexpr asl::string_view kLevelName[] = { static constexpr asl::string_view kLevelName[] = {
@ -20,9 +20,9 @@ void asl::log::register_logger(box<Logger> logger_box)
logger->m_next = exchange(g_head, logger); logger->m_next = exchange(g_head, logger);
} }
void asl::log::DefaultLogger::log(const message& msg) void asl::log::DefaultLoggerBase::log_inner(Writer& writer, const message& msg)
{ {
asl::format(m_writer, "[{}] {}:{}: {}\n", asl::format(&writer, "[{}] {}:{}: {}\n",
kLevelName[msg.level], // NOLINT kLevelName[msg.level], // NOLINT
msg.location.file, msg.location.file,
msg.location.line, msg.location.line,

View File

@ -39,16 +39,24 @@ public:
constexpr Logger* next_logger() const { return m_next; } constexpr Logger* next_logger() const { return m_next; }
}; };
// @Todo Make a deref_as trait & deref utility class DefaultLoggerBase : public Logger
// @Todo Accept writer as box, pointer, reference, or value
class DefaultLogger : public Logger
{ {
Writer* m_writer; protected:
static void log_inner(Writer&, const message&);
};
template<derefs_as<Writer> W>
class DefaultLogger : public DefaultLoggerBase
{
W m_writer;
public: public:
explicit constexpr DefaultLogger(Writer* writer) : m_writer{writer} {} explicit constexpr DefaultLogger(W&& writer) : m_writer{ASL_FWD(writer)} {}
void log(const message&) override; constexpr void log(const message& m) override
{
log_inner(deref<Writer>(m_writer), m);
}
}; };
void register_logger(box<Logger>); void register_logger(box<Logger>);

View File

@ -1,5 +1,6 @@
#include <asl/log/log.hpp> #include <asl/log/log.hpp>
#include <asl/testing/testing.hpp> #include <asl/testing/testing.hpp>
#include <asl/string_builder.hpp>
ASL_TEST(log) ASL_TEST(log)
{ {
@ -8,3 +9,15 @@ ASL_TEST(log)
ASL_LOG_ERROR("Oh no! {}", 42); ASL_LOG_ERROR("Oh no! {}", 42);
} }
static asl::StringWriter g_string_writer{};
ASL_TEST(custom_writer)
{
asl::log::register_logger<asl::log::DefaultLogger<asl::StringWriter<>&>>(g_string_writer);
ASL_LOG_INFO("Hello");
auto sv = g_string_writer.as_string_view();
ASL_TEST_EXPECT(sv == "[ INFO ] asl/log/log_tests.cpp:18: Hello\n");
}

View File

@ -117,6 +117,8 @@ template<typename T> struct _is_ref_helper<T&> { static constexpr bool l = true
template<typename T> struct _is_ref_helper<T&&> { static constexpr bool l = false; static constexpr bool r = true; }; template<typename T> struct _is_ref_helper<T&&> { static constexpr bool l = false; static constexpr bool r = true; };
template<typename T> concept is_ref = _is_ref_helper<T>::l || _is_ref_helper<T>::r; template<typename T> concept is_ref = _is_ref_helper<T>::l || _is_ref_helper<T>::r;
template<typename T> concept is_rref = _is_ref_helper<T>::r;
template<typename T> concept is_lref = _is_ref_helper<T>::l;
template<typename T> struct _is_ptr_helper : false_type {}; template<typename T> struct _is_ptr_helper : false_type {};
template<typename T> struct _is_ptr_helper<T*> : true_type {}; template<typename T> struct _is_ptr_helper<T*> : true_type {};
@ -218,4 +220,29 @@ concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T
template<typename T> template<typename T>
concept is_niche = same_as<un_cvref_t<T>, niche_t>; concept is_niche = same_as<un_cvref_t<T>, niche_t>;
template<typename T, typename U>
concept _derefs_with_indirection_as = requires(T& t)
{
*t;
requires convertible_from<U&, decltype(*t)>;
};
template<typename T, typename U>
concept _derefs_reference_as = is_ref<T> && convertible_from<U&, T>;
template<typename T, typename U>
concept _derefs_value_as = !is_ref<T> && convertible_from<U&, T&>;
template<typename U, _derefs_with_indirection_as<U> T>
constexpr U& deref(T&& t) { return static_cast<U&>(*t); }
template<typename U, _derefs_reference_as<U> T>
constexpr U& deref(T&& t) { return static_cast<U&>(t); }
template<typename U, _derefs_value_as<U> T>
constexpr U& deref(T&& t) { return static_cast<U&>(t); }
template<typename T, typename U>
concept derefs_as = _derefs_with_indirection_as<T, U> || _derefs_reference_as<T, U> || _derefs_value_as<T, U>;
} // namespace asl } // namespace asl

View File

@ -1,5 +1,7 @@
#include "asl/meta.hpp" #include "asl/meta.hpp"
#include "asl/tests/test_types.hpp" #include "asl/tests/test_types.hpp"
#include "asl/testing/testing.hpp"
#include "asl/box.hpp"
struct Struct {}; struct Struct {};
union Union {}; union Union {};
@ -247,3 +249,41 @@ static_assert(!asl::is_enum<int>);
static_assert(asl::is_enum<Enum1>); static_assert(asl::is_enum<Enum1>);
static_assert(asl::is_enum<Enum2>); static_assert(asl::is_enum<Enum2>);
static_assert(asl::derefs_as<int, int>);
static_assert(asl::derefs_as<int*, int>);
static_assert(asl::derefs_as<int&, int>);
static_assert(asl::derefs_as<asl::box<int>, int>);
static_assert(asl::derefs_as<Derived, Base>);
static_assert(asl::derefs_as<Derived*, Base>);
static_assert(asl::derefs_as<Derived&, Base>);
static_assert(asl::derefs_as<asl::box<Derived>, Base>);
static void wants_int(int) {}
static void wants_base(Base&) {}
static void wants_base_ptr(Base*) {}
ASL_TEST(deref)
{
int a = 4;
auto b = asl::make_box<int>(5);
wants_int(asl::deref<int>(5));
wants_int(asl::deref<int>(a));
wants_int(asl::deref<int>(&a));
wants_int(asl::deref<int>(b));
Derived c{};
auto d = asl::make_box<Derived>();
wants_base(asl::deref<Base>(Derived{}));
wants_base(asl::deref<Base>(c));
wants_base(asl::deref<Base>(&c));
wants_base(asl::deref<Base>(d));
wants_base_ptr(&asl::deref<Base>(Derived{}));
wants_base_ptr(&asl::deref<Base>(c));
wants_base_ptr(&asl::deref<Base>(&c));
wants_base_ptr(&asl::deref<Base>(d));
}