#include "util/types.hpp" #include #include // Thread-safe object pool with garbage collection class universal_pool { public: universal_pool(u32 gc_interval = 10000) : gc_interval(gc_interval) { } ~universal_pool() { std::lock_guard lock(mutex); storage.clear(); } universal_pool(const universal_pool&) = delete; universal_pool& operator=(const universal_pool&) = delete; void set_gc_interval(u32 new_val) { gc_interval = new_val; } template requires (std::invocable && std::is_same_v, std::shared_ptr>) void add_op(F func) { std::lock_guard lock(mutex); if (std::shared_ptr new_val = std::invoke(func); new_val) { storage.push_back(new_val); } delete_unused(); } void force_gc() { std::lock_guard lock(mutex); delete_unused(); } private: void delete_unused() { const u32 gc_int = gc_interval.observe(); if (u64 crnt_time = get_system_time(); gc_int == 0 || crnt_time > gc_last_time + gc_int) { gc_last_time = crnt_time; storage.erase ( std::remove_if(storage.begin(), storage.end(), [](auto& obj) { return obj.use_count() <= 1; }), storage.end() ); } } shared_mutex mutex{}; std::vector> storage{}; u64 gc_last_time = get_system_time(); atomic_t gc_interval = 0; }; template class transactional_storage { public: transactional_storage(std::shared_ptr pool, std::shared_ptr obj = std::make_shared()) { ensure(pool && obj); this->pool = pool; add(obj); } transactional_storage(const transactional_storage&) = delete; transactional_storage& operator=(const transactional_storage&) = delete; transactional_storage(transactional_storage&& other) { pool = std::move(other.pool); std::unique_lock lock_other{other.current_mutex}; const std::shared_ptr other_current = other.current; other.current = nullptr; lock_other.unlock(); std::lock_guard lock{current_mutex}; current = other_current; } transactional_storage& operator=(transactional_storage&& other) { if (this == &other) return *this; pool = std::move(other.pool); std::unique_lock lock_other{other.current_mutex}; const std::shared_ptr other_current = other.current; other.current = nullptr; lock_other.unlock(); std::lock_guard lock{current_mutex}; current = other_current; return *this; } std::shared_ptr get_current() { reader_lock lock(current_mutex); return current; } void add(std::shared_ptr obj) { if (!obj) { return; } pool->add_op([&]() -> std::shared_ptr { { std::lock_guard lock{current_mutex}; current = obj; } return std::move(obj); }); } template requires (std::invocable && std::is_same_v, std::shared_ptr>) void add_op(F func) { pool->add_op([&]() -> std::shared_ptr { std::shared_ptr obj = std::invoke(func); if (obj) { std::lock_guard lock{current_mutex}; current = obj; } return obj; }); } private: shared_mutex current_mutex{}; std::shared_ptr current{}; std::shared_ptr pool{}; };