diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fa6929..e16b91a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) add_library(NBEvents ./src/NBEvents/Events.cpp) -add_library(NBCore ./src/NBCoreUtils/Errors.cpp) +add_subdirectory(./src/NBCoreUtils) add_subdirectory(./src/NBWindow ./NBWindows) add_subdirectory(./tests ./tests) \ No newline at end of file diff --git a/include/DataSink.hpp b/include/DataSink.hpp new file mode 100644 index 0000000..f28f418 --- /dev/null +++ b/include/DataSink.hpp @@ -0,0 +1,75 @@ +#pragma once +#ifndef _NB_DATASINK +#define _NB_DATASINK + +namespace nb { + +template +class SinkBase { + using InputType = T; +public: + virtual bool in(const T&) = 0; + +protected: + SinkBase(); + +}; + +/* template +class Sink : public SinkBase { +public: + Sink& operator=(const Sink&) = 0; + + template + virtual bool in(const U&) = 0; + +protected: + Sink(); + +}; */ + +template +class SourceBase { + using OutputType = T; +public: + SourceBase& operator=(const SourceBase&) = 0; + + virtual bool out(T*) = 0; + + +protected: + SourceBase(); + SinkBase* _sink; + +}; + +template +class Pipe : public SinkBase, public SourceBase{ + using Input = SourceBase; + using Output = SinkBase; +public: + Pipe(Sink& sink) : Input::_sink{&sink} {} + + bool in(const T&) = 0; + +protected: + using Input::_sink; +}; + + + +/* 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/include/Logger.hpp b/include/Logger.hpp new file mode 100644 index 0000000..a551107 --- /dev/null +++ b/include/Logger.hpp @@ -0,0 +1,64 @@ +#pragma once +#ifndef _NB_LOGGER +#define _NB_LOGGER + +#include +#include +#include +#include + +#include "SmartStreams.hpp" +#include "ThreadSafeQueue.hpp" + +namespace nb { + +typedef std::chrono::time_point< + std::chrono::system_clock, + std::chrono::nanoseconds +> LoggerTimePoint; + +struct LogEvent{ + const LoggerTimePoint time; + const unsigned char lvl; + const std::string msg; +}; + +template +class Logger { +typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); +typedef std::unordered_map LogProcessFunctionMap; +public: + Logger(); + + bool isRunning() const; + unsigned int count() const; + + bool run(); + bool stop(); + LogEvent popProcess(); + LogEvent popDelete(); + void flush(); + void deleteAll(); + void msg(const std::string&, uint8_t lvl=0); + void warn(const std::string&, uint8_t lvl=1); + void warn(const std::exception&, uint8_t lvl=1); + void error(const std::string&, uint8_t lvl=0xFF); + void error(const std::exception&, uint8_t lvl=0xFF); + + +protected: + virtual void process(const LogEvent&); + + const LogProcessFunctionMap _function_map; + + ThreadsafeQueue _queue; + T* _ostream; + // std::condition_variable _cond; + // mutable std::mutex _mutex; + mutable std::mutex _runningMutex; + bool _running; + std::shared_ptr _runningThread = nullptr; +}; + +} // namespace nb +#endif // _NB_LOGGER \ No newline at end of file diff --git a/include/SmartStreams.hpp b/include/SmartStreams.hpp new file mode 100644 index 0000000..070b531 --- /dev/null +++ b/include/SmartStreams.hpp @@ -0,0 +1,109 @@ +#pragma once +#ifndef _NB_SMARTSTREAM +#define _NB_SMARTSTREAM + +#include +#include +#include +#include +#include + +namespace nb { + +typedef std::pair SmartTextKV; + +//template +struct SmartText { + std::string msg; + SmartTextKV kv = {0, ""}; +}; + +typedef std::string (*SmartTextFormatter)(std::string, std::string); + +typedef std::unordered_map SmartFormatMap; + +template +class SmartOStreamBaseImpl; + +template +class SmartOStream; + +template +class SmartOStreamBaseImpl { +public: + virtual void process(const SmartText&) = 0; + + static const SmartFormatMap Formatters; + using StreamType = SmartOStream; +protected: + SmartOStreamBaseImpl(StreamType& stream) : _ostream(&stream) {} + StreamType* _ostream; +}; + +template +class SmartOStreamBaseImpl, Derived> { + public: + virtual void process(const SmartText&) = 0; + + static const SmartFormatMap Formatters; + using StreamType = std::basic_ostream; +protected: + SmartOStreamBaseImpl(StreamType& stream) : _ostream(&stream) {} + StreamType* _ostream; +}; + + +template +class SmartOStream : public SmartOStreamBaseImpl { + template + friend SmartOStream& operator<<(SmartOStream&, const U&); + +public: + StreamType* getStream() const { return _ostream; } + + template + void process(const X&); + + void process(const SmartText&); + + static const SmartFormatMap Formatters; + using Base = SmartOStreamBaseImpl; + +protected: + using Base::Base; + using Base::_ostream; + + static std::string defaultFormatter(std::string msg, std::string fmt) { + return msg; + } +}; + +template +const SmartFormatMap SmartOStream::Formatters = { + {0, defaultFormatter} + }; + +template +SmartOStream& operator<<(SmartOStream& stream, const U& msg) { + static_cast(&stream)->process(msg); + return stream; +} + +template +void SmartOStream::process(const SmartText& msg) { + try { + *_ostream << D::Formatters.at(msg.kv.first)(msg.msg, msg.kv.second); + } catch (const std::out_of_range& e) { + *_ostream << D::Formatters.at(0)(msg.msg, msg.kv.second); + } +} + +template +template +void SmartOStream::process(const X& msg) { + *_ostream << msg; +} + +} + +#endif // _NB_SMARTSTREAM \ No newline at end of file diff --git a/src/NBCoreUtils/CMakeLists.txt b/src/NBCoreUtils/CMakeLists.txt index e69de29..c7b8376 100644 --- a/src/NBCoreUtils/CMakeLists.txt +++ b/src/NBCoreUtils/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(NBCore + Errors.cpp +) \ No newline at end of file diff --git a/src/NBCoreUtils/Logger.cpp b/src/NBCoreUtils/Logger.cpp new file mode 100644 index 0000000..e6ba3fb --- /dev/null +++ b/src/NBCoreUtils/Logger.cpp @@ -0,0 +1,87 @@ +#include "Logger.hpp" + +namespace nb { + +template +bool Logger<>::isRunning() const { + std::lock_guard lock(_runningMutex); + return _running; +} + +unsigned int Logger::count() const { + return _queue.size(); +} + +bool Logger::run() { + std::lock_guard lock(_runningMutex); + if (!_running) { + _runningThread = std::make_shared([&]{ + while(this->_running) { + this->flush(); + } + }); + } + return _running; +} + +bool Logger::stop() { + std::lock_guard lock(_runningMutex); + _running = false; + _runningThread->join(); + return _running; +} + +void Logger::process(const LogEvent& event) { + uint8_t lvl = event.lvl; + try { + _ostream << _function_map.at(lvl)(event.time, event.msg).c_str(); + } catch (std::out_of_range e) { + _ostream << _function_map[0](event.time, event.msg).c_str(); + } +} + +LogEvent Logger::popProcess() { + std::shared_ptr event; + _queue.pop(event); + process(*event); + return *event; +} + +LogEvent Logger::popDelete() { + std::shared_ptr event; + _queue.pop(event); + process(*event); + return *event; +} + +void Logger::flush() { + while(_queue.size()) { + popProcess(); + } +} + +void Logger::deleteAll() { + _queue.empty(); +} + +void Logger::msg(const std::string& _msg, uint8_t lvl) { + _queue.push(LogEvent{std::chrono::system_clock::now(), lvl, _msg}); +} + +void Logger::warn(const std::string& _msg, uint8_t lvl) { + msg(_msg, lvl); +} + +void Logger::warn(const std::exception& _err, uint8_t lvl) { + msg(_err.what(), lvl); +} + +void Logger::error(const std::string& _msg, uint8_t lvl) { + msg(_msg, lvl); +} + +void Logger::error(const std::exception& _err, uint8_t lvl) { + msg(_err.what(), lvl); +} + +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 847185b..9c349e2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,4 +13,5 @@ endif() include(GoogleTest) set(GTEST_COLOR ON) -add_subdirectory(./ErrorTest) \ No newline at end of file +add_subdirectory(./ErrorTest) +add_subdirectory(./SmartStreamTest) \ No newline at end of file diff --git a/tests/SmartStreamTest/CMakeLists.txt b/tests/SmartStreamTest/CMakeLists.txt new file mode 100644 index 0000000..5aca423 --- /dev/null +++ b/tests/SmartStreamTest/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.26.0) +project(gtest_Graphics VERSION 0.1.0 LANGUAGES C CXX) + +add_executable(SmartStreamTest main.cpp) +target_link_libraries(SmartStreamTest NBCore) \ No newline at end of file diff --git a/tests/SmartStreamTest/main.cpp b/tests/SmartStreamTest/main.cpp new file mode 100644 index 0000000..7c9815d --- /dev/null +++ b/tests/SmartStreamTest/main.cpp @@ -0,0 +1,38 @@ +#include + +#include "SmartStreams.hpp" + +template +class TestStream : public nb::SmartOStream> { + using Base = nb::SmartOStream>; +public: + TestStream(ST& stream) : Base(stream) {} + + static const nb::SmartFormatMap Formatters; + // using Base::Formatters; + + +protected: +}; + +template +const nb::SmartFormatMap TestStream::Formatters = { + {0, [](std::string msg, std::string fmt){ + return "[0] : " + msg; + }}, + {1, [](std::string msg, std::string fmt){ + return "\x1b[" + fmt + "m" + msg + "\x1b[0m"; + }}, + {2, [](std::string msg, std::string fmt){ + return "\x1b[1m" + msg + "\x1b[0m"; + }} +}; + +int main() { + + auto tout = TestStream(std::cout); + tout << nb::SmartText{"Gloop!\n", {2, "32"}}; + tout << 8989; + + return 0; +}