// Create by Jiga228 (https://git.burntroosters.twc1.net/Jiga228) #pragma once #include #include #include /* * Этоот класс по своей сути односвязный список, * каждый элемент которого - подписавшийся объект. * Реализация для случая когда Type_Parameter != void */ template class Delegate { class ObjectWasDelete : public std::runtime_error { public: ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {} }; /* * Базовая структура для записи подптсок */ struct BaseListData { std::shared_ptr next; virtual ~BaseListData() = default; virtual void call(Type_Parameter data) = 0; }; template struct ObjectListData : public BaseListData { using Method = void(Type_Object::*)(Type_Parameter); std::weak_ptr object; Method method = nullptr; ObjectListData() = default; ObjectListData(std::weak_ptr object, Method method) : object(std::move(object)), method(method) {} void call(Type_Parameter data) { if (auto shared_object = object.lock()) { (shared_object.get()->*method)(data); } else { throw ObjectWasDelete(); } } }; struct FunctionListData : public BaseListData { void(*function)(Type_Parameter); FunctionListData() = default; FunctionListData(void(*func)(Type_Parameter)) : function(func) {} void call(Type_Parameter data) { function(data); } }; std::shared_ptr list_head = nullptr; std::mutex m_list; public: template void bind(std::weak_ptr object, void (Type_Object::*method)(Type_Parameter)) { if (!object.expired() && !method) return; std::lock_guard lock(m_list); std::shared_ptr old_head = list_head; list_head = std::make_shared>(object, method); list_head->next = old_head; } void bind(void(*function)(Type_Parameter)) { if (!function) return; std::lock_guard lock(m_list); std::shared_ptr old_head = list_head; list_head = std::make_shared(function); list_head->next = old_head; } template void unbind(std::shared_ptr object, void(Type_Object::*method)(Type_Parameter)) { std::lock_guard lock(m_list); if (!list_head) return; if (auto object_list_data = dynamic_cast*>(list_head.get())) { std::shared_ptr shared_object_list_data = object_list_data->object.lock(); if (!shared_object_list_data) { list_head = list_head->next; } else if (shared_object_list_data == object && object_list_data->method == method) { list_head = list_head->next; return; } } std::shared_ptr old_it = list_head, iterator = list_head->next; while (iterator) { if (auto object_list = dynamic_cast*>(iterator.get())) { if (object_list->object.expired()) old_it->next = iterator->next; if (object_list->object.lock() == object && object_list->method == method) { old_it->next = iterator->next; return; } } old_it = iterator; iterator = iterator->next; } } void unbind(void(*func)(Type_Parameter)) { std::lock_guard lock(m_list); if (!list_head) return; if (auto function_list_data = dynamic_cast(list_head.get())) { if (function_list_data->function == func) { list_head = list_head->next; return; } } std::shared_ptr old_it = list_head, iterator = list_head->next; while (iterator) { if (auto function_list = dynamic_cast(iterator.get())) { if (function_list->function == func) { old_it->next = iterator->next; return; } } iterator = iterator->next; } } void call(Type_Parameter data) { std::lock_guard lock(m_list); std::shared_ptr old_head, iterator = list_head; while(iterator) { try { iterator->call(data); } catch (const ObjectWasDelete&) { if (iterator == list_head) { list_head = list_head->next; } else { old_head->next = iterator->next; } } iterator = iterator->next; } } };