Skip to content

Instantly share code, notes, and snippets.

@kvk1920
Created July 21, 2018 05:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kvk1920/4a5ed144648f6546492634c98200604c to your computer and use it in GitHub Desktop.
Save kvk1920/4a5ed144648f6546492634c98200604c to your computer and use it in GitHub Desktop.
//
// 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