/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015-2019 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** * * @modified 2026 Tom Clay * Modified for rexglue - Xbox 360 recompilation framework * * @changes - Consolidated bit_map.h and bit_range.h into single header */ #pragma once #include #include #include #include #include #include #include namespace rex::bit { //============================================================================= // BitMap - Efficient lookup of free/used entries //============================================================================= class BitMap { public: BitMap(); // Size is the number of entries, must be a multiple of 64. BitMap(size_t size_bits); // Data does not have to be aligned to a 4-byte boundary, but it is // preferable. // Size is the number of entries, must be a multiple of 64. BitMap(uint64_t* data, size_t size_bits); // (threadsafe) Acquires an entry and returns its index. Returns -1 if there // are no more free entries. size_t Acquire(); // (threadsafe) Releases an entry by an index. void Release(size_t index); // Resize the bitmap. Size is the number of entries, must be a multiple of 64. void Resize(size_t new_size_bits); // Sets all entries to free. void Reset(); const std::vector data() const { return data_; } std::vector& data() { return data_; } private: const static size_t kDataSize = 8; const static size_t kDataSizeBits = kDataSize * 8; std::vector data_; }; //============================================================================= // Bit Range Utilities //============================================================================= // Provided length is in bits since the first. Returns of the // range in bits, with length == 0 if not found. template std::pair GetNextRangeUnset(const Block* bits, size_t first, size_t length) { if (!length) { return std::make_pair(size_t(first), size_t(0)); } size_t last = first + length - 1; const size_t block_bits = sizeof(Block) * CHAR_BIT; size_t block_first = first / block_bits; size_t block_last = last / block_bits; size_t range_start = SIZE_MAX; for (size_t i = block_first; i <= block_last; ++i) { Block block = bits[i]; // Ignore bits in the block outside the specified range by considering them // set. if (i == block_first) { block |= (Block(1) << (first & (block_bits - 1))) - 1; } if (i == block_last && (last & (block_bits - 1)) != block_bits - 1) { block |= ~((Block(1) << ((last & (block_bits - 1)) + 1)) - 1); } while (true) { uint32_t block_bit; if (range_start == SIZE_MAX) { // Check if need to open a new range. if (!rex::bit_scan_forward(~block, &block_bit)) { break; } range_start = i * block_bits + block_bit; } else { // Check if need to close the range. // Ignore the set bits before the beginning of the range. Block block_bits_set_from_start = block; if (i == range_start / block_bits) { block_bits_set_from_start &= ~((Block(1) << (range_start & (block_bits - 1))) - 1); } if (!rex::bit_scan_forward(block_bits_set_from_start, &block_bit)) { break; } return std::make_pair(range_start, (i * block_bits) + block_bit - range_start); } } } if (range_start != SIZE_MAX) { return std::make_pair(range_start, last + size_t(1) - range_start); } return std::make_pair(first + length, size_t(0)); } template void SetRange(Block* bits, size_t first, size_t length) { if (!length) { return; } size_t last = first + length - 1; const size_t block_bits = sizeof(Block) * CHAR_BIT; size_t block_first = first / block_bits; size_t block_last = last / block_bits; Block set_first = ~((Block(1) << (first & (block_bits - 1))) - 1); Block set_last = ~Block(0); if ((last & (block_bits - 1)) != (block_bits - 1)) { set_last &= (Block(1) << ((last & (block_bits - 1)) + 1)) - 1; } if (block_first == block_last) { bits[block_first] |= set_first & set_last; return; } bits[block_first] |= set_first; if (block_first + 1 < block_last) { std::memset(bits + block_first + 1, CHAR_MAX, (block_last - (block_first + 1)) * sizeof(Block)); } bits[block_last] |= set_last; } } // namespace rex::bit