1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_ATTACHED_DATA_H_
6 #define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_ATTACHED_DATA_H_
7
8 #include <memory>
9
10 #include "base/logging.h"
11 #include "base/macros.h"
12
13 namespace performance_manager {
14
15 class Node;
16
17 // NodeAttachedData allows external observers of the graph to store data that is
18 // associated with a graph node, providing lifetime management as a service.
19 //
20 // External (to performance_manager) implementations of NodeAttachedData should
21 // derive from ExternalNodeAttachedDataImpl. For internal implementations refer
22 // to NodeAttachedDataImpl and see node_attached_data_impl.h.
23 class NodeAttachedData {
24 public:
25 NodeAttachedData();
26 virtual ~NodeAttachedData();
27
28 // Returns the 'key' associated with this type of NodeAttachedData. This needs
29 // to be unique per data type or bad things happen.
30 virtual const void* GetKey() const = 0;
31
32 private:
33 DISALLOW_COPY_AND_ASSIGN(NodeAttachedData);
34 };
35
36 // Implements NodeAttachedData for a given UserDataType.
37 //
38 // In order for a UserDataType to be attached to a node of type |NodeType| it
39 // must have a constructor of the form "UserDataType(const NodeType* node)".
40 template <typename UserDataType>
41 class ExternalNodeAttachedDataImpl : public NodeAttachedData {
42 public:
43 ExternalNodeAttachedDataImpl() = default;
44 ~ExternalNodeAttachedDataImpl() override = default;
45
46 // NodeAttachedData implementation:
GetKey()47 const void* GetKey() const override { return &kUserDataKey; }
48
49 // Gets the user data for the given |node|, creating it if it doesn't yet
50 // exist.
51 template <typename NodeType>
52 static UserDataType* GetOrCreate(const NodeType* node);
53
54 // Gets the user data for the given |node|, returning nullptr if it doesn't
55 // exist.
56 template <typename NodeType>
57 static UserDataType* Get(const NodeType* node);
58
59 // Destroys the user data associated with the given node, returning true
60 // on success or false if the user data did not exist to begin with.
61 template <typename NodeType>
62 static bool Destroy(const NodeType* node);
63
64 private:
65 static constexpr int kUserDataKey = 0;
UserDataKey()66 static const void* UserDataKey() { return &kUserDataKey; }
67
68 DISALLOW_COPY_AND_ASSIGN(ExternalNodeAttachedDataImpl);
69 };
70
71 // Everything below this point is pure implementation detail.
72
73 // Provides access for setting/getting data in the map based storage. Not
74 // intended to be used directly, but rather by (External)NodeAttachedDataImpl.
75 class NodeAttachedDataMapHelper {
76 public:
77 // Attaches the provided |data| to the provided |node|. This should only be
78 // called if the data does not exist (GetFromMap returns nullptr), and will
79 // DCHECK otherwise.
80 static void AttachInMap(const Node* node,
81 std::unique_ptr<NodeAttachedData> data);
82
83 // Retrieves the data associated with the provided |node| and |key|. This
84 // returns nullptr if no data exists.
85 static NodeAttachedData* GetFromMap(const Node* node, const void* key);
86
87 // Detaches the data associated with the provided |node| and |key|. It is
88 // harmless to call this when no data exists.
89 static std::unique_ptr<NodeAttachedData> DetachFromMap(const Node* node,
90 const void* key);
91 };
92
93 // Implementation of ExternalNodeAttachedDataImpl, which is declared in the
94 // corresponding public header. This helps keep the public headers as clean as
95 // possible.
96
97 // static
98 template <typename UserDataType>
99 constexpr int ExternalNodeAttachedDataImpl<UserDataType>::kUserDataKey;
100
101 template <typename UserDataType>
102 template <typename NodeType>
GetOrCreate(const NodeType * node)103 UserDataType* ExternalNodeAttachedDataImpl<UserDataType>::GetOrCreate(
104 const NodeType* node) {
105 if (auto* data = Get(node))
106 return data;
107 std::unique_ptr<UserDataType> data = std::make_unique<UserDataType>(node);
108 auto* raw_data = data.get();
109 auto* base = static_cast<const Node*>(node);
110 NodeAttachedDataMapHelper::AttachInMap(base, std::move(data));
111 return raw_data;
112 }
113
114 template <typename UserDataType>
115 template <typename NodeType>
Get(const NodeType * node)116 UserDataType* ExternalNodeAttachedDataImpl<UserDataType>::Get(
117 const NodeType* node) {
118 auto* base = static_cast<const Node*>(node);
119 auto* data = NodeAttachedDataMapHelper::GetFromMap(base, UserDataKey());
120 if (!data)
121 return nullptr;
122 DCHECK_EQ(UserDataKey(), data->GetKey());
123 return static_cast<UserDataType*>(data);
124 }
125
126 template <typename UserDataType>
127 template <typename NodeType>
Destroy(const NodeType * node)128 bool ExternalNodeAttachedDataImpl<UserDataType>::Destroy(const NodeType* node) {
129 auto* base = static_cast<const Node*>(node);
130 std::unique_ptr<NodeAttachedData> data =
131 NodeAttachedDataMapHelper::DetachFromMap(base, UserDataKey());
132 return data.get();
133 }
134
135 } // namespace performance_manager
136
137 #endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_ATTACHED_DATA_H_
138