blob: 13cbc7199afa2f7a3f8bc7b70d750e316017c0ca [file] [edit]
// Copyright 2022 The Chromium Authors
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OBJECT_TRACKER_H_
#define OBJECT_TRACKER_H_
#include <memory>
#include <mutex>
#include <vector>
#include "base/logging.h"
namespace libvafake {
// Class that manages and stores the objects that FakeDriver needs to keep
// track of. All public methods are thread-safe.
template <class T>
class ObjectTracker {
static_assert(std::is_integral<typename T::IdType>::value);
public:
ObjectTracker() = default;
ObjectTracker(const ObjectTracker&) = delete;
ObjectTracker& operator=(const ObjectTracker&) = delete;
~ObjectTracker() = default;
template <class... Args>
typename T::IdType CreateObject(Args&&... args) {
const std::lock_guard<std::mutex> lock(lock_);
// This ConstructObject<Args...>() trick creates an object of type T
// preferring its constructor. If the constructor is not available (e.g.,
// it's private), it creates the object using a static T::Create() method.
objects_.push_back(
ConstructObject<Args...>(next_id_, std::forward<Args>(args)...));
CHECK(objects_.back());
do {
CHECK_LT(next_id_, std::numeric_limits<typename T::IdType>::max());
next_id_++;
} while (std::find_if(objects_.begin(), objects_.end(),
[this](const std::unique_ptr<T>& it) {
return it->GetID() == next_id_;
}) != objects_.end());
return objects_.back()->GetID();
}
bool ObjectExists(typename T::IdType id) {
const std::lock_guard<std::mutex> lock(lock_);
return std::find_if(objects_.begin(), objects_.end(),
[id](const std::unique_ptr<T>& it) {
return it->GetID() == id;
}) != objects_.end();
}
const T& GetObject(typename T::IdType id) {
const std::lock_guard<std::mutex> lock(lock_);
auto object = std::find_if(
objects_.begin(), objects_.end(),
[id](const std::unique_ptr<T>& it) { return it->GetID() == id; });
CHECK(object != objects_.end());
return **object;
}
void DestroyObject(typename T::IdType id) {
const std::lock_guard<std::mutex> lock(lock_);
auto object = std::find_if(
objects_.begin(), objects_.end(),
[id](const std::unique_ptr<T>& it) { return it->GetID() == id; });
CHECK(object != objects_.end());
objects_.erase(object);
if (id < next_id_) {
next_id_ = id;
}
}
private:
// Constructs an object of type T through the regular constructor using |id|
// and |args|.
template <class... Args,
typename std::enable_if<
std::is_constructible_v<T, typename T::IdType, Args...>,
bool>::type = true>
static std::unique_ptr<T> ConstructObject(typename T::IdType id,
Args&&... args) {
return std::make_unique<T>(id, std::forward<Args>(args)...);
}
// Constructs an object of type T through the T::Create() static method using
// |id| and |args|.
template <class... Args,
typename std::enable_if<
!std::is_constructible_v<T, typename T::IdType, Args...>,
bool>::type = true>
static std::unique_ptr<T> ConstructObject(typename T::IdType id,
Args&&... args) {
return T::Create(id, std::forward<Args>(args)...);
}
std::mutex lock_;
std::vector<std::unique_ptr<T>> objects_;
typename T::IdType next_id_ = std::numeric_limits<typename T::IdType>::min();
};
} // namespace libvafake
#endif // OBJECT_TRACKER_H_