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