summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-04 00:37:08 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-04 00:37:08 +0100
commit3d5a45b283d2a59211f9e24f100b95169375213d (patch)
tree2180c31100324076f7ff862009190564c0296b58 /asl
parentf2b1af8d3f23ff47b343cef8feef6e25ff5377e4 (diff)
Add deref utilities & use them for log writer
Diffstat (limited to 'asl')
-rw-r--r--asl/log/log.cpp6
-rw-r--r--asl/log/log.hpp20
-rw-r--r--asl/log/log_tests.cpp13
-rw-r--r--asl/meta.hpp27
-rw-r--r--asl/tests/meta_tests.cpp40
5 files changed, 97 insertions, 9 deletions
diff --git a/asl/log/log.cpp b/asl/log/log.cpp
index cd5d287..af31a84 100644
--- a/asl/log/log.cpp
+++ b/asl/log/log.cpp
@@ -4,7 +4,7 @@
// @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 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);
}
-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
msg.location.file,
msg.location.line,
diff --git a/asl/log/log.hpp b/asl/log/log.hpp
index f2e3a47..7445cf6 100644
--- a/asl/log/log.hpp
+++ b/asl/log/log.hpp
@@ -39,16 +39,24 @@ public:
constexpr Logger* next_logger() const { return m_next; }
};
-// @Todo Make a deref_as trait & deref utility
-// @Todo Accept writer as box, pointer, reference, or value
-class DefaultLogger : public Logger
+class DefaultLoggerBase : 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:
- 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>);
diff --git a/asl/log/log_tests.cpp b/asl/log/log_tests.cpp
index 01e8fd7..4ab83e8 100644
--- a/asl/log/log_tests.cpp
+++ b/asl/log/log_tests.cpp
@@ -1,5 +1,6 @@
#include <asl/log/log.hpp>
#include <asl/testing/testing.hpp>
+#include <asl/string_builder.hpp>
ASL_TEST(log)
{
@@ -8,3 +9,15 @@ ASL_TEST(log)
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");
+}
+
diff --git a/asl/meta.hpp b/asl/meta.hpp
index 9909be6..a464e36 100644
--- a/asl/meta.hpp
+++ b/asl/meta.hpp
@@ -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> 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<T*> : true_type {};
@@ -218,4 +220,29 @@ concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T
template<typename 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
diff --git a/asl/tests/meta_tests.cpp b/asl/tests/meta_tests.cpp
index f01258a..5026327 100644
--- a/asl/tests/meta_tests.cpp
+++ b/asl/tests/meta_tests.cpp
@@ -1,5 +1,7 @@
#include "asl/meta.hpp"
#include "asl/tests/test_types.hpp"
+#include "asl/testing/testing.hpp"
+#include "asl/box.hpp"
struct Struct {};
union Union {};
@@ -247,3 +249,41 @@ static_assert(!asl::is_enum<int>);
static_assert(asl::is_enum<Enum1>);
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));
+}
+