Refactored to do CRTP. Got multi val init working
This commit is contained in:
parent
50e37b8421
commit
9be6036265
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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,24 +127,44 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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!");
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user