summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-20 23:47:02 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2025-02-20 23:47:02 +0100
commitaa73023bee1aebc745188e54039d3bf567be97e3 (patch)
treee4d3385a7e9eedfff7b36a8237771441668ca7cc /asl
parent409ef997e2ff99b2bbea89ea61d10fc8e26dac96 (diff)
Use intrusive list in logging, and add defer
Diffstat (limited to 'asl')
-rw-r--r--asl/base/BUILD.bazel2
-rw-r--r--asl/base/defer.hpp50
-rw-r--r--asl/base/defer_tests.cpp32
-rw-r--r--asl/base/utility.hpp3
-rw-r--r--asl/containers/intrusive_list.hpp7
-rw-r--r--asl/containers/intrusive_list_tests.cpp60
-rw-r--r--asl/logging/BUILD.bazel2
-rw-r--r--asl/logging/logging.cpp32
-rw-r--r--asl/logging/logging.hpp23
-rw-r--r--asl/logging/logging_tests.cpp17
10 files changed, 164 insertions, 64 deletions
diff --git a/asl/base/BUILD.bazel b/asl/base/BUILD.bazel
index 317c20b..3dc715b 100644
--- a/asl/base/BUILD.bazel
+++ b/asl/base/BUILD.bazel
@@ -4,6 +4,7 @@ cc_library(
"annotations.hpp",
"assert.hpp",
"config.hpp",
+ "defer.hpp",
"float.hpp",
"functional.hpp",
"integers.hpp",
@@ -28,6 +29,7 @@ cc_library(
"//asl/types:box",
],
) for name in [
+ "defer",
"float",
"functional",
"integers",
diff --git a/asl/base/defer.hpp b/asl/base/defer.hpp
new file mode 100644
index 0000000..b6d52af
--- /dev/null
+++ b/asl/base/defer.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "asl/base/utility.hpp"
+#include "asl/base/functional.hpp"
+
+namespace asl
+{
+
+// @Todo Add invokable check
+template<typename Callback>
+class DeferCallback
+{
+ Callback m_callback;
+ bool m_moved = false;
+
+public:
+ template<typename T>
+ explicit DeferCallback(T&& callback) : m_callback(ASL_FWD(callback))
+ {
+ }
+
+ ASL_DELETE_COPY(DeferCallback);
+
+ DeferCallback(DeferCallback&& other) :
+ m_callback(ASL_MOVE(other.m_callback)), m_moved(exchange(other.m_moved, true))
+ {
+ }
+
+ DeferCallback& operator=(DeferCallback&&) = delete;
+
+ ~DeferCallback()
+ {
+ if (!m_moved) { invoke(m_callback); }
+ }
+};
+
+struct DeferFactory
+{
+ // @Todo Add invokable check
+ template<typename Callback>
+ DeferCallback<Callback> operator<<(Callback&& callback) const
+ {
+ return DeferCallback<Callback>(ASL_FWD(callback));
+ }
+};
+
+} // namespace asl
+
+#define ASL_DEFER auto ASL_CONCAT(_defer_, __COUNTER__) = ::asl::DeferFactory{} <<
+
diff --git a/asl/base/defer_tests.cpp b/asl/base/defer_tests.cpp
new file mode 100644
index 0000000..b5139d5
--- /dev/null
+++ b/asl/base/defer_tests.cpp
@@ -0,0 +1,32 @@
+#include "asl/base/defer.hpp"
+#include "asl/testing/testing.hpp"
+
+ASL_TEST(defer)
+{
+ uint32_t a = 0;
+
+ {
+ ASL_DEFER [&a]() { a |= 1; };
+ ASL_TEST_EXPECT(a == 0);
+
+ {
+ ASL_DEFER [&a]() { a |= 2; };
+ ASL_DEFER [&a]() { a |= 4; };
+ ASL_TEST_EXPECT(a == 0);
+ }
+
+ ASL_TEST_EXPECT(a == 6);
+
+ {
+ ASL_DEFER [&a]() { a |= 8; };
+ ASL_TEST_EXPECT(a == 6);
+ }
+
+ ASL_TEST_EXPECT(a == 14);
+
+ ASL_DEFER [&a]() { a |= 16; };
+ ASL_TEST_EXPECT(a == 14);
+ }
+
+ ASL_TEST_EXPECT(a == 31);
+}
diff --git a/asl/base/utility.hpp b/asl/base/utility.hpp
index c03554f..b3fb36b 100644
--- a/asl/base/utility.hpp
+++ b/asl/base/utility.hpp
@@ -92,4 +92,7 @@ constexpr bool is_pow2(isize_t v)
ASL_DEFAULT_COPY(T) \
ASL_DEFAULT_MOVE(T)
+#define ASL_CONCAT2(A, B) A##B
+#define ASL_CONCAT(A, B) ASL_CONCAT2(A, B)
+
} // namespace asl
diff --git a/asl/containers/intrusive_list.hpp b/asl/containers/intrusive_list.hpp
index f061740..dcf0508 100644
--- a/asl/containers/intrusive_list.hpp
+++ b/asl/containers/intrusive_list.hpp
@@ -34,6 +34,11 @@ class IntrusiveList
public:
constexpr IntrusiveList() = default;
+ explicit IntrusiveList(T* head)
+ {
+ push_front(head);
+ }
+
ASL_DELETE_COPY(IntrusiveList)
ASL_DEFAULT_MOVE(IntrusiveList)
~IntrusiveList() = default;
@@ -121,7 +126,7 @@ public:
{
if (!is_empty())
{
- T* node = m_head->prev;
+ T* node = m_head->m_prev;
detach(node);
return node;
}
diff --git a/asl/containers/intrusive_list_tests.cpp b/asl/containers/intrusive_list_tests.cpp
index 242aaf6..ceb54a6 100644
--- a/asl/containers/intrusive_list_tests.cpp
+++ b/asl/containers/intrusive_list_tests.cpp
@@ -194,33 +194,33 @@ ASL_TEST(pop_front)
ASL_TEST_ASSERT(list.is_empty());
}
-// ASL_TEST(pop_back)
-// {
-// IntNode one{1};
-// IntNode two{2};
-// IntNode three{3};
-// asl::IntrusiveList<IntNode> list;
-
-// list.push_back(&one);
-// list.push_back(&two);
-// list.push_back(&three);
-
-// IntNode* n = list.pop_back();
-// ASL_TEST_ASSERT(n != nullptr);
-// ASL_TEST_ASSERT(!list.is_empty());
-// ASL_TEST_EXPECT(n->value == 3);
-
-// n = list.pop_back();
-// ASL_TEST_ASSERT(n != nullptr);
-// ASL_TEST_ASSERT(!list.is_empty());
-// ASL_TEST_EXPECT(n->value == 2);
-
-// n = list.pop_back();
-// ASL_TEST_ASSERT(n != nullptr);
-// ASL_TEST_ASSERT(list.is_empty());
-// ASL_TEST_EXPECT(n->value == 1);
-
-// n = list.pop_back();
-// ASL_TEST_ASSERT(n == nullptr);
-// ASL_TEST_ASSERT(list.is_empty());
-// }
+ASL_TEST(pop_back)
+{
+ IntNode one{1};
+ IntNode two{2};
+ IntNode three{3};
+ asl::IntrusiveList<IntNode> list;
+
+ list.push_back(&one);
+ list.push_back(&two);
+ list.push_back(&three);
+
+ IntNode* n = list.pop_back();
+ ASL_TEST_ASSERT(n != nullptr);
+ ASL_TEST_ASSERT(!list.is_empty());
+ ASL_TEST_EXPECT(n->value == 3);
+
+ n = list.pop_back();
+ ASL_TEST_ASSERT(n != nullptr);
+ ASL_TEST_ASSERT(!list.is_empty());
+ ASL_TEST_EXPECT(n->value == 2);
+
+ n = list.pop_back();
+ ASL_TEST_ASSERT(n != nullptr);
+ ASL_TEST_ASSERT(list.is_empty());
+ ASL_TEST_EXPECT(n->value == 1);
+
+ n = list.pop_back();
+ ASL_TEST_ASSERT(n == nullptr);
+ ASL_TEST_ASSERT(list.is_empty());
+}
diff --git a/asl/logging/BUILD.bazel b/asl/logging/BUILD.bazel
index 3c60915..0c8323a 100644
--- a/asl/logging/BUILD.bazel
+++ b/asl/logging/BUILD.bazel
@@ -8,7 +8,7 @@ cc_library(
],
deps = [
"//asl/base",
- "//asl/types:box",
+ "//asl/containers:intrusive_list",
"//asl/formatting",
"//asl/io:print",
"//asl/strings:string_builder",
diff --git a/asl/logging/logging.cpp b/asl/logging/logging.cpp
index df7758d..a825dd3 100644
--- a/asl/logging/logging.cpp
+++ b/asl/logging/logging.cpp
@@ -5,7 +5,27 @@
// @Todo Don't use internal get_stdout_writer, make console module
static asl::log::DefaultLogger<asl::Writer*> g_default_logger{asl::print_internals::get_stdout_writer()};
-static asl::log::Logger* g_head = &g_default_logger;
+
+// @Todo Protect the loggers list being a mutex
+static asl::IntrusiveList<asl::log::Logger> g_loggers(&g_default_logger);
+
+void asl::log::register_logger(Logger* logger)
+{
+ g_loggers.push_front(logger);
+}
+
+void asl::log::unregister_logger(Logger* logger)
+{
+ g_loggers.detach(logger);
+}
+
+void asl::log::remove_default_logger()
+{
+ if (g_default_logger.m_next != nullptr)
+ {
+ g_loggers.detach(&g_default_logger);
+ }
+}
static constexpr asl::string_view kLevelName[] = {
" DEBUG ",
@@ -14,12 +34,6 @@ static constexpr asl::string_view kLevelName[] = {
" ERROR ",
};
-void asl::log::register_logger(box<Logger> logger_box)
-{
- auto* logger = leak(ASL_MOVE(logger_box));
- logger->m_next = exchange(g_head, logger);
-}
-
void asl::log::DefaultLoggerBase::log_inner(Writer& writer, const message& msg)
{
asl::format(&writer, "[{}] {}:{}: {}\n",
@@ -44,9 +58,9 @@ void asl::log::log_inner(
.location = sl,
};
- for (auto* it = g_head; it != nullptr; it = it->next_logger())
+ for (auto& logger: g_loggers)
{
- it->log(m);
+ logger.log(m);
}
}
diff --git a/asl/logging/logging.hpp b/asl/logging/logging.hpp
index c692750..6ad7cfc 100644
--- a/asl/logging/logging.hpp
+++ b/asl/logging/logging.hpp
@@ -1,8 +1,8 @@
#pragma once
#include "asl/base/utility.hpp"
-#include "asl/types/box.hpp"
#include "asl/formatting/format.hpp"
+#include "asl/containers/intrusive_list.hpp"
namespace asl::log
{
@@ -22,21 +22,14 @@ struct message
source_location location;
};
-// @Todo Write and use an intrusive doubly-linked list
-class Logger
+class Logger : public intrusive_list_node<Logger>
{
- Logger* m_next{};
-
public:
Logger() = default;
ASL_DEFAULT_COPY_MOVE(Logger);
virtual ~Logger() = default;
virtual void log(const message&) = 0;
-
- friend void register_logger(box<Logger>);
-
- constexpr Logger* next_logger() const { return m_next; }
};
class DefaultLoggerBase : public Logger
@@ -59,16 +52,12 @@ public:
}
};
-void register_logger(box<Logger>);
+void register_logger(Logger*);
+void unregister_logger(Logger*);
-// @Todo Add a way to remove loggers (including all)
+void remove_default_logger();
-template<typename T, typename... Args>
-requires constructible_from<T, Args&&...> && convertible_from<Logger*, T*>
-void register_logger(Args&&... args)
-{
- register_logger(make_box<T>(ASL_FWD(args)...));
-}
+// @Todo Add a way to remove loggers (including all)
void log_inner(level l, string_view fmt, span<const format_internals::type_erased_arg> args, const source_location& sl);
diff --git a/asl/logging/logging_tests.cpp b/asl/logging/logging_tests.cpp
index 39a800a..d531cda 100644
--- a/asl/logging/logging_tests.cpp
+++ b/asl/logging/logging_tests.cpp
@@ -1,6 +1,7 @@
#include "asl/logging/logging.hpp"
#include "asl/testing/testing.hpp"
#include "asl/strings/string_builder.hpp"
+#include "asl/base/defer.hpp"
ASL_TEST(log)
{
@@ -9,15 +10,19 @@ 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::StringWriter string_writer{};
+ asl::log::DefaultLogger<asl::StringWriter<>&> logger(string_writer);
+
+ asl::log::register_logger(&logger);
+ ASL_DEFER [&logger]() {
+ asl::log::unregister_logger(&logger);
+ };
+
ASL_LOG_INFO("Hello");
- auto sv = g_string_writer.as_string_view();
+ auto sv = string_writer.as_string_view();
- ASL_TEST_EXPECT(sv == "[ INFO ] asl/logging/logging_tests.cpp:18: Hello\n");
+ ASL_TEST_EXPECT(sv == "[ INFO ] asl/logging/logging_tests.cpp:23: Hello\n");
}