blob: 2f539c7f48abbe96340290d8ee6f1110bd61960a [file]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_GRAPH_REGISTERED_H_
#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_GRAPH_REGISTERED_H_
#include "base/check.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/performance_manager.h"
namespace performance_manager {
// This provides functionality that allows an instance of a graph-associated
// object to be looked up by type, allowing the graph to act as a rendezvous
// point. It enforces singleton semantics, so there may be no more than one
// instance of an object of a given type registered with the same graph at the
// same time. All registration and unregistration must happen on the PM
// sequence. It is illegal to register more than one object of the same class at
// a time, and all registered objects must be unregistered prior to graph tear-
// down. This is intended to be used as follows:
//
// class Foo : public GraphRegisteredImpl<Foo> {
// ...
// };
//
// void InvokedOnGraph(Graph* graph) {
// Foo* foo = ... some instance of Foo ...
// DCHECK(graph->RegisterObject(foo));
// }
//
// void InvokedSometimeLaterOnGraph(Graph* graph) {
// Foo* foo = graph->GetRegisteredObjectAs<Foo>();
// foo->DoSomething();
// }
//
// GraphRegisteredImpl also provides a GetFromGraph() convenience helper that
// wraps `graph->GetRegisteredObjectAs<...>()`.
//
// This may easily (and commonly) be combined with GraphOwned, allowing the
// registered object to be owned by the graph as well. The
// GraphOwnedAndRegistered helper will register the object automatically when
// PassToGraph is called. For example:
//
// class Bar : public GraphOwnedAndRegistered<Bar> {
// void OnPassedToGraph(Graph* graph) override {
// // RegisterObject was called before OnPassedToGraph.
// graph->AddFrameNodeObserver(this);
// }
// void OnTakenFromGraph(Graph* graph) override {
// graph->RemoveFrameNodeObserver(this);
// // Will call UnregisterObject after OnTakenFromGraph.
// }
// };
//
// void RunDuringInitialization() {
// PerformanceManager::PassToGraph(std::make_unique<Bar>());
// }
//
// void InvokedSometimeLaterOnGraph(Graph* graph, bool done) {
// Bar* bar = graph->GetRegisteredObjectAs<Bar>();
// bar->DoSomething();
// if (done) {
// graph->TakeFromGraph(bar);
// CHECK(!graph->GetRegisteredObjectAs<Bar>());
// }
// }
template <typename SelfType>
class GraphRegisteredImpl;
// Interface that graph registered objects must implement. Should only be
// implemented via GraphRegisteredImpl or GraphOwnedAndRegistered.
class GraphRegistered {
public:
GraphRegistered(const GraphRegistered&) = delete;
GraphRegistered& operator=(const GraphRegistered&) = delete;
virtual ~GraphRegistered();
// Returns the unique type of the object.
virtual uintptr_t GetTypeId() const = 0;
protected:
template <typename SelfType>
friend class GraphRegisteredImpl;
GraphRegistered();
};
// Fully implements GraphRegistered. Clients should derive from this class.
template <typename SelfType>
class GraphRegisteredImpl : public GraphRegistered {
public:
GraphRegisteredImpl() = default;
~GraphRegisteredImpl() override = default;
// The static TypeId associated with this class.
static uintptr_t TypeId() {
// The pointer to this object acts as a unique key that identifies the type
// at runtime. Note that the address of this should be taken only from a
// single library, as a different address will be returned from each library
// into which a given data type is linked. Note that if base/type_id ever
// becomes a thing, this should use that!
static constexpr int kTypeId = 0;
return reinterpret_cast<uintptr_t>(&kTypeId);
}
// GraphRegistered implementation:
uintptr_t GetTypeId() const override { return TypeId(); }
// Helper function for looking up the registered object of this type from the
// provided `graph`. If none is provided, looks up the object in the default
// graph returned by PerformanceManager::GetGraph(), returning nullptr if
// the default graph is not available.
static SelfType* GetFromGraph(Graph* graph = nullptr) {
if (!graph) {
if (!PerformanceManager::IsAvailable()) {
return nullptr;
}
graph = PerformanceManager::GetGraph();
CHECK(graph);
}
return graph->GetRegisteredObjectAs<SelfType>();
}
// Returns true if this object is the registered object in the graph, false
// otherwise. Useful for DCHECKing contract conditions.
bool IsRegistered(Graph* graph) const { return GetFromGraph(graph) == this; }
// Returns true if no object of this type is registered in the graph, false
// otherwise. Useful for DCHECKing contract conditions.
static bool NothingRegistered(Graph* graph) {
return GetFromGraph(graph) == nullptr;
}
};
// Helper for classes that are both GraphOwned and GraphRegistered.
template <typename SelfType>
class GraphOwnedAndRegistered : public GraphRegisteredImpl<SelfType>,
public GraphOwned {
public:
GraphOwnedAndRegistered() = default;
~GraphOwnedAndRegistered() override = default;
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override {}
void OnTakenFromGraph(Graph* graph) override {}
private:
void PassToGraphImpl(Graph* graph) override {
graph->RegisterObject(this);
GraphOwned::PassToGraphImpl(graph);
}
void TakeFromGraphImpl(Graph* graph) override {
GraphOwned::TakeFromGraphImpl(graph);
graph->UnregisterObject(this);
}
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_GRAPH_REGISTERED_H_