Separating out into DataSink CRTP model. Removed SmartStreams
This commit is contained in:
parent
4c8c622f0b
commit
50e37b8421
@ -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)
|
||||
|
||||
@ -2,74 +2,113 @@
|
||||
#ifndef _NB_DATASINK
|
||||
#define _NB_DATASINK
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "ThreadSafeQueue.hpp"
|
||||
|
||||
namespace nb {
|
||||
|
||||
template <typename T>
|
||||
class SinkBase {
|
||||
using InputType = T;
|
||||
template<typename DataType>
|
||||
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<bool> _running;
|
||||
};
|
||||
|
||||
/* template <typename T>
|
||||
class Sink : public SinkBase {
|
||||
template<typename DataType, typename BufferType, typename ProcessorType>
|
||||
class BufferedDataProcessor : public DataSink<DataType> {
|
||||
using Base = DataSink<DataType>;
|
||||
public:
|
||||
Sink& operator=(const Sink&) = 0;
|
||||
|
||||
template<typename U>
|
||||
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 <typename T>
|
||||
class SourceBase {
|
||||
using OutputType = T;
|
||||
public:
|
||||
SourceBase& operator=(const SourceBase&) = 0;
|
||||
|
||||
virtual bool out(T*) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
SourceBase();
|
||||
SinkBase<T>* _sink;
|
||||
using Base::_running;
|
||||
|
||||
BufferType _buffer;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Pipe : public SinkBase<T>, public SourceBase<T>{
|
||||
using Input = SourceBase<T>;
|
||||
using Output = SinkBase<T>;
|
||||
template<typename DataType, typename ProcessorType>
|
||||
class MultithreadedDataProcessor : public BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType> {
|
||||
using Base = BufferedDataProcessor<DataType, ThreadsafeQueue<DataType>, ProcessorType>;
|
||||
public:
|
||||
Pipe(Sink<T>& 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<std::thread>([&]{
|
||||
auto this_type = static_cast<ProcessorType*>(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<ProcessorType*>(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<DataType> event;
|
||||
this->_buffer.pop(event);
|
||||
process(*event);
|
||||
return *event;
|
||||
}
|
||||
virtual void flush() override {
|
||||
auto this_type = static_cast<ProcessorType*>(this);
|
||||
while(this_type->count()) {
|
||||
this_type->pop();
|
||||
}
|
||||
}
|
||||
virtual void clear() override {
|
||||
this->_buffer.empty();
|
||||
}
|
||||
|
||||
virtual bool process(const DataType&) = 0;
|
||||
|
||||
std::shared_ptr<std::thread> _runningThread;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* template <typename T>
|
||||
class Source : SourceBase {
|
||||
public:
|
||||
Source& operator=(const Source&) = 0;
|
||||
|
||||
template<typename U>
|
||||
virtual bool out(const U&) = 0;
|
||||
|
||||
protected:
|
||||
Source();
|
||||
|
||||
}; */
|
||||
|
||||
} // namespace nb
|
||||
#endif // _NB_DATASINK
|
||||
@ -9,6 +9,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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<uint8_t, LogProcessFunction> LogProcessFunctionMap;
|
||||
|
||||
template<typename LoggerName, typename ST=std::ostream>
|
||||
class LoggerBase {
|
||||
/* template<typename LogType, typename Logger, typename ST=std::ostream>
|
||||
class LoggerBase;
|
||||
|
||||
template<typename Logger>
|
||||
class LoggerBase<typename Logger::LogType, Logger, typename Logger::StreamType>
|
||||
: public MultithreadedDataProcessor<typename Logger::LogType, Logger>{
|
||||
protected:
|
||||
typename Logger::StreamType _ostreams;
|
||||
}; */
|
||||
|
||||
class DebugLogger : public MultithreadedDataProcessor<LogEvent, DebugLogger>{
|
||||
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<LogEvent, DebugLogger>::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<std::thread>([&]{
|
||||
auto this_type = static_cast<Type*>(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<LogEvent> event;
|
||||
_queue.pop(event);
|
||||
static_cast<Type*>(this)->process(*event);
|
||||
return *event;
|
||||
}
|
||||
|
||||
void flush() noexcept {
|
||||
while(_queue.size()) {
|
||||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
void deleteAll() {
|
||||
_queue.empty();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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 <size_t N>
|
||||
void log(char const(&msg) [N], const uint8_t& lvl) {
|
||||
static_cast<Type*>(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<Type*>(this)->log(msg, lvl);
|
||||
}
|
||||
template<typename U>
|
||||
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<Type*>(this)->log(msg, lvl);
|
||||
}
|
||||
void warn(const std::exception& err, const uint8_t lvl=0x01) {
|
||||
static_cast<Type*>(this)->log(err, lvl);
|
||||
}
|
||||
|
||||
void error(const std::string& msg, const uint8_t lvl=0xFF) {
|
||||
static_cast<Type*>(this)->log(msg, lvl);
|
||||
}
|
||||
void error(const std::exception& err, const uint8_t lvl=0xFF) {
|
||||
static_cast<Type*>(this)->log(err, lvl);
|
||||
}
|
||||
template<typename U>
|
||||
void error(const U& val, const uint8_t& lvl=0xFF) { log(val, lvl); }
|
||||
|
||||
protected:
|
||||
void process(const LogEvent&);
|
||||
std::ostream* const _ostream;
|
||||
|
||||
ThreadsafeQueue<LogEvent> _queue;
|
||||
std::vector<StreamType*> const _ostreams;
|
||||
std::atomic<bool> _running;
|
||||
std::shared_ptr<std::thread> _runningThread = nullptr;
|
||||
virtual bool process(const LogEvent& msg) override {
|
||||
*_ostream << msg.pid << " - " << msg.tid << " : " << msg.msg << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BasicLogger : public LoggerBase<BasicLogger> {
|
||||
/* class BasicLogger : public LoggerBase<BasicLogger> {
|
||||
public:
|
||||
using Base = LoggerBase<BasicLogger>;
|
||||
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
|
||||
@ -1,124 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef _NB_SMARTSTREAM
|
||||
#define _NB_SMARTSTREAM
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace nb {
|
||||
|
||||
template <typename StreamType, typename... Mixins>
|
||||
class SmartStream;
|
||||
|
||||
template<typename Wrapper, typename U, typename Mix>
|
||||
struct MixinHasProcess {
|
||||
protected:
|
||||
template <typename M>
|
||||
static auto test(int)->decltype(
|
||||
std::declval<M>().template process<Wrapper>(std::declval<const U&>()),
|
||||
std::true_type{}
|
||||
);
|
||||
|
||||
template <typename>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static const bool value = decltype(test<Mix>(0))::value;
|
||||
};
|
||||
|
||||
template<typename Wrapper, typename U, typename... Mixins>
|
||||
struct PackHasProcess;
|
||||
|
||||
template<typename Wrapper, typename U, typename Mix>
|
||||
struct PackHasProcess<Wrapper, U, Mix> {
|
||||
static const bool value = MixinHasProcess<Wrapper, U, Mix>::value;
|
||||
using type = typename std::conditional<
|
||||
value,
|
||||
Mix,
|
||||
void
|
||||
>::type;
|
||||
};
|
||||
|
||||
template<typename Wrapper, typename U, typename Mix1, typename... Mixins>
|
||||
struct PackHasProcess<Wrapper, U, Mix1, Mixins...> {
|
||||
protected:
|
||||
static const bool base_value = MixinHasProcess<Wrapper, U, Mix1>::value;
|
||||
public:
|
||||
static const bool value = std::conditional<
|
||||
base_value,
|
||||
std::true_type,
|
||||
typename PackHasProcess<Wrapper, U, Mixins...>::value
|
||||
>::type::value;
|
||||
using type = typename std::conditional<
|
||||
base_value,
|
||||
Mix1,
|
||||
typename PackHasProcess<Wrapper, U, Mixins...>::type
|
||||
>::type;
|
||||
};
|
||||
|
||||
/* template <typename T, typename=void>
|
||||
struct HasStreamType : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasStreamType<T, > : std::false_type {}; */
|
||||
|
||||
template<typename ST, typename... Mixins>
|
||||
class SmartStream : public Mixins... {
|
||||
using StreamType = typename std::conditional<
|
||||
decltype(std::declval<ST::StreamType>(), std::true_type{}),
|
||||
ST::StreamType,
|
||||
ST
|
||||
>::type;
|
||||
protected:
|
||||
StreamType* const _stream;
|
||||
|
||||
public:
|
||||
SmartStream(StreamType& stream) : _stream(&stream), Mixins(&stream)... {}
|
||||
|
||||
using Mixins::process...;
|
||||
|
||||
template <typename U, typename StreamFmt=SmartStream<StreamType, Mixins...>>
|
||||
typename std::enable_if<PackHasProcess<SmartStream, U, Mixins...>::value, void>::type
|
||||
toStream(const U& val, const StreamFmt* fmtas=nullptr) {
|
||||
PackHasProcess<SmartStream, U, Mixins...>::type::template process<SmartStream>(val);
|
||||
}
|
||||
|
||||
template <typename U, typename StreamFmt=SmartStream<StreamType, Mixins...>>
|
||||
typename std::enable_if<!PackHasProcess<SmartStream, U, Mixins...>::value, void>::type
|
||||
toStream(const U& val, const StreamFmt* fmtas=nullptr) {
|
||||
*_stream << val;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
friend SmartStream& operator<<(SmartStream& stream, const U& val) {
|
||||
stream.toStream(val);
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
struct SmartText {
|
||||
int x;
|
||||
};
|
||||
|
||||
template <typename StreamType>
|
||||
struct ANSIFormatter {
|
||||
template <typename Wrapper>
|
||||
void process(const SmartText& val, StreamType* fmtas = nullptr) {
|
||||
static_cast<Wrapper*>(this)->toStream(val.x);
|
||||
}
|
||||
|
||||
protected:
|
||||
ANSIFormatter(StreamType* stream) : _stream(stream) {}
|
||||
|
||||
StreamType* const _stream;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _NB_SMARTSTREAM
|
||||
@ -26,20 +26,15 @@ const ErrorCodeMap TestError::ErrorMessages{
|
||||
{TestError::ErrorCodes::D, "Doin"}
|
||||
};
|
||||
|
||||
class TestLogger : public nb::LoggerBase<TestLogger> {
|
||||
public:
|
||||
using Base = LoggerBase<TestLogger>;
|
||||
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!");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user