diff options
Diffstat (limited to 'include/cru/common')
-rw-r--r-- | include/cru/common/Base.h | 2 | ||||
-rw-r--r-- | include/cru/common/Format.h | 4 | ||||
-rw-r--r-- | include/cru/common/Logger.h | 114 | ||||
-rw-r--r-- | include/cru/common/String.h | 2 | ||||
-rw-r--r-- | include/cru/common/concurrent/ConcurrentQueue.h | 110 | ||||
-rw-r--r-- | include/cru/common/log/Logger.h | 88 | ||||
-rw-r--r-- | include/cru/common/log/StdioLogTarget.h | 17 |
7 files changed, 219 insertions, 118 deletions
diff --git a/include/cru/common/Base.h b/include/cru/common/Base.h index 4d4d1f5f..899cfc13 100644 --- a/include/cru/common/Base.h +++ b/include/cru/common/Base.h @@ -94,5 +94,5 @@ inline void hash_combine(std::size_t& s, const T& v) { #define CRU_DEFINE_CLASS_LOG_TAG(tag) \ private: \ - constexpr static StringView log_tag = tag; + constexpr static const char16_t* kLogTag = tag; } // namespace cru diff --git a/include/cru/common/Format.h b/include/cru/common/Format.h index 7628f07d..2b08f03b 100644 --- a/include/cru/common/Format.h +++ b/include/cru/common/Format.h @@ -92,7 +92,7 @@ struct FormatToken { String place_holder_option; }; -std::vector<FormatToken> CRU_BASE_API ParseToFormatTokenList(const String& str); +std::vector<FormatToken> CRU_BASE_API ParseToFormatTokenList(StringView str); void CRU_BASE_API FormatAppendFromFormatTokenList( String& current, const std::vector<FormatToken>& format_token_list, @@ -123,7 +123,7 @@ void FormatAppendFromFormatTokenList( } // namespace details template <typename... T> -String Format(const String& format, T&&... args) { +String Format(StringView format, T&&... args) { String result; details::FormatAppendFromFormatTokenList( diff --git a/include/cru/common/Logger.h b/include/cru/common/Logger.h deleted file mode 100644 index 25875651..00000000 --- a/include/cru/common/Logger.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once -#include "Base.h" - -#include "String.h" -#include "Format.h" - -#include <list> -#include <memory> - -namespace cru::log { - -enum class LogLevel { Debug, Info, Warn, Error }; - -struct CRU_BASE_API ILogSource : virtual Interface { - // Write the string s. LogLevel is just a helper. It has no effect on the - // content to write. - virtual void Write(LogLevel level, StringView s) = 0; -}; - -class CRU_BASE_API Logger : public Object { - public: - static Logger* GetInstance(); - - public: - Logger() = default; - - CRU_DELETE_COPY(Logger) - CRU_DELETE_MOVE(Logger) - - ~Logger() override = default; - - public: - void AddSource(std::unique_ptr<ILogSource> source); - void RemoveSource(ILogSource* source); - - public: - void Log(LogLevel level, StringView message); - void Log(LogLevel level, StringView tag, StringView message); - - private: - std::list<std::unique_ptr<ILogSource>> sources_; -}; - -// TODO: Remove argument evaluation in Debug. -template <typename... TArgs> -void Debug([[maybe_unused]] TArgs&&... args) { -#ifdef CRU_DEBUG - Logger::GetInstance()->Log(LogLevel::Debug, - Format(std::forward<TArgs>(args)...)); -#endif -} - -template <typename... TArgs> -void Info(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Info, - Format(std::forward<TArgs>(args)...)); -} - -template <typename... TArgs> -void Warn(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Warn, - Format(std::forward<TArgs>(args)...)); -} - -template <typename... TArgs> -void Error(TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Error, - Format(std::forward<TArgs>(args)...)); -} - -// TODO: Remove argument evaluation in Debug. -template <typename... TArgs> -void TagDebug([[maybe_unused]] StringView tag, - [[maybe_unused]] TArgs&&... args) { -#ifdef CRU_DEBUG - Logger::GetInstance()->Log(LogLevel::Debug, tag, - Format(std::forward<TArgs>(args)...)); -#endif -} - -template <typename... TArgs> -void TagInfo(StringView tag, TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Info, tag, - Format(std::forward<TArgs>(args)...)); -} - -template <typename... TArgs> -void TagWarn(StringView tag, TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Warn, tag, - Format(std::forward<TArgs>(args)...)); -} - -template <typename... TArgs> -void TagError(StringView tag, TArgs&&... args) { - Logger::GetInstance()->Log(LogLevel::Error, tag, - Format(std::forward<TArgs>(args)...)); -} - -class StdioLogSource : public Object, public virtual ILogSource { - public: - explicit StdioLogSource(bool use_lock = false); - - CRU_DELETE_COPY(StdioLogSource) - CRU_DELETE_MOVE(StdioLogSource) - - ~StdioLogSource() override; - - public: - void Write(LogLevel level, StringView s) override; - - private: - bool use_lock_; -}; -} // namespace cru::log diff --git a/include/cru/common/String.h b/include/cru/common/String.h index 0b1b031b..be886168 100644 --- a/include/cru/common/String.h +++ b/include/cru/common/String.h @@ -63,7 +63,7 @@ class CRU_BASE_API String { public: String() = default; - explicit String(const_pointer str); + String(const_pointer str); String(const_pointer str, size_type size); template <Index size> diff --git a/include/cru/common/concurrent/ConcurrentQueue.h b/include/cru/common/concurrent/ConcurrentQueue.h new file mode 100644 index 00000000..4f649a41 --- /dev/null +++ b/include/cru/common/concurrent/ConcurrentQueue.h @@ -0,0 +1,110 @@ +#pragma once +#include <condition_variable> +#include <mutex> +#include <optional> +#include <utility> + +namespace cru::concurrent { +namespace details { +template <typename T> +struct ConcurrentQueueNode { + ConcurrentQueueNode(T&& value, ConcurrentQueueNode* next = nullptr) + : value(std::move(value)), next(next) {} + + T value; + ConcurrentQueueNode* next; +}; +} // namespace details + +template <typename T> +class ConcurrentQueue { + public: + ConcurrentQueue() {} + + ConcurrentQueue(const ConcurrentQueue&) = delete; + ConcurrentQueue& operator=(const ConcurrentQueue&) = delete; + + ConcurrentQueue(ConcurrentQueue&& other) + : head_(other.head_), + tail_(other.tail_), + mutex_(std::move(other.mutex_)), + condition_variable_(std::move(other.condition_variable_)) { + other.head_ = nullptr; + other.tail_ = nullptr; + } + + ConcurrentQueue& operator=(ConcurrentQueue&& other) { + if (this != &other) { + head_ = other.head_; + tail_ = other.tail_; + mutex_ = std::move(other.mutex_); + condition_variable_ = std::move(other.condition_variable_); + other.head_ = nullptr; + other.tail_ = nullptr; + return *this; + } + return *this; + } + + ~ConcurrentQueue() { + if (head_) { + auto node = head_; + while (node) { + auto next = node->next; + delete node; + node = next; + } + } + } + + public: + void Push(T&& value) { + std::unique_lock<std::mutex> lock(mutex_); + if (head_ == nullptr) { + head_ = tail_ = new details::ConcurrentQueueNode<T>(std::move(value)); + condition_variable_.notify_one(); + } else { + tail_->next = new details::ConcurrentQueueNode<T>(std::move(value)); + tail_ = tail_->next; + } + } + + T Pull() { + std::unique_lock<std::mutex> lock(mutex_); + if (head_ == nullptr) { + condition_variable_.wait(lock); + } + assert(head_ != nullptr); + auto value = std::move(head_->value); + auto next = head_->next; + delete head_; + head_ = next; + if (next == nullptr) { + tail_ = nullptr; + } + return value; + } + + std::optional<T> Poll() { + std::unique_lock<std::mutex> lock(mutex_); + if (head_ == nullptr) { + return std::nullopt; + } + auto value = std::move(head_->value); + auto next = head_->next; + delete head_; + head_ = next; + if (next == nullptr) { + tail_ = nullptr; + } + return value; + } + + private: + details::ConcurrentQueueNode<T>* head_ = nullptr; + details::ConcurrentQueueNode<T>* tail_ = nullptr; + + std::mutex mutex_; + std::condition_variable condition_variable_; +}; +} // namespace cru::concurrent diff --git a/include/cru/common/log/Logger.h b/include/cru/common/log/Logger.h new file mode 100644 index 00000000..25735e14 --- /dev/null +++ b/include/cru/common/log/Logger.h @@ -0,0 +1,88 @@ +#pragma once +#include "../Base.h" + +#include "../Format.h" +#include "../String.h" +#include "../concurrent/ConcurrentQueue.h" + +#include <memory> +#include <mutex> +#include <thread> +#include <vector> + +namespace cru::log { +enum class LogLevel { Debug, Info, Warn, Error }; + +struct CRU_BASE_API LogInfo { + LogInfo(LogLevel level, String tag, String message) + : level(level), tag(std::move(tag)), message(std::move(message)) {} + + CRU_DEFAULT_COPY(LogInfo) + CRU_DEFAULT_MOVE(LogInfo) + + ~LogInfo() = default; + + LogLevel level; + String tag; + String message; +}; + +struct CRU_BASE_API ILogTarget : virtual Interface { + // Write the string s. LogLevel is just a helper. It has no effect on the + // content to write. + virtual void Write(LogLevel level, StringView s) = 0; +}; + +class CRU_BASE_API Logger : public Object { + public: + static Logger* GetInstance(); + + public: + Logger(); + + CRU_DELETE_COPY(Logger) + CRU_DELETE_MOVE(Logger) + + ~Logger() override; + + public: + void AddLogTarget(std::unique_ptr<ILogTarget> source); + void RemoveLogTarget(ILogTarget* source); + + public: + void Log(LogLevel level, String tag, String message) { + Log(LogInfo(level, std::move(tag), std::move(message))); + } + void Log(LogInfo log_info); + + template <typename... Args> + void FormatLog(LogLevel level, String tag, StringView format, + Args&&... args) { + Log(level, std::move(tag), Format(format, std::forward<Args>(args)...)); + } + + private: + concurrent::ConcurrentQueue<LogInfo> log_queue_; + + std::mutex target_list_mutex_; + std::vector<std::unique_ptr<ILogTarget>> target_list_; + + std::thread log_thread_; +}; +} // namespace cru::log + +#define CRU_LOG_DEBUG(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Debug, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_INFO(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Info, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_WARN(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Warn, \ + kLogTag, __VA_ARGS__) + +#define CRU_LOG_ERROR(...) \ + cru::log::Logger::GetInstance()->FormatLog(cru::log::LogLevel::Error, \ + kLogTag, __VA_ARGS__) diff --git a/include/cru/common/log/StdioLogTarget.h b/include/cru/common/log/StdioLogTarget.h new file mode 100644 index 00000000..4123766b --- /dev/null +++ b/include/cru/common/log/StdioLogTarget.h @@ -0,0 +1,17 @@ +#pragma once +#include "Logger.h" + +namespace cru::log { +class StdioLogTarget : public Object, public virtual log::ILogTarget { + public: + explicit StdioLogTarget(); + + CRU_DELETE_COPY(StdioLogTarget) + CRU_DELETE_MOVE(StdioLogTarget) + + ~StdioLogTarget() override; + + public: + void Write(log::LogLevel level, StringView s) override; +}; +} // namespace cru::log |