提交 6a758a72 创建 作者: Austin Clements's avatar Austin Clements

radix: Usual constructors, key(), span(), and next_change()

These methods are to support changes in the VM system. key() and span() let you interrogate the current position of the iterator. next_change() and the copy/move constructors make it easy to work with spans of equal elements.
上级 91c171fc
...@@ -231,13 +231,18 @@ struct radix_iterator { ...@@ -231,13 +231,18 @@ struct radix_iterator {
if (k_ != key_limit_) if (k_ != key_limit_)
prime_path(); prime_path();
} }
radix_iterator() = default;
radix_iterator(const radix_iterator &o) = default;
radix_iterator(radix_iterator &&o) = default;
// Move to the next non-null entry in the collection, or end.
radix_iterator &operator++() { radix_iterator &operator++() {
assert(k_ < key_limit_); assert(k_ < key_limit_);
advance(); advance();
return *this; return *this;
} }
radix_elem* operator*() {
radix_elem* operator*() const {
return path_[level_]->load().elem(); return path_[level_]->load().elem();
} }
...@@ -245,10 +250,28 @@ struct radix_iterator { ...@@ -245,10 +250,28 @@ struct radix_iterator {
// If the current element is non-null, does nothing. // If the current element is non-null, does nothing.
void skip_nulls() void skip_nulls()
{ {
if (path_[level_]->load().is_null()) if (!**this)
++(*this); ++(*this);
} }
// Return the key of the iterator's current element.
u64 key() const
{
return k_ << r_->shift_;
}
// Return the span of the key space occupied by the iterator's
// current element.
u64 span() const
{
return (u64)1 << (bits_per_level * level_ + r_->shift_);
}
// Return an iterator that points to the next element that is not
// equal to the current element. If no such element exists, returns
// end. Note that this element may be null.
radix_iterator next_change() const;
// Compare equality on just the key. // Compare equality on just the key.
bool operator==(const radix_iterator &other) { bool operator==(const radix_iterator &other) {
return r_ == other.r_ && k_ == other.k_; } return r_ == other.r_ && k_ == other.k_; }
...@@ -267,9 +290,9 @@ private: ...@@ -267,9 +290,9 @@ private:
// Prepare the initial path_ and level_ based on k_. // Prepare the initial path_ and level_ based on k_.
void prime_path(); void prime_path();
// Advance to the next non-null leaf. This assumes that // Advance to the next leaf. If skip_nulls is true, advances to the
// k_ < key_limit_. // next non-null leaf. This assumes that k_ < key_limit_.
void advance(); void advance(bool skip_nulls = true);
}; };
inline radix_iterator inline radix_iterator
......
...@@ -231,6 +231,9 @@ radix_range::replace(u64 start, u64 size, radix_elem *val) ...@@ -231,6 +231,9 @@ radix_range::replace(u64 start, u64 size, radix_elem *val)
assert(start >= start_); assert(start >= start_);
assert(start + size <= start_ + size_); assert(start + size <= start_ + size_);
// XXX(austin) We will deadlock with ourselves if we try to replace
// a range and the replaced range is on a different level than the
// locked range (because this update_range will try to push_down).
dprintf("%p: replace: [%lx, %lx) with %p\n", r_, start, start + size, val); dprintf("%p: replace: [%lx, %lx) with %p\n", r_, start, start + size, val);
update_range(r_->root_.load(), &r_->root_, [val](radix_entry cur, radix_ptr *ptr) -> radix_entry { update_range(r_->root_.load(), &r_->root_, [val](radix_entry cur, radix_ptr *ptr) -> radix_entry {
do { do {
...@@ -246,6 +249,17 @@ radix_range::replace(u64 start, u64 size, radix_elem *val) ...@@ -246,6 +249,17 @@ radix_range::replace(u64 start, u64 size, radix_elem *val)
}, 0, 1L << key_bits, start, start + size); }, 0, 1L << key_bits, start, start + size);
} }
radix_iterator
radix_iterator::next_change() const
{
radix_elem *cur = **this;
radix_iterator next(*this);
do {
next.advance(false);
} while (next.k_ < next.key_limit_ && *next == cur);
return next;
}
void void
radix_iterator::prime_path() radix_iterator::prime_path()
{ {
...@@ -268,7 +282,7 @@ radix_iterator::prime_path() ...@@ -268,7 +282,7 @@ radix_iterator::prime_path()
} }
void void
radix_iterator::advance() radix_iterator::advance(bool skip_nulls)
{ {
while (true) { while (true) {
// As long as we haven't reached our limit or an element, advance // As long as we haven't reached our limit or an element, advance
...@@ -296,8 +310,8 @@ radix_iterator::advance() ...@@ -296,8 +310,8 @@ radix_iterator::advance()
level_--; level_--;
} }
// Did we reach a non-null leaf? // Did we reach a non-null leaf? (Or do we not care?)
if (!entry.is_null()) if (!skip_nulls || !entry.is_null())
return; return;
} }
} }
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论