Reactor/lib/Utilities.hpp
2025-06-27 18:01:00 -05:00

347 lines
7.7 KiB
C++

#pragma once
#include <future>
#include <string>
#include <memory>
#include <functional>
#include <atomic>
#include <vector>
#include <queue>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
#include <fstream>
#include <chrono>
#include <type_traits>
#include <algorithm>
#include <cstring>
#include <netinet/in.h>
#include <sstream>
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<char*>(&n);
std::reverse(ptr, ptr + sizeof(uint64_t));
return n;
}
inline uint64_t ntoh64(uint64_t n) { return hton64(n); }
// Lock-free MPSC queue
template<typename T>
class LockFreeQueue : public NonCopyable
{
private:
struct Node
{
Node() = default;
Node(const T& data) : data_(std::make_unique<T>(data)) {}
Node(T&& data) : data_(std::make_unique<T>(std::move(data))) {}
std::unique_ptr<T> data_;
std::atomic<Node*> next_{nullptr};
};
std::atomic<Node*> head_;
std::atomic<Node*> tail_;
public:
LockFreeQueue() : head_(new Node), tail_(head_.load()) {}
~LockFreeQueue()
{
T output;
while (dequeue(output)) {}
delete head_.load();
}
void enqueue(T&& input)
{
Node* node = new Node(std::move(input));
Node* prevhead = head_.exchange(node, std::memory_order_acq_rel);
prevhead->next_.store(node, std::memory_order_release);
}
void enqueue(const T& input)
{
Node* node = new Node(input);
Node* prevhead = head_.exchange(node, std::memory_order_acq_rel);
prevhead->next_.store(node, std::memory_order_release);
}
bool dequeue(T& output)
{
Node* tail = tail_.load(std::memory_order_relaxed);
Node* next = tail->next_.load(std::memory_order_acquire);
if (next == nullptr) return false;
output = std::move(*next->data_);
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;
}
};
// Object Pool
template<typename T>
class ObjectPool : public NonCopyable, public std::enable_shared_from_this<ObjectPool<T>>
{
private:
std::vector<T*> objects_;
std::mutex mutex_;
public:
std::shared_ptr<T> getObject()
{
static_assert(!std::is_pointer_v<T>, "ObjectPool type cannot be pointer");
T* p = nullptr;
{
std::lock_guard<std::mutex> lock(mutex_);
if (!objects_.empty()) {
p = objects_.back();
objects_.pop_back();
}
}
if (!p) p = new T;
std::weak_ptr<ObjectPool<T>> weakPtr = this->shared_from_this();
return std::shared_ptr<T>(p, [weakPtr](T* ptr) {
auto self = weakPtr.lock();
if (self) {
std::lock_guard<std::mutex> 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<std::ofstream> 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<std::chrono::milliseconds>(
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<std::mutex> lock(mutex_);
if (file_ && file_->is_open()) {
*file_ << stream_.str();
file_->flush();
} else {
std::cout << stream_.str();
}
}
}
template<typename T>
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<std::mutex> lock(mutex_);
file_ = std::make_unique<std::ofstream>(filename, std::ios::app);
}
};
// Task Queue interface
class TaskQueue : public NonCopyable
{
public:
virtual ~TaskQueue() = default;
virtual void runTaskInQueue(const std::function<void()>& task) = 0;
virtual void runTaskInQueue(std::function<void()>&& task) = 0;
virtual std::string getName() const { return ""; }
void syncTaskInQueue(const std::function<void()>& task)
{
std::promise<void> promise;
auto future = promise.get_future();
runTaskInQueue([&]() {
task();
promise.set_value();
});
future.wait();
}
};
// Concurrent Task Queue
class ConcurrentTaskQueue : public TaskQueue
{
private:
std::vector<std::thread> threads_;
std::queue<std::function<void()>> taskQueue_;
std::mutex taskMutex_;
std::condition_variable taskCond_;
std::atomic<bool> stop_{false};
std::string name_;
void workerThread(int threadId)
{
while (!stop_) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(taskMutex_);
taskCond_.wait(lock, [this]() { return stop_ || !taskQueue_.empty(); });
if (taskQueue_.empty()) continue;
task = std::move(taskQueue_.front());
taskQueue_.pop();
}
task();
}
}
public:
ConcurrentTaskQueue(size_t threadNum, const std::string& name = "ConcurrentTaskQueue")
: name_(name)
{
for (size_t i = 0; i < threadNum; ++i) {
threads_.emplace_back(&ConcurrentTaskQueue::workerThread, this, i);
}
}
~ConcurrentTaskQueue()
{
stop_ = true;
taskCond_.notify_all();
for (auto& t : threads_) {
if (t.joinable()) t.join();
}
}
void runTaskInQueue(const std::function<void()>& task) override
{
std::lock_guard<std::mutex> lock(taskMutex_);
taskQueue_.push(task);
taskCond_.notify_one();
}
void runTaskInQueue(std::function<void()>&& task) override
{
std::lock_guard<std::mutex> lock(taskMutex_);
taskQueue_.push(std::move(task));
taskCond_.notify_one();
}
std::string getName() const override { return name_; }
size_t getTaskCount()
{
std::lock_guard<std::mutex> lock(taskMutex_);
return taskQueue_.size();
}
};
// Logging macros
#define LOG_TRACE Logger(LogLevel::TRACE)
#define LOG_DEBUG Logger(LogLevel::DEBUG)
#define LOG_INFO Logger(LogLevel::INFO)
#define LOG_WARN Logger(LogLevel::WARN)
#define LOG_ERROR Logger(LogLevel::ERROR)
#define LOG_FATAL Logger(LogLevel::FATAL)
// Utility functions
template<typename T>
void hashCombine(std::size_t& seed, const T& value)
{
std::hash<T> hasher;
seed ^= hasher(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
inline std::vector<std::string> splitString(const std::string& s, const std::string& delimiter)
{
std::vector<std::string> 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