blob: 41986acd9e33afb981d451dd4b218d85ab5c920c [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/resource_bitset.h"
#include <algorithm>
#include <limits>
#include "absl/log/log.h"
#include "absl/numeric/bits.h"
namespace mpact {
namespace sim {
namespace generic {
ResourceBitSet::ResourceBitSet(int bit_size) {
size_ = (bit_size + kBitsInUint - 1) / kBitsInUint;
bits_ = new UInt[size_];
for (int i = 0; i < size_; ++i) bits_[i] = 0;
}
ResourceBitSet::ResourceBitSet(const ResourceBitSet& rhs)
: ResourceBitSet(rhs.size_) {
Or(rhs);
}
ResourceBitSet::ResourceBitSet(ResourceBitSet&& rhs) {
bits_ = rhs.bits_;
size_ = rhs.size_;
rhs.bits_ = nullptr;
rhs.size_ = 0;
}
ResourceBitSet& ResourceBitSet::operator=(const ResourceBitSet& rhs) {
delete[] bits_;
size_ = rhs.size_;
bits_ = new UInt[size_];
for (int i = 0; i < size_; ++i) bits_[i] = rhs.bits_[i];
return *this;
}
ResourceBitSet::~ResourceBitSet() {
delete[] bits_;
size_ = 0;
}
void ResourceBitSet::Set(int position) {
auto word = position / kBitsInUint;
auto bit = position % kBitsInUint;
if (word > size_) Resize(position);
bits_[word] |= static_cast<UInt>(1) << bit;
}
void ResourceBitSet::Or(const ResourceBitSet& rhs) {
if (rhs.size_ > size_) Resize(rhs.size_ * kBitsInUint);
auto min = std::min(size_, rhs.size_);
for (int i = 0; i < min; ++i) bits_[i] |= rhs.bits_[i];
}
void ResourceBitSet::AndNot(const ResourceBitSet& rhs) {
auto min = std::min(size_, rhs.size_);
for (int i = 0; i < min; ++i) bits_[i] &= ~rhs.bits_[i];
}
bool ResourceBitSet::IsIntersectionNonEmpty(const ResourceBitSet& rhs) const {
auto min = std::min(size_, rhs.size_);
UInt accumulator = 0;
for (int i = 0; i < min; ++i) accumulator |= bits_[i] & rhs.bits_[i];
return accumulator != 0;
}
bool ResourceBitSet::FindFirstSetBit(int* position) const {
for (int i = 0; i < size_; ++i) {
if (bits_[i] == 0) continue;
// Count the trailing zeros (position increases right to left).
int pos = i * kBitsInUint + absl::countr_zero(bits_[i]);
if (position != nullptr) *position = pos;
return true;
}
return false;
}
bool ResourceBitSet::FindNextSetBit(int* position) const {
if (position == nullptr) {
LOG(ERROR) << "null position passed to FindNextSetBit";
}
int start_word = *position / kBitsInUint;
int bit_position = *position % kBitsInUint;
UInt mask = ~(std::numeric_limits<UInt>::max() << bit_position);
for (int word = start_word; word < size_; ++word) {
// Mask out bits before the starting position.
UInt value = bits_[word] & ~mask;
if (value == 0) {
mask = 0;
continue;
}
// Count the trailing zeros (position increases right to left).
int pos = word * kBitsInUint + absl::countr_zero(value);
*position = pos;
return true;
}
return false;
}
int ResourceBitSet::GetOnesCount() const {
int count = 0;
for (int i = 0; i < size_; ++i) {
count += absl::popcount(bits_[i]);
}
return count;
}
void ResourceBitSet::Resize(int bit_size) {
auto new_size = (bit_size + kBitsInUint - 1) / kBitsInUint;
// If the size is the same, or smaller, zero out the high order bits.
if (new_size <= size_) {
int bit_offset = bit_size % kBitsInUint;
UInt mask = ~(std::numeric_limits<UInt>::max() << bit_offset);
for (int i = new_size; i < size_; ++i) {
bits_[i] = bits_[i] & ~mask;
mask = 0;
}
return;
}
auto prev = bits_;
bits_ = new UInt[new_size];
for (int i = 0; i < new_size; ++i) {
bits_[i] = (i < size_) ? prev[i] : 0;
}
delete[] prev;
size_ = new_size;
}
} // namespace generic
} // namespace sim
} // namespace mpact