#include <cstddef>
#include <vector>
#include <list>
+#include <unordered_map>
#include <memory>
#include <utility>
#include "entityx/config.h"
public:
virtual ~BaseReceiver() {
for (auto connection : connections_) {
- auto &ptr = connection.first;
+ auto &ptr = connection.second.first;
if (!ptr.expired()) {
- ptr.lock()->disconnect(connection.second);
+ ptr.lock()->disconnect(connection.second.second);
}
}
}
std::size_t connected_signals() const {
std::size_t size = 0;
for (auto connection : connections_) {
- if (!connection.first.expired()) {
+ if (!connection.second.first.expired()) {
size++;
}
}
private:
friend class EventManager;
- std::list<std::pair<EventSignalWeakPtr, std::size_t>> connections_;
+ std::unordered_map<BaseEvent::Family, std::pair<EventSignalWeakPtr, std::size_t>> connections_;
};
auto wrapper = EventCallbackWrapper<E>(std::bind(receive, &receiver, std::placeholders::_1));
auto connection = sig->connect(wrapper);
BaseReceiver &base = receiver;
- base.connections_.push_back(std::make_pair(EventSignalWeakPtr(sig), connection));
+ base.connections_.insert(std::make_pair(E::family(), std::make_pair(EventSignalWeakPtr(sig), connection)));
+ }
+
+ /**
+ * Unsubscribe an object in order to not receive events of type E anymore.
+ *
+ * Receivers must have subscribed for event E before unsubscribing from event E.
+ *
+ */
+ template <typename E, typename Receiver>
+ void unsubscribe(Receiver &receiver) {
+ BaseReceiver &base = receiver;
+ //Assert that it has been subscribed before
+ assert(base.connections_.find(E::family()) != base.connections_.end());
+ auto pair = base.connections_[E::family()];
+ auto connection = pair.second;
+ auto &ptr = pair.first;
+ if (!ptr.expired()) {
+ ptr.lock()->disconnect(connection);
+ }
+ base.connections_.erase(E::family());
}
void emit(const BaseEvent &event);
}
REQUIRE(0 == explosion_system.connected_signals());
}
+
+TEST_CASE("TestUnsubscription") {
+ ExplosionSystem explosion_system;
+ {
+ EventManager em;
+ em.subscribe<Explosion>(explosion_system);
+ REQUIRE(explosion_system.damage_received == 0);
+ em.emit<Explosion>(1);
+ REQUIRE(explosion_system.damage_received == 1);
+ em.unsubscribe<Explosion>(explosion_system);
+ em.emit<Explosion>(1);
+ REQUIRE(explosion_system.damage_received == 1);
+ }
+}