%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/utils/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/utils/sparse-bit-vector.h |
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_UTILS_SPARSE_BIT_VECTOR_H_
#define V8_UTILS_SPARSE_BIT_VECTOR_H_
#include "src/base/bits.h"
#include "src/base/iterator.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
// A sparse bit vector implementation optimized for small sizes.
// For up to {kNumBitsPerSegment} bits, no additional storage is needed, and
// accesses should be nearly as fast as {BitVector}.
class SparseBitVector : public ZoneObject {
// 6 words for the bits plus {offset} plus {next} will be 8 machine words per
// {Segment}. Most bit vectors are expected to fit in that single {Segment}.
static constexpr int kNumWordsPerSegment = 6;
static constexpr int kBitsPerWord = kBitsPerByte * kSystemPointerSize;
static constexpr int kNumBitsPerSegment = kBitsPerWord * kNumWordsPerSegment;
struct Segment {
// Offset of the first bit in this segment.
int offset = 0;
// {words} covers bits [{offset}, {offset + kNumBitsPerSegment}).
uintptr_t words[kNumWordsPerSegment] = {0};
// The next segment (with strict larger offset), or {nullptr}.
Segment* next = nullptr;
bool empty() const {
return std::all_of(std::begin(words), std::end(words),
[](auto segment) { return segment == 0; });
}
};
// Check that {Segment}s are nicely aligned, for (hopefully) better cache line
// alignment.
static_assert(sizeof(Segment) == 8 * kSystemPointerSize);
public:
// An iterator to iterate all set bits.
class Iterator : public base::iterator<std::forward_iterator_tag, int> {
public:
struct EndTag {};
explicit Iterator(EndTag) {}
explicit Iterator(const Segment* segment) {
// {segment} is {&first_segment_}, so cannot be null initially.
do {
for (int word = 0; word < kNumWordsPerSegment; ++word) {
if (segment->words[word] == 0) continue;
int bit_in_word =
base::bits::CountTrailingZeros(segment->words[word]);
segment_ = segment;
bit_in_segment_ = word * kBitsPerWord + bit_in_word;
return;
}
segment = segment->next;
} while (segment != nullptr);
DCHECK_IMPLIES(!segment_, *this == Iterator{EndTag{}});
DCHECK_IMPLIES(segment_,
contains(segment_, segment_->offset + bit_in_segment_));
}
int operator*() const {
DCHECK_NOT_NULL(segment_);
int offset = segment_->offset + bit_in_segment_;
DCHECK(contains(segment_, offset));
return offset;
}
bool operator==(const Iterator& other) const {
return segment_ == other.segment_ &&
bit_in_segment_ == other.bit_in_segment_;
}
bool operator!=(const Iterator& other) const { return !(*this == other); }
void operator++() {
int word = bit_in_segment_ / kBitsPerWord;
int bit_in_word = bit_in_segment_ % kBitsPerWord;
if (bit_in_word < kBitsPerWord - 1) {
uintptr_t remaining_bits =
segment_->words[word] &
(std::numeric_limits<uintptr_t>::max() << (1 + bit_in_word));
if (remaining_bits) {
int next_bit_in_word = base::bits::CountTrailingZeros(remaining_bits);
DCHECK_LT(bit_in_word, next_bit_in_word);
bit_in_segment_ = word * kBitsPerWord + next_bit_in_word;
return;
}
}
// No remaining bits in the current word. Search in succeeding words and
// segments.
++word;
do {
for (; word < kNumWordsPerSegment; ++word) {
if (segment_->words[word] == 0) continue;
bit_in_word = base::bits::CountTrailingZeros(segment_->words[word]);
bit_in_segment_ = word * kBitsPerWord + bit_in_word;
return;
}
segment_ = segment_->next;
word = 0;
} while (segment_);
// If we reach here, there are no more bits.
bit_in_segment_ = 0;
DCHECK_EQ(*this, Iterator{EndTag{}});
}
private:
const Segment* segment_ = nullptr;
int bit_in_segment_ = 0;
};
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(SparseBitVector);
explicit SparseBitVector(Zone* zone) : zone_(zone) {}
V8_INLINE bool Contains(int i) const {
DCHECK_LE(0, i);
const Segment* segment = &first_segment_;
// Explicit fast path for the first segment which always starts at offset 0.
if (V8_UNLIKELY(i >= kNumBitsPerSegment)) {
do {
segment = segment->next;
if (!segment) return false;
} while (segment->offset <= i - kNumBitsPerSegment);
if (segment->offset > i) return false;
}
return contains(segment, i);
}
V8_INLINE void Add(int i) {
DCHECK_LE(0, i);
Segment* last = nullptr;
Segment* segment = &first_segment_;
// Explicit fast path for the first segment which always starts at offset 0.
if (V8_UNLIKELY(i >= kNumBitsPerSegment)) {
do {
last = segment;
segment = segment->next;
if (V8_UNLIKELY(!segment)) return InsertBitAfter(last, i);
} while (segment->offset <= i - kNumBitsPerSegment);
if (V8_UNLIKELY(segment->offset > i)) return InsertBitAfter(last, i);
}
set(segment, i);
}
V8_INLINE void Remove(int i) {
DCHECK_LE(0, i);
Segment* segment = &first_segment_;
// Explicit fast path for the first segment which always starts at offset 0.
if (V8_UNLIKELY(i >= kNumBitsPerSegment)) {
do {
segment = segment->next;
if (V8_UNLIKELY(!segment)) return;
} while (segment->offset <= i - kNumBitsPerSegment);
if (V8_UNLIKELY(segment->offset > i)) return;
}
unset(segment, i);
}
void Union(const SparseBitVector& other) {
// Always remember the segment before {segment}, because we sometimes need
// to insert *before* {segment}, but we have to backlinks.
Segment* last = nullptr;
Segment* segment = &first_segment_;
// Iterate all segments in {other}, merging with with existing segments in
// {this}, or inserting new segments when needed.
for (const Segment* other_segment = &other.first_segment_; other_segment;
other_segment = other_segment->next) {
// Find the first segment whose offset is >= {other_segment}'s offset.
while (segment && segment->offset < other_segment->offset) {
last = segment;
segment = segment->next;
}
// Now either merge {other_segment} into {segment}, or insert between
// {last} and {segment}.
if (segment && segment->offset == other_segment->offset) {
std::transform(std::begin(segment->words), std::end(segment->words),
std::begin(other_segment->words),
std::begin(segment->words), std::bit_or<uintptr_t>{});
} else if (!other_segment->empty()) {
DCHECK_LT(last->offset, other_segment->offset);
Segment* new_segment = zone_->New<Segment>();
new_segment->offset = other_segment->offset;
std::copy(std::begin(other_segment->words),
std::end(other_segment->words),
std::begin(new_segment->words));
InsertSegmentAfter(last, new_segment);
last = new_segment;
}
}
}
Iterator begin() const { return Iterator{&first_segment_}; }
Iterator end() const { return Iterator{Iterator::EndTag{}}; }
private:
static std::pair<int, int> GetWordAndBitInWord(const Segment* segment,
int i) {
DCHECK_LE(segment->offset, i);
DCHECK_GT(segment->offset + kNumBitsPerSegment, i);
int bit_in_segment = i - segment->offset;
return {bit_in_segment / kBitsPerWord, bit_in_segment % kBitsPerWord};
}
V8_NOINLINE void InsertBitAfter(Segment* segment, int i) {
Segment* new_segment = zone_->New<Segment>();
new_segment->offset = i / kNumBitsPerSegment * kNumBitsPerSegment;
set(new_segment, i);
InsertSegmentAfter(segment, new_segment);
DCHECK(Contains(i));
}
V8_NOINLINE void InsertSegmentAfter(Segment* segment, Segment* new_segment) {
DCHECK_NOT_NULL(segment);
DCHECK_LT(segment->offset, new_segment->offset);
insert_after(segment, new_segment);
DCHECK(CheckConsistency(segment));
DCHECK(CheckConsistency(new_segment));
}
static bool contains(const Segment* segment, int i) {
auto [word, bit] = GetWordAndBitInWord(segment, i);
return (segment->words[word] >> bit) & 1;
}
static bool set(Segment* segment, int i) {
auto [word, bit] = GetWordAndBitInWord(segment, i);
return segment->words[word] |= uintptr_t{1} << bit;
}
static bool unset(Segment* segment, int i) {
auto [word, bit] = GetWordAndBitInWord(segment, i);
return segment->words[word] &= ~(uintptr_t{1} << bit);
}
static void insert_after(Segment* segment, Segment* new_next) {
DCHECK_NULL(new_next->next);
DCHECK_LT(segment->offset, new_next->offset);
new_next->next = segment->next;
segment->next = new_next;
}
V8_WARN_UNUSED_RESULT bool CheckConsistency(const Segment* segment) {
if ((segment->offset % kNumBitsPerSegment) != 0) return false;
if (segment->next && segment->next->offset <= segment->offset) return false;
return true;
}
Segment first_segment_;
Zone* zone_;
};
} // namespace internal
} // namespace v8
#endif // V8_UTILS_SPARSE_BIT_VECTOR_H_