#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace reactor { // NonCopyable base class class NonCopyable { protected: NonCopyable() = default; ~NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; NonCopyable(NonCopyable&&) noexcept = default; NonCopyable& operator=(NonCopyable&&) noexcept = default; }; // Network byte order utilities inline uint64_t hton64(uint64_t n) { static const int one = 1; static const char sig = *(char*)&one; if (sig == 0) return n; char* ptr = reinterpret_cast(&n); std::reverse(ptr, ptr + sizeof(uint64_t)); return n; } inline uint64_t ntoh64(uint64_t n) { return hton64(n); } // Lock-free MPSC queue using type erasure class LockFreeQueue : public NonCopyable { private: struct Node { Node() = default; template Node(T&& data) : data_(std::make_unique>(std::forward(data))) {} struct Task { virtual ~Task() = default; virtual void call() = 0; }; template struct ConcreteTask : Task { F func_; ConcreteTask(F&& f) : func_(std::forward(f)) {} void call() override { func_(); } }; std::unique_ptr data_; std::atomic next_{nullptr}; }; std::atomic head_; std::atomic tail_; public: LockFreeQueue() : head_(new Node), tail_(head_.load()) {} ~LockFreeQueue() { while (dequeue()) {} delete head_.load(); } template void enqueue(F&& input) { Node* node = new Node(std::forward(input)); Node* prevhead = head_.exchange(node, std::memory_order_acq_rel); prevhead->next_.store(node, std::memory_order_release); } bool dequeue() { Node* tail = tail_.load(std::memory_order_relaxed); Node* next = tail->next_.load(std::memory_order_acquire); if (next == nullptr) return false; if (next->data_) { next->data_->call(); } tail_.store(next, std::memory_order_release); delete tail; return true; } bool empty() { Node* tail = tail_.load(std::memory_order_relaxed); Node* next = tail->next_.load(std::memory_order_acquire); return next == nullptr; } }; // Type-safe lock-free queue for other use cases template class LockFreeQueueTyped : public NonCopyable { private: struct Node { std::atomic data_{nullptr}; std::atomic next_{nullptr}; }; std::atomic head_; std::atomic tail_; public: LockFreeQueueTyped() { Node* dummy = new Node; head_.store(dummy); tail_.store(dummy); } ~LockFreeQueueTyped() { T output; while (dequeue(output)) {} delete head_.load(); } void enqueue(T&& input) { Node* newNode = new Node; T* data = new T(std::move(input)); newNode->data_.store(data); Node* prevHead = head_.exchange(newNode); prevHead->next_.store(newNode); } void enqueue(const T& input) { Node* newNode = new Node; T* data = new T(input); newNode->data_.store(data); Node* prevHead = head_.exchange(newNode); prevHead->next_.store(newNode); } bool dequeue(T& output) { Node* tail = tail_.load(); Node* next = tail->next_.load(); if (next == nullptr) { return false; } T* data = next->data_.load(); if (data == nullptr) { return false; } output = *data; delete data; tail_.store(next); delete tail; return true; } bool empty() { Node* tail = tail_.load(); Node* next = tail->next_.load(); return next == nullptr; } }; // Object Pool template class ObjectPool : public NonCopyable, public std::enable_shared_from_this> { private: std::vector objects_; std::mutex mutex_; public: std::shared_ptr getObject() { static_assert(!std::is_pointer_v, "ObjectPool type cannot be pointer"); T* p = nullptr; { std::lock_guard lock(mutex_); if (!objects_.empty()) { p = objects_.back(); objects_.pop_back(); } } if (!p) p = new T; std::weak_ptr> weakPtr = this->shared_from_this(); return std::shared_ptr(p, [weakPtr](T* ptr) { auto self = weakPtr.lock(); if (self) { std::lock_guard lock(self->mutex_); self->objects_.push_back(ptr); } else { delete ptr; } }); } }; // Simple Logger enum class LogLevel { TRACE, DEBUG, INFO, WARN, ERROR, FATAL }; class Logger : public NonCopyable { private: static inline LogLevel level_ = LogLevel::INFO; static inline std::unique_ptr file_; static inline std::mutex mutex_; std::ostringstream stream_; LogLevel msgLevel_; static const char* levelString(LogLevel level) { switch (level) { case LogLevel::TRACE: return "TRACE"; case LogLevel::DEBUG: return "DEBUG"; case LogLevel::INFO: return "INFO "; case LogLevel::WARN: return "WARN "; case LogLevel::ERROR: return "ERROR"; case LogLevel::FATAL: return "FATAL"; } return "UNKNOWN"; } static std::string timestamp() { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); auto ms = std::chrono::duration_cast( now.time_since_epoch()) % 1000; char buf[64]; std::strftime(buf, sizeof(buf), "%Y%m%d %H:%M:%S", std::localtime(&time_t)); return std::string(buf) + "." + std::to_string(ms.count()); } public: Logger(LogLevel level) : msgLevel_(level) { if (level >= level_) { stream_ << timestamp() << " " << levelString(level) << " "; } } ~Logger() { if (msgLevel_ >= level_) { stream_ << "\n"; std::lock_guard lock(mutex_); if (file_ && file_->is_open()) { *file_ << stream_.str(); file_->flush(); } else { std::cout << stream_.str(); } } } template Logger& operator<<(const T& value) { if (msgLevel_ >= level_) { stream_ << value; } return *this; } static void setLevel(LogLevel level) { level_ = level; } static void setLogFile(const std::string& filename) { std::lock_guard lock(mutex_); file_ = std::make_unique(filename, std::ios::app); } }; class ConcurrentTaskQueue : public NonCopyable { private: std::vector threads_; std::queue> taskQueue_; std::mutex mutex_; std::condition_variable taskCond_; std::atomic stop_; std::string name_; /* * Worker thread function. * Waits for tasks and executes them. */ void workerThread() { while (true) { std::function task; { std::unique_lock lock(mutex_); taskCond_.wait(lock, [this] { return stop_.load() || !taskQueue_.empty(); }); if (stop_.load() && taskQueue_.empty()) { return; } task = std::move(taskQueue_.front()); taskQueue_.pop(); } task(); } } public: ConcurrentTaskQueue(size_t threadNum, const std::string& name = "ConcurrentTaskQueue") : stop_(false), name_(name) { for (size_t i = 0; i < threadNum; ++i) { threads_.emplace_back(&ConcurrentTaskQueue::workerThread, this); } } ~ConcurrentTaskQueue() { { std::lock_guard lock(mutex_); stop_ = true; } taskCond_.notify_all(); for (auto& t : threads_) { if (t.joinable()) t.join(); } } /* * Add a task to the queue. */ template void runTaskInQueue(F&& task) { { std::lock_guard lock(mutex_); if (stop_) return; taskQueue_.emplace(std::forward(task)); } taskCond_.notify_one(); } template void syncTaskInQueue(F&& task) { auto promise = std::make_shared>(); auto future = promise->get_future(); runTaskInQueue([promise, task = std::forward(task)]() mutable { task(); promise->set_value(); }); future.wait(); } std::string getName() const { return name_; } size_t getTaskCount() { std::lock_guard lock(mutex_); return taskQueue_.size(); } }; // Logging macros #define LOG_TRACE reactor::Logger(reactor::LogLevel::TRACE) #define LOG_DEBUG reactor::Logger(reactor::LogLevel::DEBUG) #define LOG_INFO reactor::Logger(reactor::LogLevel::INFO) #define LOG_WARN reactor::Logger(reactor::LogLevel::WARN) #define LOG_ERROR reactor::Logger(reactor::LogLevel::ERROR) #define LOG_FATAL reactor::Logger(reactor::LogLevel::FATAL) // Utility functions template void hashCombine(std::size_t& seed, const T& value) { std::hash hasher; seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } inline std::vector splitString(const std::string& s, const std::string& delimiter) { std::vector result; size_t start = 0; size_t end = s.find(delimiter); while (end != std::string::npos) { result.push_back(s.substr(start, end - start)); start = end + delimiter.length(); end = s.find(delimiter, start); } result.push_back(s.substr(start)); return result; } } // namespace reactor