1+ #pragma once
2+
3+ #include < functional>
4+ #include < typeindex>
5+ #include < unordered_map>
6+ #include < vector>
7+
8+ #include " ESPressio_IObservable.hpp"
9+ #include " ESPressio_IObserver.hpp"
10+ #include " ESPressio_ObserverHandle.hpp"
11+
12+ namespace ESPressio {
13+
14+ namespace Observable {
15+
16+ // / An `ObservableWithBuckets` is an object that can be observed by any number of `IObserver` descendant types
17+ // / This is a concrete implementation of `IObservable`, but it is NOT Thread-Safe.
18+ // / This variation uses "Buckets" (a Map, effectively) keyed on the `IObserver` type.
19+ // / It may be more performant when your descendant Observable is observed by a large number of DIFFERENT Observer types!
20+ // / Registering or Unregistering Observers while Observers are being notified can lead to undefined behavior.
21+ // / If you need a Thread-Safe Implementation, use the `ThreadSafeObservableWithBuckets` class instead.
22+ class ObservableWithBuckets : public IObservable {
23+ private:
24+ std::unordered_map<std::type_index, std::vector<IObserverHandle*>*> _observers;
25+ protected:
26+ // / Will call the `callback` for each Observer that is of type `ObserverType`
27+ template <class ObserverType >
28+ void WithObservers (std::function<void (ObserverType*)> callback) {
29+ auto observerType = std::type_index (typeid (ObserverType)); // Get the Type Index of the ObserverType
30+ std::vector<IObserverHandle*>* observers = _observers[observerType]; // Get the Observers for this Type Index
31+ if (observers == nullptr || observers->empty ()) { return ; } // If there are no Observers, return
32+
33+ for (auto observer : *observers) { // For each Observer...
34+ callback (observer); // ...call the callback (we know that it is of type `ObserverType`)
35+ }
36+ }
37+ public:
38+ ~ObservableWithBuckets () {
39+ for (auto & observer : _observers) { // Iterate all of the Type Buckets...
40+ for (auto & observerHandle : *observer.second ) { // ...and for each Observer in the Bucket...
41+ static_cast <ObserverHandle*>(observerHandle)->__invalidate (); // ...invalidate it
42+ }
43+ delete observer.second ; // ...and delete the Bucket
44+ }
45+ _observers.clear (); // Clear the Map
46+ }
47+
48+ virtual IObserverHandle* RegisterObserver (IObserver* observer) {
49+ auto observerType = std::type_index (typeid (*observer)); // Get the Type Index of the Observer
50+ std::vector<IObserverHandle*>* observers = _observers[observerType]; // Get the Observers for this Type Index
51+ if (observers == nullptr ) { // If there are no Observers for this Type Index...
52+ observers = new std::vector<IObserverHandle*>(); // ...create a new vector
53+ _observers[observerType] = observers; // ...and add it to the Map
54+ }
55+
56+ for (auto thisObserver : *observers) { // For each Observer in the vector...
57+ if (thisObserver->GetObserver () == observer) { return thisObserver; } // ...if it is the same as the one we are trying to register, return it
58+ }
59+
60+ IObserverHandle* handle = new ObserverHandle (this , observer); // Create a new ObserverHandle
61+ observers->push_back (handle); // Add it to the vector
62+ return handle; // Return the ObserverHandle
63+ }
64+
65+ virtual void UnregisterObserver (IObserver* observer) {
66+ auto observerType = std::type_index (typeid (*observer)); // Get the Type Index of the Observer
67+ std::vector<IObserverHandle*>* observers = _observers[observerType]; // Get the Observers for this Type Index
68+ if (observers == nullptr || observers->empty ()) { return ; } // If there are no Observers, return
69+
70+ for (auto thisObserver = observers->begin (); thisObserver != observers->end (); thisObserver++) { // For each Observer in the vector...
71+ if ((*thisObserver)->GetObserver () == observer) { // ...if it is the same as the one we are trying to unregister...
72+ static_cast <ObserverHandle*>((*thisObserver))->__invalidate (); // ...invalidate it
73+ observers->erase (thisObserver); // ...and erase it from the vector
74+ return ; // ...and return
75+ }
76+ }
77+ }
78+
79+ virtual bool IsObserverRegistered (IObserver* observer) {
80+ auto observerType = std::type_index (typeid (*observer)); // Get the Type Index of the Observer
81+ std::vector<IObserverHandle*>* observers = _observers[observerType]; // Get the Observers for this Type Index
82+ if (observers == nullptr || observers->empty ()) { return false ; } // If there are no Observers, return false
83+
84+ for (auto thisObserver : *observers) { // For each Observer in the vector...
85+ if (thisObserver->GetObserver () == observer) { return true ; } // ...if it is the same as the one we are checking, return true
86+ }
87+ return false ; // If we didn't find it, return false
88+ }
89+ };
90+
91+ }
92+
93+ }
0 commit comments