| // 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 |