Created
July 21, 2018 05:01
-
-
Save kvk1920/4a5ed144648f6546492634c98200604c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by kvk1920 on 21.07.18. | |
// | |
/** | |
*Слотов пока нет, но будут. | |
*/ | |
#ifndef MYSTL_SIGSLOTS_H | |
#define MYSTL_SIGSLOTS_H | |
#include <forward_list> | |
#include <utility> | |
#include <functional> | |
#include <algorithm> | |
#include <variant> | |
namespace sigslots_tools { | |
class Abstract {}; | |
using Object = Abstract*; | |
template <typename ...Args> | |
using Method = void (Abstract::*)(Args...); | |
template <typename ...Args> | |
using Delegate = std::pair<Object, Method<Args...>>; | |
template <class Class, typename ...Args> | |
inline Delegate<Args...> makeDelegate(Class* object, | |
void (Class::*method)(Args...)) { | |
return { | |
reinterpret_cast<Object>(object), | |
reinterpret_cast<Method<Args...>>(method) | |
}; | |
} | |
template <typename ...Args> | |
inline void call(const Delegate<Args...>& delegate, Args&& ...args) { | |
(delegate.first->*delegate.second)(std::forward<Args>(args)...); | |
} | |
template <typename ...Args> | |
using Function = void (*)(Args...); | |
template <typename ...Args> | |
inline void call(const Function<Args...>& function, Args&& ...args) { | |
function(std::forward<Args>(args)...); | |
} | |
template <typename ...Args> | |
using CallableObject = std::variant<Function<Args...>, Delegate<Args...>>; | |
template <class Class, typename ...Args> | |
inline CallableObject<Args...> makeCallableObject( | |
Class* object, | |
void (Class::*method)(Args...)) | |
{ return makeDelegate(object, method); } | |
template <typename ...Args> | |
inline CallableObject<Args...> makeCallableObject(const Function<Args...>& function) { return function; } | |
template <typename ...Args> | |
inline void call(const CallableObject<Args...>& callable_object, Args&& ...args) { | |
if (std::holds_alternative<Function<Args...>>(callable_object)) | |
call(std::get<Function<Args...>>(callable_object), std::forward<Args>(args)...); | |
else | |
call(std::get<Delegate<Args...>>(callable_object), std::forward<Args>(args)...); | |
} | |
template <typename ...Args> | |
class signal { | |
private: | |
std::forward_list<CallableObject<Args...>> slots; | |
size_t size; | |
bool connect(const CallableObject<Args...>& callable_object) { | |
if (std::find(slots.begin(), slots.end(), callable_object) == slots.end()) { | |
slots.push_front(callable_object); | |
++size; | |
return true; | |
} | |
return false; | |
} | |
bool disconnect(const CallableObject<Args...>& callable_object) { | |
auto target = std::find(slots.begin(), slots.end(), callable_object); | |
if (target != slots.end()) { | |
std::swap(*target, *slots.begin()); | |
slots.pop_front(); | |
--size; | |
return true; | |
} | |
return false; | |
} | |
public: | |
void emit(Args&& ...args) { | |
for (const auto& delegate : slots) | |
call(delegate, std::forward<Args>(args)...); | |
} | |
template <class Class> | |
bool connect(Class* object, void (Class::*method)(Args...)) { | |
return connect(makeCallableObject(object, method)); | |
} | |
bool connect(void (*method)(Args...)) { | |
return connect(makeCallableObject(method)); | |
} | |
template <class Class> | |
bool disconnect(Class* object, void (Class::*method)(Args...)) { | |
return disconnect(makeCallableObject(object, method)); | |
} | |
bool disconnect(void (*method)(Args...)) { | |
return disconnect(makeCallableObject(method)); | |
} | |
std::size_t number_of_slots() const { return size; } | |
}; | |
} | |
using sigslots_tools::signal; | |
#endif //MYSTL_SIGSLOTS_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment