blob: b95a58457c65f44dad567218c448114349b5f5d5 [file] [log] [blame]
// Copyright 2019 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 CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_H_
#include <memory>
#include "base/logging.h"
#include "base/macros.h"
#include "chrome/browser/performance_manager/public/graph/node_attached_data.h"
namespace performance_manager {
class NodeBase;
// Helper class for providing internal storage of a NodeAttachedData
// implementation directly in a node. The storage is provided as a raw buffer of
// bytes which is initialized externally by the NodeAttachedDataImpl via a
// placement new. In this way the node only needs to know about the
// NodeAttachedData base class, and the size of the required storage.
template <size_t DataSize>
class InternalNodeAttachedDataStorage {
public:
static constexpr size_t kDataSize = DataSize;
InternalNodeAttachedDataStorage() {}
~InternalNodeAttachedDataStorage() { Reset(); }
// Returns a pointer to the data object, if allocated.
NodeAttachedData* Get() { return data_; }
void Reset() {
if (data_)
data_->~NodeAttachedData();
data_ = nullptr;
}
uint8_t* buffer() { return buffer_; }
protected:
friend class InternalNodeAttachedDataStorageAccess;
// Transitions this object to being allocated.
void Set(NodeAttachedData* data) {
DCHECK(!data_);
// Depending on the object layout, once it has been cast to a
// NodeAttachedData there's no guarantee that the pointer will be at the
// head of the object, only that the pointer will be somewhere inside of the
// full object extent.
DCHECK_LE(buffer_, reinterpret_cast<uint8_t*>(data));
DCHECK_GT(buffer_ + kDataSize, reinterpret_cast<uint8_t*>(data));
data_ = data;
}
private:
NodeAttachedData* data_ = nullptr;
uint8_t buffer_[kDataSize];
DISALLOW_COPY_AND_ASSIGN(InternalNodeAttachedDataStorage);
};
// Provides access for setting/getting data in the map based storage. Not
// intended to be used directly, but rather by (External)NodeAttachedDataImpl.
class NodeAttachedDataMapHelper {
public:
// Attaches the provided |data| to the provided |node|. This should only be
// called if the data does not exist (GetFromMap returns nullptr), and will
// DCHECK otherwise.
static void AttachInMap(const NodeBase* node,
std::unique_ptr<NodeAttachedData> data);
// Retrieves the data associated with the provided |node| and |key|. This
// returns nullptr if no data exists.
static NodeAttachedData* GetFromMap(const NodeBase* node, const void* key);
// Detaches the data associated with the provided |node| and |key|. It is
// harmless to call this when no data exists.
static std::unique_ptr<NodeAttachedData> DetachFromMap(const NodeBase* node,
const void* key);
};
// Implementation of ExternalNodeAttachedDataImpl, which is declared in the
// corresponding public header. This helps keep the public headers as clean as
// possible.
// static
template <typename UserDataType>
constexpr int ExternalNodeAttachedDataImpl<UserDataType>::kUserDataKey;
template <typename UserDataType>
template <typename NodeType>
UserDataType* ExternalNodeAttachedDataImpl<UserDataType>::GetOrCreate(
const NodeType* node) {
if (auto* data = Get(node))
return data;
std::unique_ptr<UserDataType> data = std::make_unique<UserDataType>(node);
auto* raw_data = data.get();
auto* base = reinterpret_cast<const NodeBase*>(node->GetIndexingKey());
NodeAttachedDataMapHelper::AttachInMap(base, std::move(data));
return raw_data;
}
template <typename UserDataType>
template <typename NodeType>
UserDataType* ExternalNodeAttachedDataImpl<UserDataType>::Get(
const NodeType* node) {
auto* base = reinterpret_cast<const NodeBase*>(node->GetIndexingKey());
auto* data = NodeAttachedDataMapHelper::GetFromMap(base, UserDataKey());
if (!data)
return nullptr;
DCHECK_EQ(UserDataKey(), data->GetKey());
return static_cast<UserDataType*>(data);
}
template <typename UserDataType>
template <typename NodeType>
bool ExternalNodeAttachedDataImpl<UserDataType>::Destroy(const NodeType* node) {
auto* base = reinterpret_cast<const NodeBase*>(node->GetIndexingKey());
std::unique_ptr<NodeAttachedData> data =
NodeAttachedDataMapHelper::DetachFromMap(base, UserDataKey());
return data.get();
}
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_NODE_ATTACHED_DATA_H_