diff --git a/CMakeLists.txt b/CMakeLists.txt index 7479234..5f84f4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) include(GNUInstallDirs) include(CMakePackageConfigHelpers) +include(CMakeDependentOption) function(toAbsolutePath SETVAR PATHS) set(PATHS ${PATHS} ${ARGN}) @@ -31,13 +32,42 @@ if(CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS "Targeting Release build") elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Targeting Debug build") - set(NB_LOGGING ON) - set(NB_BUILD_TESTS ON) - set(NB_BUILD_DOCS ON) - set(NBENGINE_INSTALL ON) + set(NB_DEBUG_BUILD ON) add_compile_definitions(_NB_BUILD_DEBUG) endif() +cmake_dependent_option(NB_LOGGING + "Creates a default logger and automatically logs with code locations." + ON + NB_DEBUG_BUILD + OFF +) +cmake_dependent_option(NB_BUILD_TESTS + "Build unit tests" + ON + NB_DEBUG_BUILD + OFF +) +cmake_dependent_option(NB_BUILD_DOCS + "Build documentation" + ON + NB_DEBUG_BUILD + OFF +) +cmake_dependent_option(NBENGINE_INSTALL + "Install NBEngine" + ON + NB_DEBUG_BUILD + OFF +) +cmake_dependent_option(NB_MONITOR_OPENGL_CALLS + "Monitors every OpenGL call for errors" + ON + NB_DEBUG_BUILD + OFF +) + + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") message(STATUS "Building for Windows") set(NB_TARGET_WINDOWS ON) @@ -67,15 +97,16 @@ if (NB_LOGGING) add_compile_definitions(_NB_CODE_ERROR_LOCATIONS) endif() -if (NB_TARGET_WINDOWS) +if(NB_TARGET_WINDOWS) add_compile_definitions(_NB_TARGET_WINDOWS) -elseif (NB_TARGET_LINUX) +endif() +if(NB_TARGET_LINUX) add_compile_definitions(_NB_TARGET_LINUX) endif() -get_filename_component(NBENGINE_ROOT ./ ABSOLUTE) +get_filename_component(NBENGINE_ROOT ${CMAKE_CURRENT_LIST_DIR} ABSOLUTE) -add_subdirectory(./engine) +add_subdirectory(./engine ${PROJECT_BINARY_DIR}/${CMAKE_BUILD_TYPE}) # Toggle set(NB_REBUILD_DOCS) @@ -84,22 +115,23 @@ if (NB_BUILD_DOCS) add_subdirectory(./docs) endif() +include(CMakePackageConfigHelpers) +configure_package_config_file( + "NBEngineConfig.cmake.in" + "${PROJECT_BINARY_DIR}/cmake/NBEngineConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake + PATH_VARS CMAKE_INSTALL_LIBDIR +) +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/cmake/NBEngineConfigVersion.cmake" + COMPATIBILITY AnyNewerVersion +) + if (NBENGINE_INSTALL) include(GNUInstallDirs) - include(CMakePackageConfigHelpers) - configure_package_config_file( - "NBEngineConfig.cmake.in" - "NBEngineConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake - PATH_VARS CMAKE_INSTALL_LIBDIR - ) - write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/NBEngineConfigVersion.cmake" - COMPATIBILITY AnyNewerVersion - ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/NBEngineConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/NBEngineConfigVersion.cmake" + "${PROJECT_BINARY_DIR}/cmake/NBEngineConfig.cmake" + "${PROJECT_BINARY_DIR}/cmake/NBEngineConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" ) endif() diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 0a2e3b2..884d459 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -3,17 +3,28 @@ add_subdirectory(./NBCore) get_target_property(NBCORE_INTERFACE_INCLUDES NBCore INTERFACE_INCLUDE_DIRECTORIES) include_directories(${NBCORE_INTERFACE_INCLUDES}) -add_subdirectory(./NBEvents) +#add_subdirectory(./NBEvents) add_subdirectory(./NBGraphics) +add_subdirectory(./NBData) -if (NB_CORE_SOURCE OR NB_EVENTS_SOURCE OR NB_GRAPHICS_SOURCE) +if (NB_CORE_SOURCE OR NB_EVENTS_SOURCE OR NB_GRAPHICS_SOURCE OR NB_DATA_SOURCE) set(NB_SOURCE_FILES "") - list(APPEND NB_SOURCE_FILES ${NB_CORE_SOURCE} ${NB_GRAPHICS_SOURCE} ${NB_EVENTS_SOURCE}) + list(APPEND NB_SOURCE_FILES + ${NB_CORE_SOURCE} + ${NB_GRAPHICS_SOURCE} + ${NB_EVENTS_SOURCE} + ${NB_DATA_SOURCE} + ) set(NB_SOURCE_FILES ${NB_SOURCE_FILES} PARENT_SCOPE) endif() -if (NB_CORE_INCLUDE OR NB_EVENTS_INCLUDE OR NB_GRAPHICS_INCLUDE) +if (NB_CORE_INCLUDE OR NB_EVENTS_INCLUDE OR NB_GRAPHICS_INCLUDE OR NB_DATA_INCLUDE) set(NB_INCLUDE_FILES "") - list(APPEND NB_INCLUDE_FILES ${NB_CORE_INCLUDE} ${NB_GRAPHICS_INCLUDE} ${NB_EVENTS_INCLUDE}) + list(APPEND NB_INCLUDE_FILES + ${NB_CORE_INCLUDE} + ${NB_GRAPHICS_INCLUDE} + ${NB_EVENTS_INCLUDE} + ${NB_DATA_INCLUDE} + ) set(NB_INCLUDE_FILES ${NB_INCLUDE_FILES} PARENT_SCOPE) endif() diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index ad44959..8940f90 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -1,6 +1,13 @@ cmake_minimum_required(VERSION 3.10) project(NBCore VERSION 0.1) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + toAbsolutePath(NB_CORE_SOURCE ./src/ErrorsImpl.cpp ./src/Logger.cpp @@ -14,6 +21,7 @@ toAbsolutePath(NB_CORE_INCLUDE ./include/NBCore/Errors.hpp ./include/NBCore/ErrorsImpl.hpp ./include/NBCore/Logger.hpp + ./include/NBCore/Printer.hpp ./include/NBCore/Processes.hpp ./include/NBCore/StringUtils.hpp ./include/NBCore/ThreadsafeQueue.hpp @@ -28,45 +36,51 @@ set(NB_CORE_INCLUDE ${NB_CORE_INCLUDE} PARENT_SCOPE) add_library(NBCore ${NB_CORE_SOURCE}) add_library(NBEngine::Core ALIAS NBCore) target_include_directories(NBCore - PUBLIC "$" + PUBLIC "$" PUBLIC "$" ) +export( + TARGETS NBCore + FILE "${CMAKE_BINARY_DIR}/cmake/NBCoreTargets.cmake" + NAMESPACE NBEngine:: +) +configure_package_config_file( + "NBCoreConfig.cmake.in" + "${CMAKE_BINARY_DIR}/cmake/NBCoreConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" + PATH_VARS CMAKE_INSTALL_LIBDIR +) +write_basic_package_version_file( + "${CMAKE_BINARY_DIR}/cmake/NBCoreConfigVersion.cmake" + COMPATIBILITY AnyNewerVersion +) if (NBENGINE_INSTALL) message("Installing NBCore to ${CMAKE_INSTALL_PREFIX}") - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) install( TARGETS NBCore EXPORT NBCoreTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include ) install( - DIRECTORY "${PROJECT_SOURCE_DIR}/include/NBCore" + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/NBCore" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" ) install( EXPORT NBCoreTargets - DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake + DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" NAMESPACE NBEngine:: ) - configure_package_config_file( - "NBCoreConfig.cmake.in" - "NBCoreConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake - PATH_VARS CMAKE_INSTALL_LIBDIR - ) - write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/NBCoreConfigVersion.cmake" - COMPATIBILITY AnyNewerVersion - ) install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/NBCoreConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/NBCoreConfigVersion.cmake" - DESTINATION "${CMAKE_INSTALL_PREFIX}/cmake" + "${CMAKE_BINARY_DIR}/cmake/NBCoreConfig.cmake" + "${CMAKE_BINARY_DIR}/cmake/NBCoreConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_PREFIX}/CMake" ) endif() if (NB_BUILD_TESTS) - add_subdirectory(./tests) + add_subdirectory(./tests ) endif() \ No newline at end of file diff --git a/engine/NBCore/include/NBCore/DataSink.hpp b/engine/NBCore/include/NBCore/DataSink.hpp index 06d3903..ba8372f 100644 --- a/engine/NBCore/include/NBCore/DataSink.hpp +++ b/engine/NBCore/include/NBCore/DataSink.hpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -11,121 +12,170 @@ namespace nb { template class DataSink { -public: + public: DataSink(const DataSink&) = delete; DataSink(DataSink&&) = delete; DataSink& operator=(const DataSink&) = delete; virtual bool isRunning() const noexcept { - return _running; + std::atomic_thread_fence(std::memory_order_acquire); + return _running.load(std::memory_order_acquire); } virtual bool stop() noexcept = 0; virtual bool run() = 0; virtual bool in(const DataType&) = 0; -protected: - DataSink() = default; + protected: + DataSink() { + _running.store(false, std::memory_order_release); + } std::atomic _running; }; +template> +class MultiSink : public DataSink { + protected: + using Base = DataSink; + using SinkPtr = std::shared_ptr; + using Base::_running; + std::vector _sinks; + + public: + MultiSink(std::vector sinks={}) : _sinks(sinks) {} + virtual void addSink(SinkPtr sink) { + _sinks.push_back(sink); + } + virtual std::vector& getSinks() { return _sinks; } + bool isRunning() const noexcept override { + return Base::isRunning(); + } + bool stop() noexcept override { + _running.store(false, std::memory_order_release); + for (auto& sink : _sinks) { + sink->stop(); + } + return isRunning(); + } + bool run() override { + _running.store(true, std::memory_order_release); + for (auto& sink : _sinks) { + sink->run(); + } + return isRunning(); + } + bool in(const DataType& data) override { + if (isRunning()) { + bool success = true; + for (auto& sink : _sinks) { + success &= sink->in(data); + } + return success; + } + return false; + } +}; + template class BufferedDataProcessor : public DataSink { - using Base = DataSink; -public: - using Base::Base; + private: + ProcessorType* const type_ptr = static_cast(this); + protected: + using Base = DataSink; + using Base::_running; + BufferType _buffer; + virtual unsigned int count() const { + return type_ptr->count(); + } + virtual bool pop(std::shared_ptr ret) { + return type_ptr->pop(ret); + } + virtual void flush() { + type_ptr->flush(); + } + virtual void clear() { + type_ptr->clear(); + } + virtual bool process(const DataType& val) = 0; + + public: + using Base::Base; virtual bool stop() noexcept override { return type_ptr->stop(); } virtual bool run() override { return type_ptr->run(); } virtual bool in(const DataType& val) override { return type_ptr->in(val); } -protected: - unsigned int count() const { - return type_ptr->count(); - } - void push(const DataType& val) { - type_ptr->push(val); - } - 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; - - BufferType _buffer; - -private: - ProcessorType* const type_ptr = static_cast(this); - }; template class MultithreadedDataProcessor : public BufferedDataProcessor, ProcessorType> { - using Base = BufferedDataProcessor, ProcessorType>; - public: - ~MultithreadedDataProcessor() { type_ptr->stop(); } + private: + ProcessorType* const type_ptr = static_cast(this); + std::mutex _pause; - bool isRunning() const noexcept override { - return this->_running; + protected: + using Base = BufferedDataProcessor, ProcessorType>; + using Base::Base; + using Base::process; + using Base::_running; + std::shared_ptr _runningThread; + virtual unsigned int count() const override { + return type_ptr->_buffer.size(); } + virtual bool pop(std::shared_ptr ret=nullptr) override { + type_ptr->_buffer.pop(ret); + return this->process(*ret); + } + virtual bool popBlock(std::shared_ptr ret=nullptr) { + ret = type_ptr->_buffer.popBlock(); + return this->process(*ret); + } + virtual void flush() override { + while(type_ptr->count()) { + type_ptr->pop(); + } + } + virtual void clear() override { + type_ptr->_buffer.empty(); + } + virtual std::unique_lock pause() { + return std::move(std::unique_lock(_pause)); + } + + public: + using Base::isRunning; + virtual ~MultithreadedDataProcessor() { type_ptr->stop(); } + bool run() override { if (!type_ptr->isRunning()) { - this->_running = true; + _running.store(true, std::memory_order_release); _runningThread = std::make_shared([&]{ while(type_ptr->isRunning()) { - flush(); + std::lock_guard lock(_pause); + type_ptr->flush(); } + type_ptr->flush(); + type_ptr->stop(); }); } - return this->isRunning(); + return type_ptr->isRunning(); } bool stop() noexcept override { if (type_ptr->isRunning()) { - this->_running = false; - _runningThread->join(); - _runningThread = nullptr; + _running.store(false, std::memory_order_release); + if (_runningThread) { + _runningThread->join(); + _runningThread = nullptr; + } + type_ptr->flush(); } return !type_ptr->isRunning(); } - - protected: - using Base::Base; - - unsigned int count() const { - return this->_buffer.size(); + bool in(const DataType& val) override { + type_ptr->_buffer.push(val); + return type_ptr->isRunning(); } - void push(const DataType& val) { - this->_buffer.push(val); - }; - DataType pop() { - std::shared_ptr event; - this->_buffer.pop(event); - this->process(*event); - return *event; - } - void flush() { - while(type_ptr->count()) { - pop(); - } - } - void clear() { - this->_buffer.empty(); - } - - std::shared_ptr _runningThread; - -private: - ProcessorType* type_ptr = static_cast(this); }; diff --git a/engine/NBCore/include/NBCore/Errors.hpp b/engine/NBCore/include/NBCore/Errors.hpp index 97649b8..de66a19 100644 --- a/engine/NBCore/include/NBCore/Errors.hpp +++ b/engine/NBCore/include/NBCore/Errors.hpp @@ -8,35 +8,57 @@ namespace nb { #ifdef _NB_AUTOLOG + #ifndef LOG_W_CODE_LOC + #define LOG_W_CODE_LOC(file, line, args...) nb::logger.msg(args, file, line) + #endif // LOG_W_CODE_LOC + #ifndef WARN_W_CODE_LOC + #define WARN_W_CODE_LOC(file, line, args...) nb::logger.warn(args, file, line) + #endif // WARN_W_CODE_LOC + #ifndef ERROR_W_CODE_LOC + #define ERROR_W_CODE_LOC(file, line, args...) nb::logger.error(args, file, line) + #endif // ERROR_W_CODE_LOC #ifdef _NB_CODE_ERROR_LOCATIONS #ifndef LOG - #define LOG(args...) nb::logger.log(args, __FILE__, __LINE__) + #define LOG(arg) LOG_W_CODE_LOC(__FILE__, __LINE__, arg) #endif // LOG #ifndef WARN - #define WARN(args...) nb::logger.warn(args, __FILE__, __LINE__) + #define WARN(args...) WARN_W_CODE_LOC(__FILE__, __LINE__, args) #endif // WARN #ifndef ERROR - #define ERROR(args...) nb::logger.error(args, __FILE__, __LINE__) + #define ERROR(arg) ERROR_W_CODE_LOC(__FILE__, __LINE__, arg) #endif // ERROR #else #ifndef LOG - #define LOG(args...) nb::logger.log(args) + #define LOG(args) nb::logger.msg(args) #endif // LOG #ifndef WARN #define WARN(args...) nb::logger.warn(args) #endif // WARN #ifndef ERROR - #define ERROR(args...) nb::logger.error(args) + #define ERROR(args) nb::logger.error(args) #endif // ERROR #endif // _NB_CODE_ERROR_LOCATIONS + #ifndef THROW_W_CODE_LOC + #define THROW_W_CODE_LOC(file, line, args...) ERROR_W_CODE_LOC(file, line, args); throw args + #endif // THROW_W_CODE_LOC +#else + #ifndef LOG + #define LOG(args) + #endif // LOG + #ifndef WARN + #define WARN(args...) + #endif // WARN + #ifndef ERROR + #define ERROR(args) + #endif // ERROR #endif // _NB_AUTOLOG #ifndef THROW #ifdef _NB_AUTOLOG - #define THROW(args...) ERROR(args); nb::logger.stop(); throw args + #define THROW(args...) THROW_W_CODE_LOC(__FILE__, __LINE__, args) #else #define THROW(args...) throw args - #endif // _NB_CODE_ERROR_LOCATIONS + #endif // _NB_AUTOLOG #endif // THROW } // namespace nb diff --git a/engine/NBCore/include/NBCore/ErrorsImpl.hpp b/engine/NBCore/include/NBCore/ErrorsImpl.hpp index 4aef324..e1f1cdc 100644 --- a/engine/NBCore/include/NBCore/ErrorsImpl.hpp +++ b/engine/NBCore/include/NBCore/ErrorsImpl.hpp @@ -6,13 +6,13 @@ #include #include #include -#include #include +#include namespace nb { -typedef std::unordered_map ErrorCodeMap; +using ErrorCodeMap = ConstantMap; class ErrorBase { protected: @@ -25,11 +25,10 @@ class ErrorBase { ErrorBase(const ErrorBase&) = default; ErrorBase(const std::exception&) noexcept; - ErrorBase(const std::string&) noexcept; virtual std::string what() const noexcept { std::string ret = msg; if (trace) { - std::string trace_msg = msg; + std::string trace_msg = trace->what(); ret += NEWLINE + indent_strblock( trace_msg, TABOVER, @@ -41,16 +40,16 @@ class ErrorBase { protected: ErrorBase( - unsigned int code_, - std::string msg_, - std::string type_, - std::shared_ptr trace_ -) noexcept : - code(code_), - msg(msg_), - type(type_), - trace{trace_} -{} + unsigned int code_, + std::string msg_, + std::string type_, + std::shared_ptr trace_ + ) noexcept : + code(code_), + msg(msg_), + type(type_), + trace{trace_} + {} }; template @@ -69,17 +68,16 @@ class Error : public ErrorBase { "const std::string type must be a class member." ); } - - protected: + + public: using ErrorBase::ErrorBase; - public: Error( unsigned int code_, const ErrorBase& trace_ ) noexcept : ErrorBase( code_, - ErrorType::ErrorMessages.at(code_), + ErrorType::ErrorMessages[code_], ErrorType::type, std::make_shared(trace_) ) { check_asserts(); } @@ -88,7 +86,7 @@ class Error : public ErrorBase { std::string msg_, const ErrorBase& trace_ ) noexcept : ErrorBase( - 0, + ErrorType::Codes::UNDEFINED, msg_, ErrorType::type, std::make_shared(trace_) @@ -96,13 +94,13 @@ class Error : public ErrorBase { Error(unsigned int code_) noexcept : ErrorBase( code_, - ErrorType::ErrorMessages.at(code_), + ErrorType::ErrorMessages[code_], ErrorType::type, nullptr ) { check_asserts(); } Error(std::string msg_) noexcept : ErrorBase( - 0, + ErrorType::Codes::UNDEFINED, msg_, ErrorType::type, nullptr @@ -114,14 +112,14 @@ class Error : public ErrorBase { const ErrorBase& trace_ ) noexcept : ErrorBase( code_, - ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::ErrorMessages[code_] + " (" + note_ + ")", ErrorType::type, std::make_shared(trace_) ) { check_asserts(); } Error(unsigned int code_, const std::string& note_) noexcept : ErrorBase( code_, - ErrorType::ErrorMessages.at(code_) + " (" + note_ + ")", + ErrorType::ErrorMessages[code_] + " (" + note_ + ")", ErrorType::type, nullptr ) { check_asserts(); } @@ -142,14 +140,18 @@ class Error : public Error> { using Base::what; using Base::code; using Base::trace; + using Base::Base; enum Codes : unsigned int { - STANDARD, UNDEFINED, INDEX_ERROR + STANDARD, UNDEFINED, OUT_OF_RANGE, VALUE_ERROR, OVERWRITE_ERROR }; inline static const std::string type = "nb::Error"; inline static const ErrorCodeMap ErrorMessages = { {STANDARD, "std::exception"}, {UNDEFINED, "Error"}, - {INDEX_ERROR, "Indexing error"} + {OUT_OF_RANGE, "Out-of-range error"}, + {VALUE_ERROR, "Invalid value"}, + {OVERWRITE_ERROR, "Attempting to overwrite managed data"} + }; Error(unsigned int code_=1) noexcept : Base(code_) {} @@ -159,13 +161,6 @@ class Error : public Error> { "std::exception", nullptr ) {} - - Error(const std::string& msg_) noexcept : Base( - Codes::UNDEFINED, - msg_, - type, - nullptr - ) {} }; template diff --git a/engine/NBCore/include/NBCore/Logger.hpp b/engine/NBCore/include/NBCore/Logger.hpp index 854564d..93129ce 100644 --- a/engine/NBCore/include/NBCore/Logger.hpp +++ b/engine/NBCore/include/NBCore/Logger.hpp @@ -3,13 +3,13 @@ #define _NB_LOGGER #include -#include #include #include #include #include #include +#include #include #include #include @@ -26,32 +26,32 @@ typedef std::chrono::time_point< typedef std::string (*LogProcessFunction)(const LoggerTimePoint&, const std::string&); typedef std::unordered_map LogProcessFunctionMap; -template -class LoggerBase -: public MultithreadedDataProcessor{ - using StreamType = ST; - using LoggerType = Logger; - using Base = MultithreadedDataProcessor; - - public: - bool run() override { - if (!static_cast(this)->isRunning()) { - this->_running = true; - this->_runningThread = std::make_shared([&]{ - while(static_cast(this)->isRunning()) { - static_cast(this)->flush(); - } - static_cast(this)->flush(); - }); - } - return static_cast(this)->isRunning(); - } - using Base::flush; +template +class LoggerBase : public MultithreadedDataProcessor{ + private: + Logger* const type_ptr = static_cast(this); protected: - LoggerBase() = default; + using LoggerType = Logger; + using Base = MultithreadedDataProcessor; + using SinkType = DataSink; + using Base::process; + std::shared_ptr _logsink; + LoggerBase(std::shared_ptr sink) : _logsink(sink) {} + + public: + using Base::flush; + bool run() override { + _logsink->run(); + return Base::run(); + } + using Base::pause; + bool stop() noexcept override { + auto ret = Base::stop(); + _logsink->stop(); + return ret; + } - StreamType _ostream; }; struct LogEvent{ @@ -64,59 +64,42 @@ struct LogEvent{ const unsigned int line=0; }; +class LogEventHandler : public DataSink { + protected: + using Base = DataSink; + using Base::_running; + std::atomic _logLevel; + + public: + using Base::isRunning; + LogEventHandler(uint8_t logging_level=0x01); + virtual uint8_t logLevel(uint8_t); + virtual uint8_t logLevel() const; + bool stop() noexcept override; + bool run() override; +}; + template -class DebugLogger : public LoggerBase>{ - using StreamType = std::vector; - using LoggerType = LT; - using Base = LoggerBase; -public: - - template - DebugLogger(ST&... streams) : _ostream(nb::RefPackToPtrVec(streams...).vec) {} - - ~DebugLogger() { static_cast(this)->stop(); } - - template - void log( - U val, - std::string file="", - unsigned int line=0 - ) { static_cast(this)->write_message(val, 0x00, file, line); } - - template - void warn( - U val, - uint8_t lvl=0x01, - std::string file="", - unsigned int line=0 - ) { static_cast(this)->write_message(val, lvl, file, line); } - - void error( - const ErrorBase& val, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->write_message(val, 0xFF, file, line); - static_cast(this)->flush(); - } - void error( - const std::string& val, - std::string file="", - unsigned int line=0 - ) { - static_cast(this)->write_message(Error(val), 0xFF, file, line); - static_cast(this)->flush(); - } +class DebugLogger : public LoggerBase{ + private: + LT* const type_ptr = static_cast(this); protected: - std::vector _ostream; - void write_message( + using LoggerType = LT; + using Base = LoggerBase; + using SinkType = LogEventHandler; + using SinkPtr = std::shared_ptr; + using Distributor = MultiSink; + using Base::_logsink; + using Base::process; + std::atomic _loglvl; + virtual void write_message( std::string msg, uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->push(LogEvent{ + type_ptr->in(LogEvent{ std::chrono::system_clock::now(), lvl, msg, @@ -126,7 +109,6 @@ public: line }); } - template void write_message( char const(&msg) [N], @@ -134,18 +116,16 @@ public: std::string file="", unsigned int line=0 ) { - static_cast(this)->write_message(std::string(msg), lvl, file, line); + this->write_message(std::string(msg), lvl, file, line); } - void write_message( const ErrorBase& err, uint8_t lvl=0x00, std::string file="", unsigned int line=0 ) { - static_cast(this)->write_message(err.what(), lvl, file, line); + this->write_message(err.what(), lvl, file, line); } - template std::enable_if_t, void> write_message( const U& val, @@ -153,38 +133,115 @@ public: std::string file="", unsigned int line=0 ) { - static_cast(this)->write_message(std::to_string(val), lvl, file, line); + this->write_message(std::to_string(val), lvl, file, line); + } + + public: + DebugLogger(std::vector sinks={}) : Base( + std::static_pointer_cast>(std::make_shared()) + ) { + for (auto sink : sinks) { + addLogHandler(sink); + } + } + ~DebugLogger() { static_cast(this)->stop(); } + void addLogHandler(SinkPtr sink) { + auto multsink = std::static_pointer_cast(_logsink); + multsink->addSink(sink); + } + uint8_t minimalLogLevel() const { + return _loglvl.load(std::memory_order_acquire); + } + uint8_t minimalLogLevel(uint8_t level) { + _loglvl.store(level, std::memory_order_release); + auto multsink = std::static_pointer_cast(_logsink); + for (auto& sink : multsink->getSinks()) { + if (sink->logLevel() < level) { + sink->logLevel(level); + } + } + return minimalLogLevel(); + } + + template + void msg( + U val, + std::string file="", + unsigned int line=0 + ) { this->write_message(val, 0x00, file, line); } + + template + void warn( + U val, + uint8_t lvl=0x01, + std::string file="", + unsigned int line=0 + ) { this->write_message(val, lvl, file, line); } + + void error( + const ErrorBase& val, + std::string file="", + unsigned int line=0 + ) { + this->write_message(val, 0xFF, file, line); + auto lock = this->pause(); + this->flush(); + } + + void error( + const std::string& val, + std::string file="", + unsigned int line=0 + ) { + this->write_message(Error<>(val), 0xFF, file, line); + auto lock = this->pause(); + this->flush(); } }; -class DefaultDebugLogger : public DebugLogger { - using LoggerType = DefaultDebugLogger; - using Base = DebugLogger; - - template - struct LogRow; +class DefaultTerminalLogEventPrinter : public LogEventHandler { + protected: + using Base = LogEventHandler; + using Base::_running; public: + using Base::isRunning; + using Base::logLevel; + using Base::stop; + using Base::run; using Base::Base; + bool in(const LogEvent&) override; +}; +class DefaultDebugLogger : public DebugLogger { + protected: + using LoggerType = DefaultDebugLogger; + using Base = DebugLogger; + using MultiLogSink = MultiSink; + using SinkPtr = std::shared_ptr; + using Base::_logsink; + using Base::write_message; + virtual bool process(const LogEvent& msg) override; + + public: + using Base::Base; + using Base::msg; + using Base::warn; + using Base::error; + using Base::addLogHandler; + using Base::minimalLogLevel; + DefaultDebugLogger(std::vector sinks={}) : Base(sinks) {} ~DefaultDebugLogger() { stop(); } friend class BufferedDataProcessor, DefaultDebugLogger>; - - template - friend STR& operator<<(STR&, const DefaultDebugLogger::LogRow&); - -protected: - using Base::_ostream; - - bool process(const LogEvent& msg); }; extern const bool LOGGER_RUNNING; -#ifndef _NB_NO_LOGGER +extern const bool LOGGER_RUNNING; +#ifdef _NB_AUTOLOG extern DefaultDebugLogger logger; -#endif // _NB_NO_LOGGER +#endif // _NB_AUTOLOG // Taking Charge of Adult ADHD by Russell Barkley diff --git a/engine/NBCore/include/NBCore/Printer.hpp b/engine/NBCore/include/NBCore/Printer.hpp new file mode 100644 index 0000000..90d9f79 --- /dev/null +++ b/engine/NBCore/include/NBCore/Printer.hpp @@ -0,0 +1,52 @@ +#pragma once +#ifndef _NB_PRINTER +#define _NB_PRINTER + +#include +#include +#include +#include + +namespace nb { + +template +class Printer { + private: + PrinterType* const type_ptr = static_cast(this); + + protected: + STREAM& _stream; + Printer(STREAM* const stream_) : _stream(stream_) {} + + public: + template + PrinterType& operator<<(const T& val_) { + (*type_ptr) << val_; + return type_ptr; + } + +}; + +class Terminal : public Printer { + private: + Terminal* const type_ptr = static_cast(this); + using MutexLock = std::lock_guard; + + protected: + using Base = Printer; + using Base::_stream; + std::mutex _mutex; + + public: + using Base::Base; + + template + Terminal& operator<<(const T& val_) { + MutexLock lock(_mutex); + _stream << val_; + return *type_ptr; + } +}; + +} // namespace nb +#endif // _NB_PRINTER \ No newline at end of file diff --git a/engine/NBCore/include/NBCore/StringUtils.hpp b/engine/NBCore/include/NBCore/StringUtils.hpp index bd283f3..43e8c77 100644 --- a/engine/NBCore/include/NBCore/StringUtils.hpp +++ b/engine/NBCore/include/NBCore/StringUtils.hpp @@ -2,7 +2,6 @@ #ifndef _NB_STRING_UTILS #define _NB_STRING_UTILS -#include #include #include @@ -21,24 +20,6 @@ namespace nb { const std::string TABOVER = " "; -// std::wstring str_to_wstr(std::string in); - -// std::string wstr_to_str(std::wstring in); - -template -void stream(const Stream& s, Args&&... args); - -template -void stream(const Stream& s, Args&&... args) { - (s << ... << args); -} - -template -void term(Args&&... args) { stream(std::cout, args..., NEWLINE); } - -template -void wterm(Args&&... args) { stream(std::wcout, args..., nb::WNEWLINE); } - template std::basic_string find_and_replace( ExplicitType_t> original, diff --git a/engine/NBCore/include/NBCore/TypeTraits.hpp b/engine/NBCore/include/NBCore/TypeTraits.hpp index 93d32b6..17fae25 100644 --- a/engine/NBCore/include/NBCore/TypeTraits.hpp +++ b/engine/NBCore/include/NBCore/TypeTraits.hpp @@ -90,6 +90,15 @@ struct RunAndOutput { } }; +template +using SubtractType = decltype(std::declval() - std::declval()); + +template +using MultiplyType = decltype(std::declval() * std::declval()); + +template +using AdditionType = decltype(std::declval() + std::declval()); + template inline typename std::enable_if::type ForEach(std::tuple&, Func) {} diff --git a/engine/NBCore/include/NBCore/Utils.hpp b/engine/NBCore/include/NBCore/Utils.hpp index f03761c..d4e0ab5 100644 --- a/engine/NBCore/include/NBCore/Utils.hpp +++ b/engine/NBCore/include/NBCore/Utils.hpp @@ -2,13 +2,27 @@ #ifndef _NB_CORE_TYPES #define _NB_CORE_TYPES -#include +#include +#include +#include #include -#include +// #include namespace nb { +template +class ConstantMap : public std::unordered_map { + using Base = std::unordered_map; + + public: + using Base::Base; + using Base::at; + const B& operator[](const A& key) const { + return at(key); + } +}; + template using SharedVector = std::vector>; @@ -17,7 +31,7 @@ using RValueVector = std::vector; using ByteVector = std::vector; -class ObjectManagerError : public Error { +/* class ObjectManagerError : public Error { using Base = Error; public: @@ -29,7 +43,7 @@ class ObjectManagerError : public Error { static const std::string type; static const ErrorCodeMap ErrorMessages; -}; +}; */ template ByteVector vectorToBytes(const std::vector& vec) { @@ -54,9 +68,10 @@ ByteVector concatVectorBytes(const std::vector& vec1, const std::vector& v template std::vector bytesToVector(const ByteVector& vec) { if (vec.size() % sizeof(T) != 0) { - THROW(Error( +/* THROW(Error( std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.") - )); + )); */ + throw "byyyyeeee"; } unsigned int num_elmts = vec.size() / sizeof(T); std::vector ret(num_elmts); @@ -65,7 +80,7 @@ std::vector bytesToVector(const ByteVector& vec) { return ret; } -template +/* template class ThreadsafeObjectLock; template @@ -114,7 +129,7 @@ class ThreadsafeObjectLock { _manager->_mutex.lock(); } ThreadsafeObject* const _manager; -}; +}; */ } // namespace nb #endif // _NB_CORE_TYPES \ No newline at end of file diff --git a/engine/NBCore/src/Logger.cpp b/engine/NBCore/src/Logger.cpp index da963c0..b3cb1c3 100644 --- a/engine/NBCore/src/Logger.cpp +++ b/engine/NBCore/src/Logger.cpp @@ -1,38 +1,82 @@ #include +#include #include #include namespace nb { -#ifndef _NB_NO_LOGGER -nb::DefaultDebugLogger logger(std::cout); -#endif // _NB_NO_LOGGER +static bool RUN_LOGGER(nb::DefaultDebugLogger& logger_) { + logger_.run(); + return logger_.isRunning(); +} -bool nb::DefaultDebugLogger::process(const LogEvent& msg) { +#ifdef _NB_AUTOLOG +DefaultDebugLogger logger({std::static_pointer_cast( + std::make_shared(0x0) +)}); +const bool LOGGER_RUNNING = RUN_LOGGER(logger); +#else +const bool LOGGER_RUNNING = false; +#endif // _NB_AUTOLOG + +// class LogEventHandler + +LogEventHandler::LogEventHandler(uint8_t logging_level) { + _logLevel.store(logging_level, std::memory_order_release); +} + +bool LogEventHandler::stop() noexcept { + _running.store(false, std::memory_order_release); + return isRunning(); +} + +bool LogEventHandler::run() { + _running.store(true, std::memory_order_release); + return isRunning(); +} + +uint8_t LogEventHandler::logLevel(uint8_t val) { + _logLevel.store(val, std::memory_order_release); + return logLevel(); +} +uint8_t LogEventHandler::logLevel() const { + return _logLevel.load(); +} + +// class DefaultTerminalLogEventPrinter + +bool DefaultTerminalLogEventPrinter::in(const LogEvent& msg) { + if (!isRunning()) { + return false; + } + if (msg.lvl < logLevel()) { + return false; + } constexpr size_t level_field_width = 5; constexpr size_t msg_prompt_length = level_field_width+7; - for (const auto os : this->_ostream) { - *os << "["; - os->width(level_field_width); - *os << std::to_string(msg.lvl) << "] :: "; - std::string fileloc=""; - if (!msg.file.empty()) { - fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; - } - *os << indent_strblock( - fileloc + msg.msg, - std::string(20 - msg_prompt_length, ' '), - "" - ) << nb::NEWLINE; + std::stringstream formatted_stream; + formatted_stream << "["; + formatted_stream.width(level_field_width); + formatted_stream << std::to_string(msg.lvl) << "] :: "; + std::string fileloc=""; + if (!msg.file.empty()) { + fileloc += "(" + msg.file + ":" + std::to_string(msg.line) + ") - "; } + formatted_stream << indent_strblock( + fileloc + msg.msg, + std::string(20 - msg_prompt_length, ' '), + "" + ) << nb::NEWLINE; + std::string formatted_string = formatted_stream.str(); + std::cout << formatted_string << std::flush; return true; } -static bool RUN_LOGGER(nb::DefaultDebugLogger& log) { - return log.run(); +// class DefaultDebugLogger + +bool DefaultDebugLogger::process(const LogEvent& msg) { + return _logsink->in(msg); } -const bool LOGGER_RUNNING = RUN_LOGGER(logger); - } // namespace nb \ No newline at end of file diff --git a/engine/NBCore/src/Utils.cpp b/engine/NBCore/src/Utils.cpp index 9ea7406..aa6904b 100644 --- a/engine/NBCore/src/Utils.cpp +++ b/engine/NBCore/src/Utils.cpp @@ -2,7 +2,7 @@ namespace nb { -using ObjectManagerCodes = ObjectManagerError::Codes; +/* using ObjectManagerCodes = ObjectManagerError::Codes; const std::string ObjectManagerError::type = "nb::ObjectManagerError"; const ErrorCodeMap ObjectManagerError::ErrorMessages({ {ObjectManagerCodes::UNDEFINED, "Error"}, @@ -22,6 +22,6 @@ const ErrorCodeMap ObjectManagerError::ErrorMessages({ ObjectManagerCodes::BAD_THREAD, "Attempting operation from a bad thread" } -}); +}); */ }; // namespace nb diff --git a/engine/NBCore/tests/testLogger.cpp b/engine/NBCore/tests/testLogger.cpp index 3ff74ff..b7d6e26 100644 --- a/engine/NBCore/tests/testLogger.cpp +++ b/engine/NBCore/tests/testLogger.cpp @@ -1,3 +1,4 @@ +#define _NB_AUTOLOG #include #include @@ -29,17 +30,19 @@ const nb::ErrorCodeMap TestError::ErrorMessages{ }; int main() { - nb::logger.log("Whoop!"); + while(!nb::LOGGER_RUNNING) {} + nb::logger.minimalLogLevel(0x0); + nb::logger.msg("Whoop!"); try { THROW(TestError(0, TestError(1, TestError(2, TestError(3, TestError(2)))))); } catch (TestError e){ - nb::logger.log("nb::Error was thrown!"); + nb::logger.msg("nb::Error was thrown!"); } try { THROW(std::exception()); } catch (std::exception e){ - nb::logger.log("std::exception was thrown!"); + nb::logger.msg("std::exception was thrown!"); } ERROR("hello there!"); return 0;