/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/base/bit_map.h" #include "xenia/base/assert.h" #include "xenia/base/atomic.h" #include "xenia/base/math.h" namespace xe { BitMap::BitMap() = default; BitMap::BitMap(size_t size_bits) { Resize(size_bits); } BitMap::BitMap(uint64_t* data, size_t size_bits) { assert_true(size_bits % kDataSizeBits == 0); data_.resize(size_bits / kDataSizeBits); std::memcpy(data_.data(), data, size_bits / kDataSizeBits); } inline size_t BitMap::TryAcquireAt(size_t i) { uint64_t entry = 0; uint64_t new_entry = 0; int64_t acquired_idx = -1LL; do { entry = data_[i]; uint8_t index = lzcnt(entry); if (index == kDataSizeBits) { // None free. acquired_idx = -1; break; } // Entry has a free bit. Acquire it. uint64_t bit = 1ull << (kDataSizeBits - index - 1); new_entry = entry & ~bit; assert_not_zero(entry & bit); acquired_idx = index; } while (!atomic_cas(entry, new_entry, &data_[i])); if (acquired_idx != -1) { // Acquired. return (i * kDataSizeBits) + acquired_idx; } return -1LL; } size_t BitMap::Acquire() { for (size_t i = 0; i < data_.size(); i++) { size_t attempt_result = TryAcquireAt(i); if (attempt_result != -1LL) { return attempt_result; } } return -1LL; } size_t BitMap::AcquireFromBack() { if (!data_.size()) { return -1LL; } for (ptrdiff_t i = data_.size() - 1; i >= 0; i--) { size_t attempt_result = TryAcquireAt(static_cast(i)); if (attempt_result != -1LL) { return attempt_result; } } return -1LL; } void BitMap::Release(size_t index) { auto slot = index / kDataSizeBits; index -= slot * kDataSizeBits; uint64_t bit = 1ull << (kDataSizeBits - index - 1); uint64_t entry = 0; uint64_t new_entry = 0; do { entry = data_[slot]; assert_zero(entry & bit); new_entry = entry | bit; } while (!atomic_cas(entry, new_entry, &data_[slot])); } void BitMap::Resize(size_t new_size_bits) { auto old_size = data_.size(); assert_true(new_size_bits % kDataSizeBits == 0); data_.resize(new_size_bits / kDataSizeBits); // Initialize new entries. if (data_.size() > old_size) { for (size_t i = old_size; i < data_.size(); i++) { data_[i] = -1; } } } void BitMap::Reset() { for (size_t i = 0; i < data_.size(); i++) { data_[i] = -1; } } } // namespace xe