Refactored to do CRTP. Got multi val init working

This commit is contained in:
NaifBanana 2026-01-28 19:43:08 -06:00
parent 50e37b8421
commit 9be6036265
3 changed files with 161 additions and 61 deletions

View File

@ -33,80 +33,99 @@ class BufferedDataProcessor : public DataSink<DataType> {
using Base = DataSink<DataType>; using Base = DataSink<DataType>;
public: public:
using Base::Base; using Base::Base;
bool in(const DataType& val) { this->push(val); return true;}
bool stop() noexcept { return type_ptr->stop(); }
bool run() { return type_ptr->run(); }
bool in(const DataType& val) { return type_ptr->in(val); }
protected: protected:
virtual unsigned int count() const = 0; unsigned int count() const {
virtual void push(const DataType&) = 0; return type_ptr->count();
virtual DataType pop() = 0; }
virtual void flush() = 0; void push(const DataType& val) {
virtual void clear() = 0; type_ptr->push(val);
virtual bool process(const DataType& val) = 0; }
DataType pop() {
return type_ptr->pop();
}
void flush() {
type_ptr->flush();
}
void clear() {
type_ptr->clear();
}
bool process(const DataType& val) {
return type_ptr->process(val);
}
using Base::_running; using Base::_running;
BufferType _buffer; BufferType _buffer;
private:
ProcessorType* const type_ptr = static_cast<ProcessorType*>(this);
}; };
template<typename DataType, typename ProcessorType> template<typename DataType, typename ProcessorType>
class MultithreadedDataProcessor : public BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType> { class MultithreadedDataProcessor
: public BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType> {
using Base = BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType>; using Base = BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType>;
public: public:
~MultithreadedDataProcessor() { this->stop(); } ~MultithreadedDataProcessor() { type_ptr->stop(); }
bool isRunning() const noexcept override { bool isRunning() const noexcept override {
return this->_running && _runningThread; return this->_running && (_runningThread!=nullptr);
} }
bool run() override { bool run() {
if (!isRunning()) { if (!type_ptr->isRunning()) {
this->_running = true; this->_running = true;
_runningThread = std::make_shared<std::thread>([&]{ _runningThread = std::make_shared<std::thread>([&]{
auto this_type = static_cast<ProcessorType*>(this); while(type_ptr->isRunning()) {
while(this_type->isRunning()) { flush();
this_type->flush();
} }
}); });
} }
return isRunning(); return this->isRunning();
} }
bool stop() noexcept override { bool stop() noexcept override {
if (isRunning()) { if (type_ptr->isRunning()) {
this->_running = false; this->_running = false;
_runningThread->join(); _runningThread->join();
_runningThread = nullptr; _runningThread = nullptr;
auto this_type = static_cast<ProcessorType*>(this);
} }
return !isRunning(); return !type_ptr->isRunning();
} }
protected: protected:
using Base::Base; using Base::Base;
unsigned int count() const override { unsigned int count() const {
return this->_buffer.size(); return this->_buffer.size();
} }
virtual void push(const DataType& val) { void push(const DataType& val) {
this->_buffer.push(val); this->_buffer.push(val);
}; };
virtual DataType pop() { DataType pop() {
std::shared_ptr<DataType> event; std::shared_ptr<DataType> event;
this->_buffer.pop(event); this->_buffer.pop(event);
process(*event); this->process(*event);
return *event; return *event;
} }
virtual void flush() override { void flush() {
auto this_type = static_cast<ProcessorType*>(this); while(type_ptr->count()) {
while(this_type->count()) { pop();
this_type->pop();
} }
} }
virtual void clear() override { void clear() {
this->_buffer.empty(); this->_buffer.empty();
} }
virtual bool process(const DataType&) = 0;
std::shared_ptr<std::thread> _runningThread; std::shared_ptr<std::thread> _runningThread;
private:
ProcessorType* type_ptr = static_cast<ProcessorType*>(this);
}; };

View File

