ass.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #pragma once
  2. /**
  3. * MIT License
  4. *
  5. * Copyright (c) 2019 Michael Cowan
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. */
  25. #include <algorithm>
  26. #include <functional>
  27. #include <vector>
  28. namespace ass {
  29. template<typename... Args>
  30. class Signal;
  31. template<typename... Args>
  32. class Slot final {
  33. friend class Signal<Args...>;
  34. public:
  35. Slot() = default;
  36. explicit Slot(std::function<void(Args...)> callback)
  37. : callback(std::move(callback)) {
  38. }
  39. template<typename T>
  40. Slot(T* instance, void (T::* function)(Args...))
  41. : Slot([=](Args... args) { (instance->*function)(args...); }) {
  42. }
  43. ~Slot() {
  44. disconnectAll();
  45. }
  46. /**
  47. * Copies all connections of other Slot to this Slot.
  48. * @param other Slot to copy connections from.
  49. */
  50. Slot(const Slot& other) {
  51. copyConnectionsFrom(other);
  52. this->callback = other.callback;
  53. }
  54. /**
  55. * Replaces connections of this Slot with connections of other Slot.
  56. * @param other Slot to copy connections from.
  57. * @return Copy assigned instance.
  58. */
  59. Slot& operator=(const Slot& other) {
  60. disconnectAll();
  61. copyConnectionsFrom(other);
  62. this->callback = other.callback;
  63. return *this;
  64. };
  65. /**
  66. * Copies all connections of other Slot to this Slot then disconnects other Slot.
  67. * @param other Slot to copy connections from.
  68. */
  69. Slot(Slot&& other) noexcept {
  70. copyConnectionsFrom(other);
  71. other.disconnectAll();
  72. std::swap(this->callback, other.callback);
  73. }
  74. /**
  75. * Replaces connections of this Slot with connections of other Slot then disconnects other
  76. * Slot.
  77. * @param other Slot to copy connections from.
  78. * @return Move assigned instance.
  79. */
  80. Slot& operator=(Slot&& other) noexcept {
  81. disconnectAll();
  82. copyConnectionsFrom(other);
  83. other.disconnectAll();
  84. std::swap(this->callback, other.callback);
  85. return *this;
  86. }
  87. /**
  88. * Returns the number of connections for this Slot.
  89. *
  90. * @return Number of connections for this Slot.
  91. */
  92. int connectionCount() const {
  93. return signals.size();
  94. }
  95. /**
  96. * Returns true if this Slot is connected to the provided Signal.
  97. *
  98. * @param signal Signal to test connection against.
  99. * @return true if connected.
  100. */
  101. bool isConnectedTo(const Signal<Args...>& signal) const {
  102. return std::find(signals.begin(), signals.end(), &signal) != signals.end();
  103. }
  104. private:
  105. void addSignal(Signal<Args...>& signal) const {
  106. signals.push_back(&signal);
  107. }
  108. void removeSignal(Signal<Args...>& signal) const {
  109. signals.erase(std::remove(signals.begin(), signals.end(), &signal), signals.end());
  110. }
  111. void disconnectAll() {
  112. for (auto* signal : signals) {
  113. signal->removeSlot(*this);
  114. }
  115. signals.clear();
  116. }
  117. void copyConnectionsFrom(const Slot<Args...>& other) {
  118. for (auto* signal : other.signals) {
  119. signal->connect(*this);
  120. }
  121. }
  122. private:
  123. std::function<void(Args...)> callback;
  124. mutable std::vector<Signal<Args...>*> signals;
  125. };
  126. template<typename... Args>
  127. class Signal final {
  128. friend class Slot<Args...>;
  129. public:
  130. Signal() = default;
  131. ~Signal() {
  132. disconnectAll();
  133. }
  134. /**
  135. * Copies all connections of other Signal to this Signal.
  136. * @param other Signal to copy connections from.
  137. */
  138. Signal(const Signal& other) {
  139. copyConnectionsFrom(other);
  140. }
  141. /**
  142. * Replaces connections of this Signal with connections of other Signal.
  143. * @param other Signal to copy connections from.
  144. * @return Copy assigned instance.
  145. */
  146. Signal& operator=(const Signal& other) {
  147. disconnectAll();
  148. copyConnectionsFrom(other);
  149. return *this;
  150. };
  151. /**
  152. * Copies all connections of other Signal to this Signal then disconnects other Signal.
  153. * @param other Signal to copy connections from.
  154. */
  155. Signal(Signal&& other) noexcept {
  156. copyConnectionsFrom(other);
  157. other.disconnectAll();
  158. }
  159. /**
  160. * Replaces connections of this Signal with connections of other Signal then disconnects other
  161. * Signal.
  162. * @param other Signal to copy connections from.
  163. * @return Move assigned instance.
  164. */
  165. Signal& operator=(Signal&& other) noexcept {
  166. disconnectAll();
  167. copyConnectionsFrom(other);
  168. other.disconnectAll();
  169. return *this;
  170. }
  171. /**
  172. * Calls function(s) of the connected Slot(s).
  173. * @param args Arguments to pass to the Slot functions.
  174. */
  175. void emit(Args... args) {
  176. for (auto* slot : slots) {
  177. slot->callback(std::forward<Args>(args)...);
  178. }
  179. }
  180. /**
  181. * Connects this Signal to the provided Slot unless already connected.
  182. *
  183. * @param slot Slot to connect this Signal to.
  184. */
  185. void connect(const Slot<Args...>& slot) {
  186. if (!isConnectedTo(slot)) {
  187. slots.push_back(&slot);
  188. slot.addSignal(*this);
  189. }
  190. }
  191. /**
  192. * Disconnects this Signal from the provided Slot if connected.
  193. *
  194. * @param slot Slot to disconnect this Signal from.
  195. */
  196. void disconnect(const Slot<Args...>& slot) {
  197. this->removeSlot(slot);
  198. slot.removeSignal(*this);
  199. }
  200. /**
  201. * Disconnects this Signal from all connected Slot.
  202. */
  203. void disconnectAll() {
  204. for (auto* slot : slots) {
  205. slot->removeSignal(*this);
  206. }
  207. slots.clear();
  208. }
  209. /**
  210. * Returns the number of connections for this Signal.
  211. *
  212. * @return Number of connections for this Signal.
  213. */
  214. int connectionCount() const {
  215. return slots.size();
  216. }
  217. /**
  218. * Returns true if this Signal is connected to the provided Slot.
  219. *
  220. * @param slot Slot to test connection against.
  221. * @return true if connected.
  222. */
  223. bool isConnectedTo(const Slot<Args...>& slot) const {
  224. return std::find(slots.begin(), slots.end(), &slot) != slots.end();
  225. }
  226. private:
  227. void removeSlot(const Slot<Args...>& slot) {
  228. slots.erase(std::remove(slots.begin(), slots.end(), &slot), slots.end());
  229. }
  230. void copyConnectionsFrom(const Signal<Args...>& other) {
  231. for (auto* slot : other.slots) {
  232. this->connect(*slot);
  233. }
  234. }
  235. private:
  236. std::vector<const Slot<Args...>*> slots;
  237. };
  238. }