blob: 7bff1688a6b7356b12b13e8dcd97da446e2a69e9 [file] [log] [blame]
// Copyright 2017 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_GRAPH_NODE_BASE_H_
#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_NODE_BASE_H_
#include <stdint.h>
#include "base/check_op.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "components/performance_manager/graph/graph_impl.h"
#include "components/performance_manager/graph/properties.h"
#include "components/performance_manager/public/graph/node_state.h"
#include "components/performance_manager/public/graph/node_type.h"
namespace performance_manager {
class Node;
// NodeBase implements shared functionality among different types of graph
// nodes. A specific type of graph node will derive from this class and can
// override shared functionality when needed.
// All node classes allow construction on one sequence and subsequent use from
// another sequence.
// All methods not documented otherwise are single-threaded.
class NodeBase {
public:
// Used as a unique key to safely allow downcasting from a public node type
// to NodeBase via "GetImplType" and "GetImpl". The implementations are
// provided by PublicNodeImpl below.
static const uintptr_t kNodeBaseType;
NodeBase();
NodeBase(const NodeBase&) = delete;
NodeBase& operator=(const NodeBase&) = delete;
virtual ~NodeBase();
// May be called on any sequence.
NodeTypeEnum GetNodeType() const { return ToNode()->GetNodeType(); }
// The state of this node.
NodeState GetNodeState() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!graph_) {
return NodeState::kNotInGraph;
}
return graph_->GetNodeState(this);
}
// Returns the graph that contains this node. Only valid after JoinGraph() and
// before LeaveGraph().
GraphImpl* graph() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(graph_);
return graph_;
}
// Helper functions for casting from a node type to its underlying NodeBase.
// This CHECKs that the cast is valid. These functions work happily with
// public and private node class inputs.
static const NodeBase* FromNode(const Node* node);
static NodeBase* FromNode(Node* node);
// For converting from NodeBase to Node. This is implemented by
// TypedNodeBase.
virtual const Node* ToNode() const = 0;
// Satisfies part of the contract expected by ObservedProperty.
// GetObservers is implemented by TypedNodeImpl.
bool CanSetProperty() const;
bool CanSetAndNotifyProperty() const;
protected:
friend class GraphImpl;
// Helper function for TypedNodeBase to access the list of typed observers
// stored in the graph.
template <typename Observer>
const GraphImpl::ObserverList<Observer>& GetObservers(
const GraphImpl* graph) const {
DCHECK(CanSetAndNotifyProperty());
return graph->GetObservers<Observer>();
}
// Node lifecycle:
// Step 0: A node is constructed. Node state is kNotInGraph. Outgoing edges
// are set but not publicly visible.
// Step 1:
// Initializes the `graph_` pointer. Node must be in the kNotInGraph state.
void SetGraphPointer(GraphImpl* graph);
// Step 2:
// Node enters kInitializingNotInGraph state: nodes may modify their
// properties that don't affect the graph topology but *not* cause any
// notifications to be emitted that refer to the node, since public observers
// have not been notified that the node was added to the graph via
// OnBeforeNodeAdded and OnNodeAdded yet.
// Called after `graph_` is set, a good opportunity to initialize node state.
virtual void OnInitializingProperties();
// Step 3:
// OnBeforeNodeAdded notifications are dispatched. The public observer method
// can read and update the node state, but sees no incoming or outgoing edges.
// The graph is in a consistent state that doesn't include this node.
// Step 4:
// Node enters kInitializingEdges state: nodes may modify their properties
// that link to other nodes but *not* cause any notifications to be emitted
// that refer to the node, since public observers have not been notified that
// the node was added to the graph via OnNodeAdded yet.
// Called after properties are initialized, for nodes to update incoming edges
// to fully join the graph.
virtual void OnInitializingEdges();
// Step 5:
// Node enters kJoiningGraph state: the node must not be modified, since
// observers will now be notified of its initial state in the graph, and each
// observer should see the same state.
// OnNodeAdded notifications are dispatched.
// Step 6:
// Node enters kActiveInGraph state: the node may make property changes, and
// these changes may cause notifications to be dispatched.
// Called just after sending OnNodeAdded notifications, for nodes to perform
// initialization that causes notifications to be dispatched. For example,
// this could be used to set up an "opener" relationship between a PageNode
// and FrameNode: when OnPageNodeAdded() was called, the graph was in the
// valid state where both FrameNode and PageNode exist but the PageNode has
// no opener. Then this function sets the FrameNode as the opener and sends
// the OnOpenerFrameNodeChanged notification.
virtual void OnAfterJoiningGraph();
// The node lives in the graph normally at this point, in the kActiveInGraph
// state.
// Step 7:
// Called just before sending OnBeforeNodeRemoved notifications, for nodes to
// perform cleanup that causes notifications to be dispatched. This must leave
// the node and the graph in a consistent state since the node is still in the
// graph. For example if this is used to sever the "opener" relationship
// between a PageNode and a FrameNode, it must send the
// OnOpenerFrameNodeChanged notification, and leave the PageNode and FrameNode
// in the valid state they would have when the page has no opener.
virtual void OnBeforeLeavingGraph();
// Step 8:
// Node enters kLeavingGraph state: the node must not be modified, since it's
// about to be deleted. Observers will commonly use OnBeforeNodeRemoved
// notifications to clean up, and each observer should see the same state.
// OnBeforeNodeRemoved notifications are dispatched.
// Step 9:
// Node enters kUninitializingEdges state: nodes may modify their properties
// that link to other nodes but *not* cause any notifications to be emitted
// that refer to the node, since public observers have already been notified
// that the node is being removed from the graph via OnBeforeNodeRemoved.
// Called while leaving `graph_`, to sever the node from the graph by updating
// incoming edges.
virtual void OnUninitializingEdges();
// Step 10:
// Node enters kLeftGraph state: the node must not be modified, since it's
// about to be deleted. Any property changes would only be visible to other
// OnNodeRemoved observers, and their effects shouldn't depend on the order
// that observers are triggered.
// OnNodeRemoved notifications are dispatched. The public observer method sees
// the node's final properties but no incoming or outgoing edges. The graph is
// in a consistent state that doesn't include this node.
// Step 11:
// Called after the node's edges have been severed from the graph, a good
// opportunity to uninitialize node state. This is a pure virtual since almost
// all node classes must implement it to destroy private node-attached data.
virtual void CleanUpNodeState() = 0;
// Step 12:
// Resets the graph pointer. The node is in the kLeftGraph state during this
// call, and will be in the kNotInGraph state immediately afterwards.
void ClearGraphPointer();
// Assigned when SetGraphPointer() is called, up until ClearGraphPointer() is
// called, where it is reset to null.
raw_ptr<GraphImpl> graph_ GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;
SEQUENCE_CHECKER(sequence_checker_);
};
// Helper for implementing the Node parent of a PublicNodeClass.
template <class NodeImplClass, class PublicNodeClass>
class PublicNodeImpl : public PublicNodeClass {
public:
// Node implementation:
Graph* GetGraph() const override {
return static_cast<const NodeImplClass*>(this)->graph();
}
uintptr_t GetImplType() const override { return NodeBase::kNodeBaseType; }
const void* GetImpl() const override {
// This exposes NodeBase, so that we can complete the triangle of casting
// between all views of a node: NodeBase, FooNodeImpl, and FooNode.
return static_cast<const NodeBase*>(
static_cast<const NodeImplClass*>(this));
}
};
template <class NodeImplClass, class NodeClass, class NodeObserverClass>
class TypedNodeBase : public NodeBase {
public:
using ObservedProperty =
ObservedPropertyImpl<NodeImplClass, NodeClass, NodeObserverClass>;
TypedNodeBase() = default;
TypedNodeBase(const TypedNodeBase&) = delete;
TypedNodeBase& operator=(const TypedNodeBase&) = delete;
// Helper functions for casting from NodeBase to a concrete node type. This
// CHECKs that the cast is valid.
static const NodeImplClass* FromNodeBase(const NodeBase* node) {
CHECK_EQ(NodeImplClass::Type(), node->GetNodeType());
return static_cast<const NodeImplClass*>(node);
}
static NodeImplClass* FromNodeBase(NodeBase* node) {
CHECK_EQ(NodeImplClass::Type(), node->GetNodeType());
return static_cast<NodeImplClass*>(node);
}
// Helper functions for casting from a public node type to the private impl.
// This also casts away const correctness, as it is intended to be used by
// impl code that uses the public observer interface for a node type, where
// all notifications are delivered with a const node pointer. This CHECKs that
// the cast is valid.
static NodeImplClass* FromNode(const Node* node) {
NodeBase* node_base = const_cast<NodeBase*>(NodeBase::FromNode(node));
return FromNodeBase(node_base);
}
// Convenience accessor to the per-node-class list of observers that is stored
// in the graph. Satisfies the contract expected by ObservedProperty.
const GraphImpl::ObserverList<NodeObserverClass>& GetObservers() const {
// Mediate through NodeBase, as it's the class that is friended by the
// GraphImpl in order to provide access.
return NodeBase::GetObservers<NodeObserverClass>(graph());
}
const Node* ToNode() const override {
return static_cast<const NodeImplClass*>(this);
}
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_NODE_BASE_H_