108 std::lock_guard<std::recursive_mutex> lock(notify_mutex_);
109 RejectIfIncompatible(new_observer);
111 w.raw = &new_observer;
112 EnqueueOrApplyAdd(std::move(w));
127 void AddObserver(std::shared_ptr<AnyObserver>
const& new_observer)
const
129 std::lock_guard<std::recursive_mutex> lock(notify_mutex_);
130 RejectIfIncompatible(*new_observer);
132 w.owned = new_observer;
133 w.raw = new_observer.get();
134 EnqueueOrApplyAdd(std::move(w));
145 std::lock_guard<std::recursive_mutex> lock(notify_mutex_);
146 if (dispatch_depth_ > 0)
149 op.kind = PendingOp::Remove;
150 op.watcher.raw = &observer;
151 pending_ops_.push_back(std::move(op));
154 RemoveWatcher(&observer);
168 return t == std::type_index(
typeid(
void))
169 || t == std::type_index(
typeid(*
this));
206 if (!untyped_watchers_.empty())
208 for (
auto const& kv : typed_watchers_)
209 if (!kv.second.empty())
224 std::shared_ptr<AnyObserver> owned;
228 using ObserverList = std::vector<Watcher>;
232 enum Kind {
Add, Remove } kind;
236 void RejectIfIncompatible(AnyObserver
const& obs)
const
239 throw IncompatibleObserver(
240 "this observable (" + boost::core::demangle(
typeid(*this).name())
241 +
") does not accept an observer for "
242 + boost::core::demangle(obs.ObservedKind().name()));
245 void EnqueueOrApplyAdd(Watcher w)
const
247 if (dispatch_depth_ > 0)
250 op.kind = PendingOp::Add;
251 op.watcher = std::move(w);
252 pending_ops_.push_back(std::move(op));
255 AddWatcher(std::move(w));
258 void AddWatcher(Watcher
const& w)
const
260 auto present_in = [&](ObserverList
const& c) {
261 return std::find_if(c.begin(), c.end(),
262 [&](Watcher
const& x){ return x.raw == w.raw; }) != c.end();
265 auto types = w.raw->SubscribedEventTypes();
268 if (!present_in(untyped_watchers_))
269 untyped_watchers_.push_back(w);
273 for (
auto& ti : types)
275 auto& bucket = typed_watchers_[ti];
276 if (std::find_if(bucket.begin(), bucket.end(),
277 [&](Watcher
const& x){ return x.raw == w.raw; }) == bucket.end())
283 void RemoveWatcher(AnyObserver* who)
const
285 auto erase_from = [&](ObserverList& c) {
286 c.erase(std::remove_if(c.begin(), c.end(),
287 [&](Watcher
const& x){ return x.raw == who; }),
290 erase_from(untyped_watchers_);
291 for (
auto& [ti, bucket] : typed_watchers_)
295 void DrainPendingOps()
const
299 for (
auto& op : pending_ops_)
301 if (op.kind == PendingOp::Add)
302 AddWatcher(op.watcher);
304 RemoveWatcher(op.watcher.raw);
306 pending_ops_.clear();
309 void DispatchEvent(AnyEvent
const& e)
const
311 std::lock_guard<std::recursive_mutex> lock(notify_mutex_);
314 auto run = [&](ObserverList& bucket) {
315 for (
auto& w : bucket)
322 op.kind = PendingOp::Remove;
323 op.watcher.raw = w.raw;
324 pending_ops_.push_back(std::move(op));
329 auto it = typed_watchers_.find(std::type_index(
typeid(e)));
330 if (it != typed_watchers_.end())
332 run(untyped_watchers_);
335 if (dispatch_depth_ == 0)
339 mutable std::unordered_map<std::type_index, ObserverList> typed_watchers_;
340 mutable ObserverList untyped_watchers_;
342 mutable unsigned dispatch_depth_ = 0;
343 mutable std::vector<PendingOp> pending_ops_;
353 mutable std::recursive_mutex notify_mutex_;
Observable & operator=(Observable const &)
Copy-assignment: leaves the target's own watcher list untouched (see the copy ctor note).
Definition observable.hpp:81
void AddObserver(std::shared_ptr< AnyObserver > const &new_observer) const
Add an observer whose lifetime is co-owned by this observable.
Definition observable.hpp:127
void NotifyObservers(AnyEvent const &e) const
Sends an event to observers that subscribed to its exact dynamic type, then to all catch-all (untyped...
Definition observable.hpp:185
Observable(Observable const &)
Copies do NOT inherit the watcher list: observers subscribed to the source object,...
Definition observable.hpp:79