From 50e37b8421ee43c03df831c68cf497e245a0d46c Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:25:12 -0600 Subject: [PATCH] Separating out into DataSink CRTP model. Removed SmartStreams --- CMakeLists.txt | 2 +- engine/NBCore/DataSink.hpp | 135 +++++++++++++++++++---------- engine/NBCore/Logger.hpp | 133 ++++++++-------------------- engine/NBCore/SmartStreams.hpp | 124 -------------------------- engine/NBCore/tests/testErrors.cpp | 17 ++-- 5 files changed, 130 insertions(+), 281 deletions(-) delete mode 100644 engine/NBCore/SmartStreams.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d7f442f..4b40723 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ endif() find_package(OpenGL) add_subdirectory(../glfw ../glfw/build) -include_directories(./dep ./include ../glfw/include ../glad/include) +include_directories(../glfw/include ../glad/include) set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) diff --git a/engine/NBCore/DataSink.hpp b/engine/NBCore/DataSink.hpp index f28f418..a15a521 100644 --- a/engine/NBCore/DataSink.hpp +++ b/engine/NBCore/DataSink.hpp @@ -2,74 +2,113 @@ #ifndef _NB_DATASINK #define _NB_DATASINK +#include + +#include "ThreadSafeQueue.hpp" + namespace nb { -template -class SinkBase { - using InputType = T; +template +class DataSink { public: - virtual bool in(const T&) = 0; + DataSink(const DataSink&) = delete; + DataSink(DataSink&&) = delete; + DataSink& operator=(const DataSink&) = delete; -protected: - SinkBase(); + virtual bool isRunning() const noexcept { + return _running; + } + virtual bool stop() noexcept = 0; + virtual bool run() = 0; + virtual bool in(const DataType&) = 0; +protected: + DataSink() = default; + + std::atomic _running; }; -/* template -class Sink : public SinkBase { +template +class BufferedDataProcessor : public DataSink { + using Base = DataSink; public: - Sink& operator=(const Sink&) = 0; - - template - virtual bool in(const U&) = 0; + using Base::Base; + bool in(const DataType& val) { this->push(val); return true;} protected: - Sink(); + virtual unsigned int count() const = 0; + virtual void push(const DataType&) = 0; + virtual DataType pop() = 0; + virtual void flush() = 0; + virtual void clear() = 0; + virtual bool process(const DataType& val) = 0; -}; */ - -template -class SourceBase { - using OutputType = T; -public: - SourceBase& operator=(const SourceBase&) = 0; - - virtual bool out(T*) = 0; - - -protected: - SourceBase(); - SinkBase* _sink; + using Base::_running; + BufferType _buffer; }; -template -class Pipe : public SinkBase, public SourceBase{ - using Input = SourceBase; - using Output = SinkBase; +template +class MultithreadedDataProcessor : public BufferedDataProcessor, ProcessorType> { + using Base = BufferedDataProcessor, ProcessorType>; public: - Pipe(Sink& sink) : Input::_sink{&sink} {} + ~MultithreadedDataProcessor() { this->stop(); } - bool in(const T&) = 0; + bool isRunning() const noexcept override { + return this->_running && _runningThread; + } + bool run() override { + if (!isRunning()) { + this->_running = true; + _runningThread = std::make_shared([&]{ + auto this_type = static_cast(this); + while(this_type->isRunning()) { + this_type->flush(); + } + }); + } + return isRunning(); + } + bool stop() noexcept override { + if (isRunning()) { + this->_running = false; + _runningThread->join(); + _runningThread = nullptr; + auto this_type = static_cast(this); + } + return !isRunning(); + } protected: - using Input::_sink; + using Base::Base; + + unsigned int count() const override { + return this->_buffer.size(); + } + virtual void push(const DataType& val) { + this->_buffer.push(val); + }; + virtual DataType pop() { + std::shared_ptr event; + this->_buffer.pop(event); + process(*event); + return *event; + } + virtual void flush() override { + auto this_type = static_cast(this); + while(this_type->count()) { + this_type->pop(); + } + } + virtual void clear() override { + this->_buffer.empty(); + } + + virtual bool process(const DataType&) = 0; + + std::shared_ptr _runningThread; }; - -/* template -class Source : SourceBase { -public: - Source& operator=(const Source&) = 0; - - template - virtual bool out(const U&) = 0; - -protected: - Source(); - -}; */ - } // namespace nb #endif // _NB_DATASINK \ No newline at end of file diff --git a/engine/NBCore/Logger.hpp b/engine/NBCore/Logger.hpp index f31562e..7319852 100644 --- a/engine/NBCore/Logger.hpp +++ b/engine/NBCore/Logger.hpp @@ -9,6 +9,7 @@ #include #include +#include "DataSink.hpp" #include "Processes.hpp" #include "ThreadSafeQueue.hpp" @@ -31,75 +32,30 @@ struct LogEvent{ typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; -template -class LoggerBase { +/* template +class LoggerBase; + +template +class LoggerBase +: public MultithreadedDataProcessor{ +protected: + typename Logger::StreamType _ostreams; +}; */ + +class DebugLogger : public MultithreadedDataProcessor{ public: - using Type = LoggerName; - using StreamType = ST; + DebugLogger(std::ostream& stream) : _ostream(&stream) {} - LoggerBase(StreamType& stream) : _ostreams({&stream}) {} - LoggerBase(const LoggerBase&) = delete; - LoggerBase(LoggerBase&&) = delete; + ~DebugLogger() { stop(); } - LoggerBase& operator=(const LoggerBase&) = delete; - - ~LoggerBase() { - stop(); + virtual bool stop() noexcept override { + auto ret = MultithreadedDataProcessor::stop(); + flush(); + return ret; } - bool isRunning() const noexcept { - return _running && bool(_runningThread); - } - - unsigned int count() const { - return _queue.size(); - } - - bool run() { - if (!isRunning()) { - _running = true; - _runningThread = std::make_shared([&]{ - auto this_type = static_cast(this); - while(this_type->isRunning()) { - this_type->flush(); - } - }); - } - return isRunning(); - } - - bool stop() noexcept { - if (isRunning()) { - _running = false; - _runningThread->join(); - _runningThread = nullptr; - flush(); - } - return isRunning(); - } - - LogEvent pop() { - std::shared_ptr event; - _queue.pop(event); - static_cast(this)->process(*event); - return *event; - } - - void flush() noexcept { - while(_queue.size()) { - pop(); - } - } - - void deleteAll() { - _queue.empty(); - } - - template - void log(const T&, const uint8_t); - - void log(const std::string& msg, const uint8_t& lvl) { - _queue.push(LogEvent{ + void log(const std::string& msg, const uint8_t& lvl=0xFF) { + push(LogEvent{ std::chrono::system_clock::now(), lvl, msg, @@ -109,48 +65,31 @@ public: } template - void log(char const(&msg) [N], const uint8_t& lvl) { - static_cast(this)->log(std::string(msg), lvl); + void log(char const(&msg) [N], const uint8_t& lvl=0xFF) { + log(std::string(msg), lvl); } - void log(const std::exception& err, const uint8_t& lvl) { - _queue.push(LogEvent{ - std::chrono::system_clock::now(), - lvl, - err.what(), - std::this_thread::get_id(), - GetPID(), - }); + void log(const std::exception& err, const uint8_t& lvl=0xFF) { + log(err.what(), lvl); } - void msg(const std::string& msg, const uint8_t& lvl=0x00) { - static_cast(this)->log(msg, lvl); - } + template + void warn(const U& val, const uint8_t& lvl=0x01) { log(val, lvl); } - void warn(const std::string& msg, const uint8_t& lvl=0x01) { - static_cast(this)->log(msg, lvl); - } - void warn(const std::exception& err, const uint8_t lvl=0x01) { - static_cast(this)->log(err, lvl); - } - - void error(const std::string& msg, const uint8_t lvl=0xFF) { - static_cast(this)->log(msg, lvl); - } - void error(const std::exception& err, const uint8_t lvl=0xFF) { - static_cast(this)->log(err, lvl); - } + template + void error(const U& val, const uint8_t& lvl=0xFF) { log(val, lvl); } protected: - void process(const LogEvent&); + std::ostream* const _ostream; - ThreadsafeQueue _queue; - std::vector const _ostreams; - std::atomic _running; - std::shared_ptr _runningThread = nullptr; + virtual bool process(const LogEvent& msg) override { + *_ostream << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n"; + return true; + } + }; -class BasicLogger : public LoggerBase { +/* class BasicLogger : public LoggerBase { public: using Base = LoggerBase; BasicLogger(std::ostream& stream) : Base(stream) {} @@ -158,7 +97,7 @@ public: virtual void process(const LogEvent& event) { *_ostreams[0] << event.msg << "\n"; } -}; +}; */ } // namespace nb #endif // _NB_LOGGER \ No newline at end of file diff --git a/engine/NBCore/SmartStreams.hpp b/engine/NBCore/SmartStreams.hpp deleted file mode 100644 index 2496a44..0000000 --- a/engine/NBCore/SmartStreams.hpp +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once -#ifndef _NB_SMARTSTREAM -#define _NB_SMARTSTREAM - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace nb { - -template -class SmartStream; - -template -struct MixinHasProcess { -protected: - template - static auto test(int)->decltype( - std::declval().template process(std::declval()), - std::true_type{} - ); - - template - static std::false_type test(...); - -public: - static const bool value = decltype(test(0))::value; -}; - -template -struct PackHasProcess; - -template -struct PackHasProcess { - static const bool value = MixinHasProcess::value; - using type = typename std::conditional< - value, - Mix, - void - >::type; -}; - -template -struct PackHasProcess { -protected: - static const bool base_value = MixinHasProcess::value; -public: - static const bool value = std::conditional< - base_value, - std::true_type, - typename PackHasProcess::value - >::type::value; - using type = typename std::conditional< - base_value, - Mix1, - typename PackHasProcess::type - >::type; -}; - -/* template -struct HasStreamType : std::false_type {}; - -template -struct HasStreamType : std::false_type {}; */ - -template -class SmartStream : public Mixins... { - using StreamType = typename std::conditional< - decltype(std::declval(), std::true_type{}), - ST::StreamType, - ST - >::type; -protected: - StreamType* const _stream; - -public: - SmartStream(StreamType& stream) : _stream(&stream), Mixins(&stream)... {} - - using Mixins::process...; - - template > - typename std::enable_if::value, void>::type - toStream(const U& val, const StreamFmt* fmtas=nullptr) { - PackHasProcess::type::template process(val); - } - - template > - typename std::enable_if::value, void>::type - toStream(const U& val, const StreamFmt* fmtas=nullptr) { - *_stream << val; - } - - template - friend SmartStream& operator<<(SmartStream& stream, const U& val) { - stream.toStream(val); - return stream; - } -}; - -struct SmartText { - int x; -}; - -template -struct ANSIFormatter { - template - void process(const SmartText& val, StreamType* fmtas = nullptr) { - static_cast(this)->toStream(val.x); - } - -protected: - ANSIFormatter(StreamType* stream) : _stream(stream) {} - - StreamType* const _stream; -}; - -} - -#endif // _NB_SMARTSTREAM \ No newline at end of file diff --git a/engine/NBCore/tests/testErrors.cpp b/engine/NBCore/tests/testErrors.cpp index 8b45b97..5999c86 100644 --- a/engine/NBCore/tests/testErrors.cpp +++ b/engine/NBCore/tests/testErrors.cpp @@ -26,20 +26,15 @@ const ErrorCodeMap TestError::ErrorMessages{ {TestError::ErrorCodes::D, "Doin"} }; -class TestLogger : public nb::LoggerBase { -public: - using Base = LoggerBase; - using Base::Base; - - virtual void process(const LogEvent& event) { - *_ostreams[0] << event.pid << " : " << event.msg << std::endl; - } -}; TEST(ErrorTest, Test) { EXPECT_EQ(1, 1); - TestLogger log(std::cout); + nb::DebugLogger log(std::cout); ASSERT_TRUE(log.run()); - log.msg("Hey!"); + ASSERT_TRUE(log.isRunning()); + while (!log.isRunning()){ + 1+1; + } + log.log("Hey!"); } \ No newline at end of file