diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-20 23:47:02 +0100 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-02-20 23:47:02 +0100 |
commit | aa73023bee1aebc745188e54039d3bf567be97e3 (patch) | |
tree | e4d3385a7e9eedfff7b36a8237771441668ca7cc /asl | |
parent | 409ef997e2ff99b2bbea89ea61d10fc8e26dac96 (diff) |
Use intrusive list in logging, and add defer
Diffstat (limited to 'asl')
-rw-r--r-- | asl/base/BUILD.bazel | 2 | ||||
-rw-r--r-- | asl/base/defer.hpp | 50 | ||||
-rw-r--r-- | asl/base/defer_tests.cpp | 32 | ||||
-rw-r--r-- | asl/base/utility.hpp | 3 | ||||
-rw-r--r-- | asl/containers/intrusive_list.hpp | 7 | ||||
-rw-r--r-- | asl/containers/intrusive_list_tests.cpp | 60 | ||||
-rw-r--r-- | asl/logging/BUILD.bazel | 2 | ||||
-rw-r--r-- | asl/logging/logging.cpp | 32 | ||||
-rw-r--r-- | asl/logging/logging.hpp | 23 | ||||
-rw-r--r-- | asl/logging/logging_tests.cpp | 17 |
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"); } |