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