blob: 3b9a9d751cc0b9d2a9bdd8ea79d771c1057caa88 [file]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mpact/sim/generic/simple_resource.h"
#include <string>
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
namespace mpact {
namespace sim {
namespace generic {
// Initialize the bitmap and set the bit specified by index.
SimpleResource::SimpleResource(absl::string_view name, int index,
SimpleResourcePool *pool)
: name_(name), index_(index), pool_(pool) {
resource_bit_.Resize(pool_->width());
resource_bit_.Set(index);
}
// Just call into the pool to reserve/free/check.
void SimpleResource::Acquire() { pool_->Acquire(this); }
void SimpleResource::Release() { pool_->Release(this); }
bool SimpleResource::IsFree() const { return pool_->IsFree(this); }
SimpleResourceSet::SimpleResourceSet(SimpleResourcePool *pool) : pool_(pool) {
resource_vector_.Resize(pool_->width());
}
// Verify that the resource comes from the same pool. If so, add it (union with)
// the bitmap. Return appropriate status.
absl::Status SimpleResourceSet::AddResource(SimpleResource *resource) {
// If the resource is nullptr, just return ok status.
if (resource == nullptr) return absl::OkStatus();
// Make sure it belongs to the same pool as the resource set.
if (resource->pool() != pool_) {
return absl::Status(
absl::StatusCode::kInternal,
"SimpleResourceSet: Attempt to add resource from different pool");
}
resource_vector_.Or(resource->resource_bit());
return absl::OkStatus();
}
// If the resource doesn't exist, add it to the resource pool, before adding it
// to the resource set.
absl::Status SimpleResourceSet::AddResource(absl::string_view name) {
SimpleResource *resource = pool_->GetResource(name);
if (nullptr == resource) {
auto status = pool_->AddResource(name);
if (!status.ok()) return status;
resource = pool_->GetResource(name);
}
auto status = AddResource(resource);
if (!status.ok()) return status;
return absl::OkStatus();
}
// Call into the pool to reserve/free/check.
void SimpleResourceSet::Acquire() { pool_->Acquire(this); }
void SimpleResourceSet::Release() { pool_->Release(this); }
bool SimpleResourceSet::IsFree() const { return pool_->IsFree(this); }
std::string SimpleResourceSet::AsString() const {
std::string out = "[";
std::string sep;
for (int index = 0; resource_vector_.FindNextSetBit(&index); ++index) {
auto *resource = pool_->GetResource(index);
if (resource == nullptr) {
LOG(ERROR) << absl::StrCat("Cannot find resource (", index, ") in pool '",
pool_->name(), "'");
continue;
}
absl::StrAppend(&out, sep, resource->name());
sep = ", ";
}
absl::StrAppend(&out, "]");
return out;
}
SimpleResourcePool::SimpleResourcePool(absl::string_view name, int width)
: name_(name), width_(width) {
resource_vector_.Resize(width_);
}
SimpleResourcePool::~SimpleResourcePool() {
for (const auto &entry : resource_name_map_) {
delete entry.second;
}
resource_name_map_.clear();
for (auto entry : resource_sets_) {
delete entry;
}
resource_sets_.clear();
}
// Add named resource to the pool. If the pool has reached maximum size, return
// an error.
absl::StatusOr<SimpleResource *> SimpleResourcePool::AddResourceInternal(
absl::string_view name) {
if (resource_name_map_.size() == width_) {
return absl::InternalError(absl::StrCat(
"SimpleResourcePool: Attempted to add too many resources to pool '",
name_, "'"));
}
if (resource_name_map_.contains(name)) {
return absl::AlreadyExistsError(
absl::StrCat("SimpleResourcePool: Resource '", name,
"' already exists in pool '", name_, "'"));
}
int index = resource_name_map_.size();
SimpleResource *resource = new SimpleResource(name, index, this);
resource_name_map_.emplace(name, resource);
resources_.push_back(resource);
return resource;
}
absl::Status SimpleResourcePool::AddResource(absl::string_view name) {
auto result = AddResourceInternal(name);
if (result.ok()) return absl::OkStatus();
return result.status();
}
SimpleResource *SimpleResourcePool::GetResource(unsigned index) const {
if ((index < 0) || (index >= resources_.size())) return nullptr;
return resources_[index];
}
SimpleResource *SimpleResourcePool::GetResource(absl::string_view name) const {
auto ptr = resource_name_map_.find(name);
if (ptr == resource_name_map_.end()) return nullptr;
return ptr->second;
}
SimpleResource *SimpleResourcePool::GetOrAddResource(absl::string_view name) {
auto *resource = GetResource(name);
if (resource != nullptr) return resource;
auto result = AddResourceInternal(name);
if (!result.ok()) {
LOG(ERROR) << "Unable to add resource '" << name
<< "' to resource pool: " << result.status().message();
return nullptr;
}
return result.value();
}
SimpleResourceSet *SimpleResourcePool::CreateResourceSet() {
resource_sets_.push_front(new SimpleResourceSet(this));
return resource_sets_.front();
}
// Bitmap operations to reserve, free and check resources. Union with a bitmap
// from a resource or resource set to reserve (set), difference to free (clear),
// and non-empty intersection (non-zero and) to check.
bool SimpleResourcePool::IsFree(const SimpleResourceSet *resource_set) const {
return !resource_vector_.IsIntersectionNonEmpty(
resource_set->resource_vector());
}
bool SimpleResourcePool::IsFree(const SimpleResource *resource) const {
return !resource_vector_.IsIntersectionNonEmpty(resource->resource_bit());
}
void SimpleResourcePool::Acquire(const SimpleResourceSet *resource_set) {
resource_vector_.Or(resource_set->resource_vector());
}
void SimpleResourcePool::Acquire(const SimpleResource *resource) {
resource_vector_.Or(resource->resource_bit());
}
void SimpleResourcePool::Release(const SimpleResourceSet *resource_set) {
resource_vector_.AndNot(resource_set->resource_vector());
}
void SimpleResourcePool::Release(const SimpleResource *resource) {
resource_vector_.AndNot(resource->resource_bit());
}
std::string SimpleResourcePool::ReservedAsString() const {
std::string out = "[";
std::string sep;
for (int index = 0; resource_vector_.FindNextSetBit(&index); ++index) {
auto *resource = resources_[index];
if (resource == nullptr) {
LOG(ERROR) << absl::StrCat("Cannot find resource (", index, ") in pool '",
name(), "'");
continue;
}
absl::StrAppend(&out, sep, resource->name());
sep = ", ";
}
absl::StrAppend(&out, "]");
return out;
}
} // namespace generic
} // namespace sim
} // namespace mpact