// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_ #include "base/auto_reset.h" #include "third_party/blink/renderer/platform/heap/handle.h" namespace blink { // A set of observers. Ensures list is not mutated while iterating. Observers // are not retained. template class PLATFORM_EXPORT HeapObserverSet { DISALLOW_NEW(); public: // Add an observer to this list. An observer should not be added to the same // list more than once. void AddObserver(ObserverType* observer) { CHECK(iteration_state_ & kAllowingAddition); DCHECK(!HasObserver(observer)); observers_.insert(observer); } // Removes the given observer from this list. Does nothing if this observer is // not in this list. void RemoveObserver(ObserverType* observer) { CHECK(iteration_state_ & kAllowingRemoval); observers_.erase(observer); } // Determine whether a particular observer is in the list. bool HasObserver(ObserverType* observer) const { DCHECK(!IsIteratingOverObservers()); return observers_.Contains(observer); } // Returns true if the list is being iterated over. bool IsIteratingOverObservers() const { return iteration_state_ != kNotIterating; } // Removes all the observers from this list. void Clear() { CHECK(iteration_state_ & kAllowingRemoval); observers_.clear(); } // Safely iterate over the registered lifecycle observers in an unpredictable // order. // // Adding or removing observers is not allowed during iteration. The callable // will only be called synchronously inside ForEachObserver(). // // Sample usage: // ForEachObserver([](ObserverType* observer) { // observer->SomeMethod(); // }); template void ForEachObserver(const ForEachCallable& callable) const { base::AutoReset scope(&iteration_state_, kAllowingNone); for (ObserverType* observer : observers_) { callable(observer); } } void Trace(Visitor* visitor) const { visitor->Trace(observers_); } private: using ObserverSet = HeapHashSet>; // TODO(keishi): Clean up iteration state once transition from // LifecycleObserver is complete. enum IterationState { kAllowingNone = 0, kAllowingAddition = 1, kAllowingRemoval = 1 << 1, kNotIterating = kAllowingAddition | kAllowingRemoval, }; // Iteration state is recorded while iterating the observer set, // optionally barring add or remove mutations. mutable IterationState iteration_state_ = kNotIterating; ObserverSet observers_; }; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_