Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 71 additions & 4 deletions include/sparse_bitset_asm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class SparseBitsetASM {
}

SparseBitsetASM(const SparseBitsetASM &o)
: len_(o.len_), cap_(o.cap_), num_bits_(o.num_bits_) {
: len_(o.len_), cap_(o.cap_), num_bits_(o.num_bits_),
cache_b_idx_(o.cache_b_idx_), cache_pos_(o.cache_pos_) {
if (cap_ > 0) {
allocate(cap_);
std::memcpy(data_, o.data_, static_cast<size_t>(len_ + 1) * 32);
Expand All @@ -28,17 +29,22 @@ class SparseBitsetASM {

SparseBitsetASM(SparseBitsetASM &&o) noexcept
: data_(o.data_), ids_(o.ids_), len_(o.len_), cap_(o.cap_),
num_bits_(o.num_bits_) {
num_bits_(o.num_bits_), cache_b_idx_(o.cache_b_idx_),
cache_pos_(o.cache_pos_) {
o.data_ = nullptr;
o.ids_ = nullptr;
o.len_ = 0;
o.cap_ = 0;
o.num_bits_ = 0;
o.cache_b_idx_ = UINT32_MAX;
o.cache_pos_ = 0;
}

SparseBitsetASM &operator=(const SparseBitsetASM &o) {
if (this != &o) {
num_bits_ = o.num_bits_;
cache_b_idx_ = o.cache_b_idx_;
cache_pos_ = o.cache_pos_;
if (o.cap_ == 0) {
if (data_)
_mm_free(data_);
Expand Down Expand Up @@ -76,11 +82,16 @@ class SparseBitsetASM {
len_ = o.len_;
cap_ = o.cap_;
num_bits_ = o.num_bits_;
cache_b_idx_ = o.cache_b_idx_;
cache_pos_ = o.cache_pos_;

o.data_ = nullptr;
o.ids_ = nullptr;
o.len_ = 0;
o.cap_ = 0;
o.num_bits_ = 0;
o.cache_b_idx_ = UINT32_MAX;
o.cache_pos_ = 0;
}
return *this;
}
Expand All @@ -91,6 +102,8 @@ class SparseBitsetASM {
// Fast reset keeping capacity
inline void clear() noexcept {
len_ = 0;
cache_b_idx_ = UINT32_MAX;
cache_pos_ = 0;
if (cap_ > 0) {
ids_[0] = UINT32_MAX;
std::memset(data_, 0,
Expand All @@ -109,8 +122,8 @@ class SparseBitsetASM {
[[nodiscard]] size_t num_bits() const noexcept { return num_bits_; }
[[nodiscard]] bool intersects(const SparseBitsetASM &other) const noexcept;

// Iterate over set bits, calling `fn` with the bit index, Must not modify
// itself.
// Iterate over set bits sequentially calling `fn`. Exposes raw bits directly.
// Must not modify itself.
template <typename Fn>
__attribute__((always_inline)) // Force inlining
void for_each(Fn &&fn) const {
Expand Down Expand Up @@ -169,6 +182,58 @@ class SparseBitsetASM {
uint32_t cap_ = 0;
size_t num_bits_ = 0;

// Block Level Read Caching for O(1) Sequentials
mutable uint32_t cache_b_idx_ = UINT32_MAX;
mutable uint32_t cache_pos_ = 0;

inline uint32_t find_pos(uint32_t b_idx, bool &found) const noexcept {
// Immediate O(1) Cache Match (Both hits & missing items)
if (cache_b_idx_ == b_idx) {
found = (cache_pos_ < len_ && ids_[cache_pos_] == b_idx);
return cache_pos_;
}

// Checking forward/backwards sequentials iteratively mapped to consecutive
// blocks
if (cache_pos_ < len_ && ids_[cache_pos_] == cache_b_idx_) {
if (cache_pos_ + 1 < len_ && ids_[cache_pos_ + 1] == b_idx) {
cache_b_idx_ = b_idx;
cache_pos_++;
found = true;
return cache_pos_;
}
if (cache_pos_ > 0 && ids_[cache_pos_ - 1] == b_idx) {
cache_b_idx_ = b_idx;
cache_pos_--;
found = true;
return cache_pos_;
}
}

// Fallback binary search narrowing boundaries implicitly with the previous
// pos cache constraint
const uint32_t *start = ids_;
const uint32_t *end = ids_ + len_;

if (cache_pos_ < len_) {
if (ids_[cache_pos_] < b_idx) {
start = ids_ + cache_pos_ + 1;
} else {
end = ids_ + cache_pos_;
}
}

const uint32_t *it = std::lower_bound(start, end, b_idx);
uint32_t pos = static_cast<uint32_t>(it - ids_);

found = (pos < len_ && ids_[pos] == b_idx);

cache_b_idx_ = b_idx;
cache_pos_ = pos;

return pos;
}

void allocate(uint32_t n) {
if (n == 0)
return;
Expand Down Expand Up @@ -216,6 +281,7 @@ class SparseBitsetASM {
ids_[pos] = b_idx;
std::memset(data_ + pos * 4, 0, 32);
len_++;
cache_b_idx_ = UINT32_MAX;
}

inline void erase_block(uint32_t pos) {
Expand All @@ -225,5 +291,6 @@ class SparseBitsetASM {
(len_ - pos - 1) * 32);
}
len_--;
cache_b_idx_ = UINT32_MAX;
}
};
Loading
Loading