diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 41b0078..63829eb 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -1929,14 +1929,118 @@ struct IteratorBase { InternalVersionT exchangeMaxVersion(InternalVersionT); InternalVersionT setMaxVersion(); TrivialSpan partialKey(); + IteratorBase getFirstChild(); + bool checkRangeVersionOfFirstGeq(InternalVersionT readVersion); + struct ChildAndMaxVersion; + ChildAndMaxVersion getChildAndMaxVersion(int index); + IteratorBase getChildGeq(int index); + IteratorBase nextSibling(); -private: +protected: Node *node; // index into children array of particular leaf type int index; }; -template struct Iterator : IteratorBase {}; +struct IteratorBase::ChildAndMaxVersion { + IteratorBase child; + InternalVersionT maxVersion; +}; + +template struct Iterator : IteratorBase { + IteratorBase getFirstChild() { + return IteratorBase(::getFirstChild(static_cast(node))); + } + ChildAndMaxVersion getChildAndMaxVersion(int index) { + auto x = ::getChildAndMaxVersion(static_cast(node), index); + return {IteratorBase{x.child}, x.maxVersion}; + } + IteratorBase getChildGeq(int index) { + return IteratorBase{::getChildGeq(static_cast(node), index)}; + } + TrivialSpan partialKey() { + return {static_cast(node)->partialKey(), node->partialKeyLen}; + } +}; + +TrivialSpan IteratorBase::partialKey() { + switch (node->getType()) { + case Type_Node0: + return as().partialKey(); + case Type_Node3: + return as().partialKey(); + case Type_Node16: + return as().partialKey(); + case Type_Node48: + return as().partialKey(); + case Type_Node256: + return as().partialKey(); + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } +} + +IteratorBase IteratorBase::getFirstChild() { + switch (node->getType()) { + case Type_Node0: + return as().getFirstChild(); + case Type_Node3: + return as().getFirstChild(); + case Type_Node16: + return as().getFirstChild(); + case Type_Node48: + return as().getFirstChild(); + case Type_Node256: + return as().getFirstChild(); + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } +} + +IteratorBase::ChildAndMaxVersion +IteratorBase::getChildAndMaxVersion(int index) { + switch (node->getType()) { + case Type_Node0: + return as().getChildAndMaxVersion(index); + case Type_Node3: + return as().getChildAndMaxVersion(index); + case Type_Node16: + return as().getChildAndMaxVersion(index); + case Type_Node48: + return as().getChildAndMaxVersion(index); + case Type_Node256: + return as().getChildAndMaxVersion(index); + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } +} + +IteratorBase IteratorBase::getChildGeq(int index) { + switch (node->getType()) { + case Type_Node0: + return as().getChildGeq(index); + case Type_Node3: + return as().getChildGeq(index); + case Type_Node16: + return as().getChildGeq(index); + case Type_Node48: + return as().getChildGeq(index); + case Type_Node256: + return as().getChildGeq(index); + default: // GCOVR_EXCL_LINE + __builtin_unreachable(); // GCOVR_EXCL_LINE + } +} + +bool IteratorBase::checkRangeVersionOfFirstGeq(InternalVersionT readVersion) { + return ::checkRangeVersionOfFirstGeq(node, readVersion); +} + +TaggedNodePointer nextSibling(Node *node); + +IteratorBase IteratorBase::nextSibling() { + return IteratorBase{::nextSibling(node)}; +} // Precondition: self is not the root. May invalidate nodes along the search // path to self. May invalidate children of self->parent. Returns a pointer to @@ -4437,7 +4541,7 @@ namespace { // Logically this is the same as performing firstGeq and then checking against // point or range version according to cmp, but this version short circuits as // soon as it can prove that there's no conflict. -bool checkPointRead(Node *n, const TrivialSpan key, +bool checkPointRead(IteratorBase n, const TrivialSpan key, InternalVersionT readVersion, ReadContext *readContext) { ++readContext->point_read_accum; #if DEBUG_VERBOSE && !defined(NDEBUG) @@ -4446,54 +4550,54 @@ bool checkPointRead(Node *n, const TrivialSpan key, auto remaining = key; for (;; ++readContext->point_read_iterations_accum) { if (remaining.size() == 0) { - if (n->entryPresent) { - return n->entry.pointVersion <= readVersion; + if (n.entryPresent()) { + return n.getEntry().pointVersion <= readVersion; } - n = getFirstChild(n); - return checkRangeVersionOfFirstGeq(n, readVersion); + return n.getFirstChild().checkRangeVersionOfFirstGeq(readVersion); } - auto [c, maxV] = getChildAndMaxVersion(n, remaining[0]); - Node *child = c; - if (child == nullptr) { - auto c = getChildGeq(n, remaining[0]); - if (c != nullptr) { - n = c; - return checkRangeVersionOfFirstGeq(n, readVersion); + auto [c, maxV] = n.getChildAndMaxVersion(remaining[0]); + IteratorBase child = c; + if (!child.valid()) { + auto c = n.getChildGeq(remaining[0]); + if (c.valid()) { + return c.checkRangeVersionOfFirstGeq(readVersion); } else { - n = nextSibling(n); - if (n == nullptr) { + n = n.nextSibling(); + if (!n.valid()) { return true; } - return checkRangeVersionOfFirstGeq(n, readVersion); + return n.checkRangeVersionOfFirstGeq(readVersion); } } n = child; remaining = remaining.subspan(1, remaining.size() - 1); - if (n->partialKeyLen > 0) { - int commonLen = std::min(n->partialKeyLen, remaining.size()); - int i = longestCommonPrefix(n->partialKey(), remaining.data(), commonLen); + auto partialKey = n.partialKey(); + if (partialKey.size() > 0) { + int commonLen = std::min(partialKey.size(), remaining.size()); + int i = + longestCommonPrefix(partialKey.data(), remaining.data(), commonLen); if (i < commonLen) { - auto c = n->partialKey()[i] <=> remaining[i]; + auto c = partialKey[i] <=> remaining[i]; if (c > 0) { - return checkRangeVersionOfFirstGeq(n, readVersion); + return n.checkRangeVersionOfFirstGeq(readVersion); } else { - n = nextSibling(n); - if (n == nullptr) { + n = n.nextSibling(); + if (!n.valid()) { return true; } - return checkRangeVersionOfFirstGeq(n, readVersion); + return n.checkRangeVersionOfFirstGeq(readVersion); } } - if (commonLen == n->partialKeyLen) { + if (commonLen == partialKey.size()) { // partial key matches remaining = remaining.subspan(commonLen, remaining.size() - commonLen); - } else if (n->partialKeyLen > remaining.size()) { + } else if (partialKey.size() > remaining.size()) { // n is the first physical node greater than remaining, and there's no // eq node - return checkRangeVersionOfFirstGeq(n, readVersion); + return n.checkRangeVersionOfFirstGeq(readVersion); } } @@ -4753,7 +4857,7 @@ bool checkRangeRead(Node *n, TrivialSpan begin, TrivialSpan end, std::min(begin.size(), end.size())); if (lcp == begin.size() && end.size() == begin.size() + 1 && end.back() == 0) { - return checkPointRead(n, begin, readVersion, readContext); + return checkPointRead(IteratorBase{n}, begin, readVersion, readContext); } if (lcp == begin.size() - 1 && end.size() == begin.size() && begin.back() + 1 == end.back()) { @@ -4829,7 +4933,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { } else { bool ok; if (reads[i].end.len == 0) { - ok = checkPointRead(rootParent->children[0], + ok = checkPointRead(IteratorBase{rootParent->children[0]}, TrivialSpan(reads[i].begin.p, reads[i].begin.len), InternalVersionT(reads[i].readVersion), &context.readContext);