tiny_signal.hpp 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #ifndef SOPHIAR2_TINY_SIGNAL_HPP
  2. #define SOPHIAR2_TINY_SIGNAL_HPP
  3. #include <boost/intrusive/list.hpp>
  4. #include <cassert>
  5. #include <type_traits>
  6. #include <utility>
  7. namespace sophiar {
  8. using slot_hook_type = boost::intrusive::list_base_hook<
  9. boost::intrusive::link_mode<
  10. boost::intrusive::auto_unlink>>;
  11. struct tiny_slot_base : public slot_hook_type {
  12. bool is_enabled = true;
  13. virtual ~tiny_slot_base() = default;
  14. void disconnect() {
  15. assert(this->is_linked());
  16. this->unlink();
  17. }
  18. };
  19. struct tiny_signal_base {
  20. virtual ~tiny_signal_base() = default;
  21. virtual void add_slot_base(tiny_slot_base *slot_base) = 0;
  22. };
  23. template<typename... Args>
  24. class tiny_signal : public tiny_signal_base {
  25. public:
  26. class slot_type : public tiny_slot_base {
  27. public:
  28. void signal_received(Args... args) {
  29. if (!is_enabled) return;
  30. on_signal_received(std::move(args)...);
  31. }
  32. protected:
  33. virtual void on_signal_received(Args... args) = 0;
  34. };
  35. void add_slot_base(tiny_slot_base *slot_base) override {
  36. auto slot_ptr = dynamic_cast<slot_type *>(slot_base);
  37. assert(slot_ptr != nullptr);
  38. slot_list.push_back(*slot_ptr);
  39. }
  40. void emit(Args... args) {
  41. auto iter = slot_list.begin(), iter_end = slot_list.end();
  42. while (iter != iter_end) {
  43. auto this_iter = iter++;
  44. if (iter == iter_end) {
  45. this_iter->signal_received(std::move(args)...);
  46. } else {
  47. this_iter->signal_received(args...);
  48. }
  49. }
  50. }
  51. private:
  52. using slot_list_type = boost::intrusive::list<
  53. slot_type, boost::intrusive::constant_time_size<false>>;
  54. slot_list_type slot_list;
  55. };
  56. }
  57. #endif //SOPHIAR2_TINY_SIGNAL_HPP