1 #pragma once 2 3 #include <algorithm> // for std::remove_if 4 #include <cinttypes> 5 #include <memory> 6 #include <utility> 7 #include <vector> 8 9 namespace scx { 10 11 namespace signal { 12 13 template<class> 14 class MuteSignal; 15 16 template<class R, class... P> 17 class MuteSignal<R(P...)> 18 { 19 using RawFunction = R (*)(P...); 20 21 private: 22 struct Slot; 23 24 public: 25 MuteSignal() = default; 26 ~MuteSignal() = default; 27 28 MuteSignal(const MuteSignal&) = delete; 29 MuteSignal(MuteSignal&&) = delete; 30 MuteSignal& operator=(const MuteSignal&) = delete; 31 MuteSignal& operator=(MuteSignal&&) = delete; 32 33 template<class... Args> Connect(Args &&...args)34 uintptr_t Connect(Args&&... args) 35 { 36 auto slot = MakeSlot(std::forward<Args>(args)...); 37 auto id = reinterpret_cast<uintptr_t>(slot.get()); 38 _slots.push_back(std::move(slot)); 39 return id; 40 } 41 Disconnect(uintptr_t id)42 bool Disconnect(uintptr_t id) 43 { 44 for (size_t i = 0; i < _slots.size(); ++i) { 45 auto thatId = reinterpret_cast<uintptr_t>(_slots[i].get()); 46 if (thatId == id) { 47 _slots.erase(_slots.begin() + i); 48 return true; 49 } 50 } 51 return false; 52 } 53 Disconnect(RawFunction fn)54 bool Disconnect(RawFunction fn) 55 { 56 bool hit = false; 57 EraseIf([&hit, fn](const auto& slot) { 58 if (slot->type == SlotType::RawFunction) { 59 auto that = static_cast<RawFunctionSlot*>(slot.get()); 60 if (that->fn == fn) { 61 hit = true; 62 return true; 63 } 64 } 65 return false; 66 }); 67 return hit; 68 } 69 70 template<class O> Disconnect(O * obj)71 bool Disconnect(O* obj) 72 { 73 bool hit = false; 74 EraseIf([&hit, obj](const auto& slot) { 75 if (slot->type == SlotType::MemberFunction) { 76 auto that = dynamic_cast<MemberFunctionSlot<O>*>(slot.get()); 77 if (that && that->obj == obj) { 78 hit = true; 79 return true; 80 } 81 } 82 return false; 83 }); 84 return hit; 85 } 86 87 template<class F, class O> Disconnect(F fn,O * obj)88 bool Disconnect(F fn, O* obj) 89 { 90 bool hit = false; 91 EraseIf([&hit, fn, obj](const auto& slot) { 92 if (slot->type == SlotType::MemberFunction) { 93 auto that = dynamic_cast<SignedMemberFunctionSlot<F, O>*>(slot.get()); 94 if (that && that->obj == obj && that->fn == fn) { 95 hit = true; 96 return true; 97 } 98 } 99 return false; 100 }); 101 return hit; 102 } 103 Clear()104 void Clear() { _slots.clear(); } 105 Empty()106 auto Empty() const { return _slots.empty(); } 107 Size()108 auto Size() const { return _slots.size(); } 109 110 protected: 111 std::vector<std::unique_ptr<Slot>> _slots; 112 113 private: 114 template<typename Pred> EraseIf(Pred && pred)115 void EraseIf(Pred&& pred) 116 { 117 _slots.erase(std::remove_if(_slots.begin(), _slots.end(), std::forward<Pred>(pred)), _slots.end()); 118 } 119 120 enum class SlotType : uint8_t 121 { 122 Function, 123 RawFunction, 124 MemberFunction 125 }; 126 127 struct Slot 128 { SlotSlot129 explicit Slot(SlotType type) 130 : type(type) 131 { 132 } 133 ~SlotSlot134 virtual ~Slot() {} 135 virtual R Invoke(P...) const = 0; 136 137 const SlotType type; 138 }; 139 140 template<class F> 141 struct FunctionSlot : public Slot 142 { FunctionSlotFunctionSlot143 FunctionSlot(const F& fn) 144 : Slot(SlotType::Function) 145 , fn(fn) 146 { 147 } 148 FunctionSlotFunctionSlot149 FunctionSlot(F&& fn) 150 : Slot(SlotType::Function) 151 , fn(std::move(fn)) 152 { 153 } 154 InvokeFunctionSlot155 R Invoke(P... p) const final { return fn(p...); } 156 157 F const fn; 158 }; 159 160 struct RawFunctionSlot : public Slot 161 { RawFunctionSlotRawFunctionSlot162 explicit RawFunctionSlot(RawFunction fn) 163 : Slot(SlotType::RawFunction) 164 , fn(fn) 165 { 166 } 167 InvokeRawFunctionSlot168 R Invoke(P... p) const final { return fn(p...); } 169 170 RawFunction const fn; 171 }; 172 173 template<class O> 174 struct MemberFunctionSlot : public Slot 175 { MemberFunctionSlotMemberFunctionSlot176 explicit MemberFunctionSlot(O* obj) 177 : Slot(SlotType::MemberFunction) 178 , obj(obj) 179 { 180 } 181 182 O* const obj; 183 }; 184 185 template<class F, class O> 186 struct SignedMemberFunctionSlot : public MemberFunctionSlot<O> 187 { SignedMemberFunctionSlotSignedMemberFunctionSlot188 SignedMemberFunctionSlot(F fn, O* obj) 189 : MemberFunctionSlot<O>(obj) 190 , fn(fn) 191 { 192 } 193 InvokeSignedMemberFunctionSlot194 R Invoke(P... p) const final { return (this->obj->*fn)(p...); } 195 196 F const fn; 197 }; 198 MakeSlot(RawFunction f)199 static auto MakeSlot(RawFunction f) { return std::make_unique<RawFunctionSlot>(f); } 200 201 template<class F, class O> MakeSlot(F f,O * o)202 static auto MakeSlot(F f, O* o) 203 { 204 return std::make_unique<SignedMemberFunctionSlot<F, O>>(f, o); 205 } 206 207 template<class F> MakeSlot(F && f)208 static auto MakeSlot(F&& f) 209 { 210 return std::make_unique<FunctionSlot<std::decay_t<F>>>(std::forward<F>(f)); 211 } 212 }; 213 214 template<class R> 215 class LastValueCollector 216 { 217 public: 218 void operator+=(const R& val) { this->val = val; } 219 220 void operator+=(R&& val) { this->val = std::move(val); } 221 operator()222 R& operator()() { return val; } 223 224 private: 225 R val; 226 }; 227 228 } // namespace signal 229 230 template<class, template<class> class Collector = signal::LastValueCollector> 231 class Signal; 232 233 template<class R, class... P, template<class> class Collector> 234 class Signal<R(P...), Collector> : public signal::MuteSignal<R(P...)> 235 { 236 public: operator()237 R operator()(P... p) const 238 { 239 Collector<R> collector; 240 for (size_t i = 0; i < this->_slots.size(); ++i) { 241 collector += this->_slots[i]->Invoke(p...); 242 } 243 return std::move(collector()); 244 } 245 }; 246 247 template<class... P> 248 class Signal<void(P...)> : public signal::MuteSignal<void(P...)> 249 { 250 public: operator()251 void operator()(P... p) const 252 { 253 for (size_t i = 0; i < this->_slots.size(); ++i) { 254 this->_slots[i]->Invoke(p...); 255 } 256 } 257 }; 258 259 } // namespace scx 260