[Improvement] (MG_Util/Misc): Replace byte array with 64-bit bitmap in IndexGenerator.

This commit is contained in:
BZLZHH
2025-07-25 12:40:38 +08:00
parent e79a2fa809
commit 5962499147
2 changed files with 51 additions and 24 deletions
+1 -1
View File
@@ -89,7 +89,7 @@
typedef int android_LogPriority; typedef int android_LogPriority;
inline int __android_log_print(int prio, const char* tag, const char* fmt, ...) { } inline int __android_log_print(int prio, const char* tag, const char* fmt, ...) { return 0; }
#endif #endif
#include "MG_Util/GLExtensions.h" #include "MG_Util/GLExtensions.h"
+50 -23
View File
@@ -1,7 +1,4 @@
#pragma once #pragma once
#include <vector>
#include <algorithm>
#include <cstdint>
namespace MobileGL { namespace MobileGL {
template <typename IndexType> template <typename IndexType>
@@ -10,49 +7,79 @@ namespace MobileGL {
explicit IndexGenerator(size_t initial_capacity = 1024, IndexType first_index = 0) explicit IndexGenerator(size_t initial_capacity = 1024, IndexType first_index = 0)
: next_index_(first_index) : next_index_(first_index)
{ {
is_valid_.reserve(initial_capacity); const size_t words_needed = (initial_capacity + 63) / 64;
is_valid_.resize(words_needed, ~0ull);
freed_indices_.reserve(initial_capacity);
} }
void Generate(size_t n, IndexType* indices) { void Generate(size_t n, IndexType* indices) {
if (n == 0) return; if (n == 0) return;
size_t from_freed = std::min(n, freed_indices_.size()); size_t from_freed = std::min(n, freed_indices_.size());
for (size_t i = 0; i < from_freed; ++i) { if (from_freed > 0) {
indices[i] = freed_indices_.back(); std::copy_n(freed_indices_.end() - from_freed, from_freed, indices);
freed_indices_.pop_back(); freed_indices_.resize(freed_indices_.size() - from_freed);
is_valid_[indices[i]] = 1;
for (size_t i = 0; i < from_freed; ++i) {
SetValid(indices[i], true);
}
} }
size_t need_new = n - from_freed; size_t need_new = n - from_freed;
if (need_new > 0) { if (need_new > 0) {
size_t required = next_index_ + need_new; size_t required_index = next_index_ + need_new;
if (required > is_valid_.size()) { size_t required_words = (required_index + 63) / 64;
size_t new_cap = std::max(required, is_valid_.size() * 2); if (required_words > is_valid_.size()) {
is_valid_.resize(new_cap, 0); is_valid_.resize(required_words, ~0ull);
} }
for (size_t i = 0; i < need_new; ++i) { for (size_t i = 0; i < need_new; ++i) {
indices[from_freed + i] = next_index_; indices[from_freed + i] = next_index_++;
is_valid_[next_index_] = 1;
++next_index_;
} }
} }
} }
void Delete(IndexType index) { void Delete(IndexType index) {
if (index < is_valid_.size() && is_valid_[index]) { SetValid(index, false);
is_valid_[index] = 0; freed_indices_.push_back(index);
freed_indices_.push_back(index); if (freed_indices_.size() > 1024 && freed_indices_.size() > next_index_ / 2) {
CompactFreeList();
} }
} }
bool IsValid(IndexType index) const { bool IsValid(IndexType index) const {
return index < is_valid_.size() && is_valid_[index]; size_t word = index >> 6;
size_t bit = index & 0x3F;
return word < is_valid_.size() && (is_valid_[word] & (1ull << bit));
}
size_t FreeListSize() const { return freed_indices_.size(); }
size_t ActiveCount() const { return next_index_ - freed_indices_.size(); }
private:
inline void SetValid(IndexType index, bool valid) {
size_t word = index >> 6;
uint64_t mask = 1ull << (index & 0x3F);
if (word >= is_valid_.size()) return;
if (valid) {
is_valid_[word] |= mask;
}
else {
is_valid_[word] &= ~mask;
}
}
void CompactFreeList() {
std::sort(freed_indices_.begin(), freed_indices_.end());
auto last = std::unique(freed_indices_.begin(), freed_indices_.end());
freed_indices_.erase(last, freed_indices_.end());
} }
private: private:
IndexType next_index_ = 0; IndexType next_index_ = 0;
std::vector<IndexType> freed_indices_; std::vector<IndexType> freed_indices_;
std::vector<Uint8> is_valid_; std::vector<Uint64> is_valid_;
}; };
}
}