Guest User

Untitled

a guest
Jun 24th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.89 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <algorithm>
  4. #include <functional>
  5. #include <tuple>
  6. #include <utility>
  7. #include <vector>
  8.  
  9. template<typename... Args>
  10. class Event {
  11. public:
  12. using cb_t = std::function<void(Args...)>;
  13. struct event_t {
  14. cb_t cb{};
  15. std::tuple<Args...> args;
  16. event_t(const cb_t& cb, Args... args) : cb(cb), args(std::forward_as_tuple<Args...>(std::decay_t<Args>(args)...)) { }
  17. bool operator==(const event_t& rhs) {
  18. //Test pointer then signature
  19. return (this->cb.target_type().hash_code() == rhs.cb.target_type().hash_code())
  20. || (this->args == rhs.args);
  21. }
  22. };
  23. Event() = default;
  24. ~Event() = default;
  25.  
  26. void Subscribe(const cb_t& cb, Args... args) {
  27. event_t sub(cb, args...);
  28. Subscribe(sub);
  29. }
  30.  
  31. void Unsubscribe(const cb_t& cb) {
  32. _subscribers.erase(
  33. std::remove_if(
  34. std::begin(_subscribers),
  35. std::end(_subscribers),
  36. [&cb](const event_t& e) {
  37. return (cb.target_type().hash_code() == e.cb.target_type().hash_code());
  38. }),
  39. std::end(_subscribers));
  40. }
  41.  
  42. void Trigger() const {
  43. for(auto& s : _subscribers) {
  44. std::apply(s.cb, s.args); //REQUIRES C++17
  45. }
  46. }
  47.  
  48. protected:
  49. private:
  50. std::vector<event_t> _subscribers{};
  51.  
  52. void Subscribe(const event_t& cb) {
  53. auto found = std::find(std::begin(_subscribers), std::end(_subscribers), cb);
  54. if(found == std::end(_subscribers)) {
  55. _subscribers.push_back(cb);
  56. }
  57. }
  58.  
  59. void Unsubscribe(const event_t& cb) {
  60. auto found = std::find(std::begin(_subscribers), std::end(_subscribers), cb);
  61. if(found != std::end(_subscribers)) {
  62. std::iter_swap(found, _subscribers.end() - 1);
  63. _subscribers.pop_back();
  64. }
  65. }
  66.  
  67. };
  68.  
  69. //Specialization to get Event<void> to work
  70. template<>
  71. class Event<void> : public Event<> { };
  72.  
  73. #include "Event.hpp"
  74. #include <iostream>
  75. #include <string>
  76.  
  77. Event<> OnThing1; //Event signature takes no arguments
  78. Event<void> OnThing2; //Ditto
  79. Event<std::string> OnThing3; //Event signature takes a std::string
  80. Event<std::string, int> OnThing4; //Event signature takes a std::string and an int
  81.  
  82. //...
  83.  
  84. void MyCallbackFunction1() { std::cout << "Hi from MCF1!n"; }
  85. void MyCallbackFunction2() { std::cout << "Hi from MCF2!n"; }
  86. void MyCallbackFunction3(const std::string& str) { std::cout << "MCF3 says " << str << "!n"; }
  87. void MyCallbackFunction4(const std::string& str, int i) { std::cout << "MCF4 says " << str << " and " << i << "!n"; }
  88.  
  89. int main() {
  90.  
  91. OnThing1.Subscribe(MyCallbackFunction1);
  92. OnThing1.Subscribe(MyCallbackFunction2); //Uh-oh! Same signature as MCF1, does not get subscribed!
  93. OnThing2.Subscribe(MyCallbackFunction2); //Okay because it's on a different Event
  94. OnThing3.Subscribe(MyCallbackFunction3, std::string("Hello World"));
  95. OnThing3.Subscribe([](const std::string& str){ std::cout << str << 'n'; }, std::string("Hello Lambda")); //Can be Subscribed because the internal representation of the signature is not the same.
  96. OnThing4.Subscribe(MyCallbackFunction4, std::string("Hello World"), 1);
  97.  
  98. //...
  99.  
  100. OnThing1.Trigger(); //Calls MCF1 but not MCF2
  101. OnThing2.Trigger(); //Calls MCF2
  102. OnThing3.Trigger(); //Calls MCF3 and the lambda
  103. OnThing4.Trigger(); //Calls MCF4
  104.  
  105. //...
  106.  
  107. OnThing1.Unsubscribe(MyCallbackFunction1);
  108. OnThing1.Unsubscribe(MyCallbackFunction2); //MCF2 was never registered in the first place.
  109. OnThing2.Unsubscribe(MyCallbackFunction2);
  110. OnThing3.Unsubscribe(MyCallbackFunction3);
  111. //Lambda can not be unsubscribed because there is no way to get the type information. Re-creating the lambda will result in a different signature.
  112. OnThing4.Unsubscribe(MyCallbackFunction4);
  113. }
  114.  
  115. Hi from MCF1!
  116. Hi from MCF2!
  117. MCF3 says Hello World!
  118. Hello Lambda
  119. MCF4 says Hello World and 1
Add Comment
Please, Sign In to add comment