#pragma once #include #include #include #include #include #include namespace ts { namespace event { class EventExecutor; class EventEntry { friend class EventExecutor; public: virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0; private: void* _event_ptr = nullptr; }; template class ProxiedEventEntry : public event::EventEntry { public: using callback_t = void(class_t::*)(const std::chrono::system_clock::time_point &); ProxiedEventEntry(const std::shared_ptr& _instance, callback_t callback) : instance(_instance), callback(callback) { } std::weak_ptr instance; callback_t callback; void event_execute(const std::chrono::system_clock::time_point &point) override { auto _instance = this->instance.lock(); if(!_instance) return; ((void(*)(class_t*, const std::chrono::system_clock::time_point &)) this->callback)(&*_instance, point); } }; class EventExecutor { public: explicit EventExecutor(const std::string& /* thread prefix */); virtual ~EventExecutor(); bool initialize(int /* num threads */); bool schedule(const std::shared_ptr& /* entry */); bool cancel(const std::shared_ptr& /* entry */); /* Note: Will not cancel already running executes */ void shutdown(); inline const std::string& thread_prefix() const { return this->_thread_prefix; } void threads(int /* num threads */); inline int threads() const { return this->target_threads; } private: struct LinkedEntry { LinkedEntry* previous; LinkedEntry* next; std::chrono::system_clock::time_point scheduled; std::weak_ptr entry; }; static void _executor(EventExecutor*); void _spawn_executor(std::unique_lock&); void _shutdown(std::unique_lock&); void _reset_events(std::unique_lock&); #ifndef WIN32 void _reassign_thread_names(std::unique_lock&); #endif bool should_shutdown = true; bool should_adjust = false; /* thread adjustments */ int target_threads = 0; std::vector _threads; std::mutex lock; std::condition_variable condition; LinkedEntry* head = nullptr; LinkedEntry* tail = nullptr; std::string _thread_prefix; }; } }