@ -6,6 +6,7 @@
#include <chrono> #include <chrono>
#include <ostream> #include <ostream>
#include <thread> #include <thread>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -32,30 +33,90 @@ struct LogEvent{
typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&);
typedef std::unordered_map<uint8_t, LogProcessFunction> LogProcessFunctionMap; typedef std::unordered_map<uint8_t, LogProcessFunction> LogProcessFunctionMap;
/* template<typename LogType, typename Logger, typename ST=std::ostream> template<typename LogType, typename Logger, typename ST=std::ostream*>
class LoggerBase; class LoggerBase
: public MultithreadedDataProcessor<LogType, Logger>{
template<typename Logger> using StreamType = ST;
class LoggerBase<typename Logger::LogType, Logger, typename Logger::StreamType> using LoggerType = Logger;
: public MultithreadedDataProcessor<typename Logger::LogType, Logger>{ using Base = MultithreadedDataProcessor<LogType, LoggerType>;
protected:
typename Logger::StreamType _ostreams;
}; */
class DebugLogger : public MultithreadedDataProcessor<LogEvent, DebugLogger>{
public: public:
DebugLogger(std::ostream& stream) : _ostream(&stream) {} bool run() {
if (!type_ptr->isRunning()) {
this->_running = true;
this->_runningThread = std::make_shared<std::thread>([&]{
while(type_ptr->isRunning()) {
type_ptr->flush();
}
type_ptr->flush();
});
}
return type_ptr->isRunning();
}
protected:
LoggerBase() = default;
~DebugLogger() { stop(); } StreamType _ostream;
virtual bool stop() noexcept override { private:
auto ret = MultithreadedDataProcessor<LogEvent, DebugLogger>::stop(); LoggerType* type_ptr = static_cast<LoggerType*>(this);
flush(); };
return ret;
template <typename T, typename... Pack>
struct PackIsType;
template <typename T, typename PackType>
struct PackIsType<T, PackType> {
const bool value = std::is_base_of<T, PackType>::value;
};
template <typename T, typename FirstPack, typename... Pack>
struct PackIsType<T, FirstPack, Pack...> {
const bool value = std::is_base_of<T, FirstPack>::value && PackIsType<T, Pack...>::value;
};
template <typename T, typename Pack1, typename... Pack>
struct StreamRefToPtrVec {
StreamRefToPtrVec(std::vector<T*> _vec, Pack1& p1, Pack&... packs)
: vec(_vec) {
static_assert(std::is_base_of<T, Pack1>::value);
vec.push_back(&p1);
vec = StreamRefToPtrVec<T, Pack...>(vec, packs...).vec;
} }
StreamRefToPtrVec(Pack1& p1, Pack&... packs)
: StreamRefToPtrVec({}, p1, packs...) {}
std::vector<T*> vec;
};
template <typename T, typename Pack>
struct StreamRefToPtrVec<T, Pack> {
StreamRefToPtrVec(std::vector<T*> _vec, Pack& p1)
: vec(_vec) {
static_assert(std::is_base_of<T, Pack>::value);
vec.push_back(&p1);
}
StreamRefToPtrVec(Pack& p1)
: StreamRefToPtrVec({}, p1) {}
std::vector<T*> vec;
};
template <typename LT>
class DebugLogger : public LoggerBase<LogEvent, LT, std::vector<std::ostream*>>{
using StreamType = std::vector<std::ostream*>;
using LoggerType = LT;
using Base = LoggerBase<LogEvent, LoggerType, StreamType>;
public:
template<typename... ST>
DebugLogger(ST&... streams) : _ostream(StreamRefToPtrVec<std::ostream, ST...>(streams...).vec) {}
~DebugLogger() { type_ptr->stop(); }
void log(const std::string& msg, const uint8_t& lvl=0xFF) { void log(const std::string& msg, const uint8_t& lvl=0xFF) {
push(LogEvent{ type_ptr->push(LogEvent{
std::chrono::system_clock::now(), std::chrono::system_clock::now(),
lvl, lvl,
msg, msg,
@ -66,27 +127,47 @@ public:
template <size_t N> template <size_t N>
void log(char const(&msg) [N], const uint8_t& lvl=0xFF) { void log(char const(&msg) [N], const uint8_t& lvl=0xFF) {
log(std::string(msg), lvl); type_ptr->log(std::string(msg), lvl);
} }
void log(const std::exception& err, const uint8_t& lvl=0xFF) { void log(const std::exception& err, const uint8_t& lvl=0xFF) {
log(err.what(), lvl); type_ptr->log(err.what(), lvl);
} }
template<typename U> template<typename U>
void warn(const U& val, const uint8_t& lvl=0x01) { log(val, lvl); } void warn(const U& val, const uint8_t& lvl=0x01) { type_ptr->log(val, lvl); }
template<typename U> template<typename U>
void error(const U& val, const uint8_t& lvl=0xFF) { log(val, lvl); } void error(const U& val) { type_ptr->log(val, 0xFF); }
protected: protected:
std::ostream* const _ostream; std::vector<std::ostream*> _ostream;
virtual bool process(const LogEvent& msg) override { private:
*_ostream << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n"; LoggerType* type_ptr = static_cast<LoggerType*>(this);
};
class DefaultDebugLogger : public DebugLogger<DefaultDebugLogger> {
using LoggerType = DefaultDebugLogger;
using Base = DebugLogger<DefaultDebugLogger>;
public:
using Base::Base;
~DefaultDebugLogger() { stop(); }
friend class BufferedDataProcessor<LogEvent, ThreadsafeQueue<LogEvent>, DefaultDebugLogger>;
protected:
using Base::_ostream;
bool process(const LogEvent& msg) {
for (const auto os : this->_ostream) {
(*os) << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n";
}
return true; return true;
} }
}; };
/* class BasicLogger : public LoggerBase<BasicLogger> { /* class BasicLogger : public LoggerBase<BasicLogger> {

View File

@ -30,11 +30,11 @@ const ErrorCodeMap TestError::ErrorMessages{
TEST(ErrorTest, Test) { TEST(ErrorTest, Test) {
EXPECT_EQ(1, 1); EXPECT_EQ(1, 1);
nb::DebugLogger log(std::cout); nb::DefaultDebugLogger logr(std::cout, std::cout, std::cout);
ASSERT_TRUE(log.run()); ASSERT_TRUE(logr.run());
ASSERT_TRUE(log.isRunning()); ASSERT_TRUE(logr.isRunning());
while (!log.isRunning()){ while (!logr.isRunning()){
1+1; 1+1;
} }
log.log("Hey!"); logr.log("Hey!");
} }