Open arapelle opened 3 years ago
#pragma once
#include <arba/core/memory/intrusive_ref_counter.hpp>
#include <arba/core/memory/intrusive_shared_ptr.hpp>
#include <iostream>
inline namespace arba
{
namespace evnt
{
template <typename... ArgsT>
class signal
{
private:
class abstract_slot_box : public core::intrusive_ref_counter<>
{
public:
virtual ~abstract_slot_box() = default;
virtual void execute(ArgsT... args) = 0;
core::intrusive_shared_ptr<abstract_slot_box> previous, next;
};
using abstract_slot_box_isptr = core::intrusive_shared_ptr<abstract_slot_box>;
class sentinel_slot_box : public abstract_slot_box
{
public:
virtual ~sentinel_slot_box() = default;
virtual void execute(ArgsT...) { std::abort(); }
};
template <class SlotCallbableT>
requires requires(SlotCallbableT& slot, ArgsT... args)
{
{ slot(args...) };
}
class slot_box : public abstract_slot_box
{
public:
explicit slot_box(SlotCallbableT slot) : slot(std::move(slot)) { std::cout << sizeof(*this) << std::endl; }
virtual ~slot_box() override = default;
virtual void execute(ArgsT... args) { slot(args...); }
SlotCallbableT slot;
};
public:
signal();
~signal()
{
clear();
}
void clear()
{
while (slot_list_.next.get() != &slot_list_)
{
slot_list_.next->next->previous.release();
slot_list_.next = std::move(slot_list_.next->next);
}
}
template <class SlotCallbableT>
void connect(SlotCallbableT slot)
{
auto* slot_ptr = new slot_box{ std::move(slot) };
connect_(abstract_slot_box_isptr(slot_ptr));
}
template <class InstanceT, class MemFuncT>
void connect(InstanceT& inst, MemFuncT mem_fn)
{
auto* slot_ptr = new slot_box{ [i_ptr = &inst, mem_fn](ArgsT... args){ (i_ptr->*mem_fn)(args...); } };
connect_(abstract_slot_box_isptr(slot_ptr));
}
void emit(ArgsT... args)
{
abstract_slot_box* first = slot_list_.next.get();
abstract_slot_box* last = &slot_list_;
for (; first != last; first = first->next.get())
first->execute(args...);
}
private:
void connect_(abstract_slot_box_isptr slot_isptr)
{
slot_isptr->next = slot_list_.next;
slot_isptr->next->previous = slot_isptr;
slot_isptr->previous = abstract_slot_box_isptr(&slot_list_);
slot_list_.next = slot_isptr;
}
private:
sentinel_slot_box slot_list_;
};
template <typename... ArgsT>
signal<ArgsT...>::signal()
{
core::intrusive_shared_ptr_add_ref(&slot_list_);
slot_list_.next = core::intrusive_shared_ptr(&slot_list_);
slot_list_.previous = slot_list_.next;
}
}
}
#include "cpprd.hpp"
#include <iostream>
class slot_sv_n
{
public:
void operator()(std::string_view sv, int n)
{
std::cout << "slot_sv_n(): " << sv << " " << n << std::endl;
}
void execute(std::string_view sv, int n)
{
std::cout << "slot_sv_n::execute(): " << sv << " " << n << std::endl;
}
};
void print_sv_n(std::string_view sv, int n)
{
std::cout << "print_sv_n(): " << sv << " " << n << std::endl;
}
int main()
{
evnt::signal<std::string_view, int> source_location_signal;
source_location_signal.connect([](std::string_view sv, int n){ std::cout << "lambda: " << sv << " " << n << std::endl; });
source_location_signal.connect(slot_sv_n());
slot_sv_n sl;
source_location_signal.connect(sl, &slot_sv_n::execute);
source_location_signal.connect(&print_sv_n);
source_location_signal.emit("coucou", 5);
std::cout << "EXIT_SUCCESS" << std::endl;
return EXIT_SUCCESS;
}
Use the famous Fast C++ Delegates:
Fast C++ delegates: https://www.codeproject.com/Articles/1170503/The-Impossibly-Fast-Cplusplus-Delegates-Fixed https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=1170503 https://codereview.stackexchange.com/questions/14730/impossibly-fast-delegate-in-c11 https://www.codeproject.com/articles/11015/the-impossibly-fast-c-delegates
signal benchmark: https://medium.com/@julienjorge/testing-c-signal-slot-libraries-1994eb120826