Files
UwU-Engine/Core/Delegate/Delegate.h
T
2026-06-22 14:47:53 +07:00

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;
}
}
};