5 Commits

Author SHA1 Message Date
639518bed4 Share "scan16" between Node16 and Node48
Some checks failed
Tests / Clang total: 1130, passed: 1130
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1130, passed: 1130
Tests / Release [gcc] total: 1130, passed: 1130
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 844, passed: 844
Tests / Coverage total: 848, passed: 848
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-06-27 13:22:51 -07:00
7de983cc15 Simd bounds checking for scan for Node16 2024-06-27 13:08:12 -07:00
1b4b61ddc6 Write Node16 scan in a "more vectorized" style 2024-06-27 12:07:38 -07:00
bff7b85de2 Remove "Child" struct 2024-06-27 10:03:14 -07:00
9108ee209a SoA instead of AoS for child, maxVersion 2024-06-27 09:57:54 -07:00

View File

@@ -236,11 +236,6 @@ constexpr int kNodeCopyBegin = offsetof(Node, entry);
constexpr int kNodeCopySize =
offsetof(Node, parentsIndex) + sizeof(Node::parentsIndex) - kNodeCopyBegin;
struct Child {
int64_t childMaxVersion;
Node *child;
};
// copyChildrenAndKeyFrom is responsible for copying all
// public members of Node, copying the partial key, logically copying the
// children (converting representation if necessary), and updating all the
@@ -262,7 +257,8 @@ struct Node3 : Node {
constexpr static auto kType = Type_Node3;
// Sorted
uint8_t index[kMaxNodes];
Child children[kMaxNodes];
Node *children[kMaxNodes];
int64_t childMaxVersion[kMaxNodes];
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
void copyChildrenAndKeyFrom(const Node0 &other);
@@ -277,7 +273,8 @@ struct Node16 : Node {
constexpr static auto kMaxNodes = 16;
// Sorted
uint8_t index[kMaxNodes];
Child children[kMaxNodes];
Node *children[kMaxNodes];
int64_t childMaxVersion[kMaxNodes];
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
void copyChildrenAndKeyFrom(const Node3 &other);
@@ -293,9 +290,10 @@ struct Node48 : Node {
BitSet bitSet;
int8_t nextFree;
int8_t index[256];
Child children[kMaxNodes];
Node *children[kMaxNodes];
int64_t childMaxVersion[kMaxNodes];
uint8_t reverseIndex[kMaxNodes];
constexpr static int kMaxOfMaxPageSize = 8;
constexpr static int kMaxOfMaxPageSize = 16;
constexpr static int kMaxOfMaxShift =
std::countr_zero(uint32_t(kMaxOfMaxPageSize));
constexpr static int kMaxOfMaxTotalPages = kMaxNodes / kMaxOfMaxPageSize;
@@ -313,7 +311,8 @@ struct Node48 : Node {
struct Node256 : Node {
constexpr static auto kType = Type_Node256;
BitSet bitSet;
Child children[256];
Node *children[256];
int64_t childMaxVersion[256];
constexpr static int kMaxOfMaxPageSize = 8;
constexpr static int kMaxOfMaxShift =
std::countr_zero(uint32_t(kMaxOfMaxPageSize));
@@ -350,8 +349,8 @@ inline void Node3::copyChildrenAndKeyFrom(const Node3 &other) {
memcpy(index, other.index, sizeof(*this) - sizeof(Node));
memcpy(partialKey(), &other + 1, partialKeyLen);
for (int i = 0; i < numChildren; ++i) {
assert(children[i].child->parent == &other);
children[i].child->parent = this;
assert(children[i]->parent == &other);
children[i]->parent = this;
}
}
@@ -359,11 +358,13 @@ inline void Node3::copyChildrenAndKeyFrom(const Node16 &other) {
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
kNodeCopySize);
memcpy(index, other.index, kMaxNodes);
memcpy(children, other.children, kMaxNodes * sizeof(Child));
memcpy(children, other.children, kMaxNodes * sizeof(children[0])); // NOLINT
memcpy(childMaxVersion, other.childMaxVersion,
kMaxNodes * sizeof(childMaxVersion[0]));
memcpy(partialKey(), &other + 1, partialKeyLen);
for (int i = 0; i < numChildren; ++i) {
assert(children[i].child->parent == &other);
children[i].child->parent = this;
assert(children[i]->parent == &other);
children[i]->parent = this;
}
}
@@ -371,12 +372,15 @@ inline void Node16::copyChildrenAndKeyFrom(const Node3 &other) {
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
kNodeCopySize);
memcpy(index, other.index, Node3::kMaxNodes);
memcpy(children, other.children, Node3::kMaxNodes * sizeof(Child));
memcpy(children, other.children,
Node3::kMaxNodes * sizeof(children[0])); // NOLINT
memcpy(childMaxVersion, other.childMaxVersion,
Node3::kMaxNodes * sizeof(childMaxVersion[0]));
memcpy(partialKey(), &other + 1, partialKeyLen);
assert(numChildren == Node3::kMaxNodes);
for (int i = 0; i < Node3::kMaxNodes; ++i) {
assert(children[i].child->parent == &other);
children[i].child->parent = this;
assert(children[i]->parent == &other);
children[i]->parent = this;
}
}
@@ -386,8 +390,9 @@ inline void Node16::copyChildrenAndKeyFrom(const Node16 &other) {
memcpy(index, other.index, sizeof(index));
for (int i = 0; i < numChildren; ++i) {
children[i] = other.children[i];
assert(children[i].child->parent == &other);
children[i].child->parent = this;
childMaxVersion[i] = other.childMaxVersion[i];
assert(children[i]->parent == &other);
children[i]->parent = this;
}
memcpy(partialKey(), &other + 1, partialKeyLen);
}
@@ -403,8 +408,9 @@ inline void Node16::copyChildrenAndKeyFrom(const Node48 &other) {
assume(i < Node16::kMaxNodes);
index[i] = c;
children[i] = other.children[other.index[c]];
assert(children[i].child->parent == &other);
children[i].child->parent = this;
childMaxVersion[i] = other.childMaxVersion[other.index[c]];
assert(children[i]->parent == &other);
children[i]->parent = this;
++i;
},
0, 256);
@@ -417,6 +423,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node16 &other) {
assert(numChildren == Node16::kMaxNodes);
memset(index, -1, sizeof(index));
memset(children, 0, sizeof(children));
memset(childMaxVersion, 0, sizeof(childMaxVersion));
memcpy(partialKey(), &other + 1, partialKeyLen);
bitSet.init();
nextFree = Node16::kMaxNodes;
@@ -425,11 +432,12 @@ inline void Node48::copyChildrenAndKeyFrom(const Node16 &other) {
bitSet.set(x);
index[x] = i;
children[i] = other.children[i];
assert(children[i].child->parent == &other);
children[i].child->parent = this;
childMaxVersion[i] = other.childMaxVersion[i];
assert(children[i]->parent == &other);
children[i]->parent = this;
reverseIndex[i] = x;
maxOfMax[i >> Node48::kMaxOfMaxShift] = std::max(
maxOfMax[i >> Node48::kMaxOfMaxShift], children[i].childMaxVersion);
maxOfMax[i >> Node48::kMaxOfMaxShift] =
std::max(maxOfMax[i >> Node48::kMaxOfMaxShift], childMaxVersion[i]);
++i;
}
}
@@ -441,10 +449,12 @@ inline void Node48::copyChildrenAndKeyFrom(const Node48 &other) {
nextFree = other.nextFree;
memcpy(index, other.index, sizeof(index));
memset(children, 0, sizeof(children));
memset(childMaxVersion, 0, sizeof(childMaxVersion));
for (int i = 0; i < numChildren; ++i) {
children[i] = other.children[i];
assert(children[i].child->parent == &other);
children[i].child->parent = this;
childMaxVersion[i] = other.childMaxVersion[i];
assert(children[i]->parent == &other);
children[i]->parent = this;
}
memcpy(reverseIndex, other.reverseIndex, sizeof(reverseIndex));
memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax));
@@ -456,6 +466,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) {
kNodeCopySize);
memset(index, -1, sizeof(index));
memset(children, 0, sizeof(children));
memset(childMaxVersion, 0, sizeof(childMaxVersion));
nextFree = other.numChildren;
bitSet = other.bitSet;
int i = 0;
@@ -466,11 +477,12 @@ inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) {
assume(i < Node48::kMaxNodes);
index[c] = i;
children[i] = other.children[c];
assert(children[i].child->parent == &other);
children[i].child->parent = this;
childMaxVersion[i] = other.childMaxVersion[c];
assert(children[i]->parent == &other);
children[i]->parent = this;
reverseIndex[i] = c;
maxOfMax[i >> Node48::kMaxOfMaxShift] = std::max(
maxOfMax[i >> Node48::kMaxOfMaxShift], children[i].childMaxVersion);
maxOfMax[i >> Node48::kMaxOfMaxShift] =
std::max(maxOfMax[i >> Node48::kMaxOfMaxShift], childMaxVersion[i]);
++i;
},
0, 256);
@@ -482,15 +494,16 @@ inline void Node256::copyChildrenAndKeyFrom(const Node48 &other) {
kNodeCopySize);
bitSet = other.bitSet;
memset(children, 0, sizeof(children));
memset(childMaxVersion, 0, sizeof(childMaxVersion));
memset(maxOfMax, 0, sizeof(maxOfMax));
bitSet.forEachInRange(
[&](int c) {
children[c] = other.children[other.index[c]];
assert(children[c].child->parent == &other);
children[c].child->parent = this;
maxOfMax[c >> Node256::kMaxOfMaxShift] =
std::max(maxOfMax[c >> Node256::kMaxOfMaxShift],
children[c].childMaxVersion);
childMaxVersion[c] = other.childMaxVersion[other.index[c]];
assert(children[c]->parent == &other);
children[c]->parent = this;
maxOfMax[c >> Node256::kMaxOfMaxShift] = std::max(
maxOfMax[c >> Node256::kMaxOfMaxShift], childMaxVersion[c]);
},
0, 256);
memcpy(partialKey(), &other + 1, partialKeyLen);
@@ -500,12 +513,14 @@ inline void Node256::copyChildrenAndKeyFrom(const Node256 &other) {
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
kNodeCopySize);
memset(children, 0, sizeof(children));
memset(childMaxVersion, 0, sizeof(childMaxVersion));
bitSet = other.bitSet;
bitSet.forEachInRange(
[&](int c) {
children[c] = other.children[c];
assert(children[c].child->parent == &other);
children[c].child->parent = this;
childMaxVersion[c] = other.childMaxVersion[c];
assert(children[c]->parent == &other);
children[c]->parent = this;
},
0, 256);
memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax));
@@ -592,6 +607,7 @@ template <class T> struct BoundedFreeListAllocator {
T *result = allocate_helper(partialKeyCapacity);
if constexpr (!std::is_same_v<T, Node0>) {
memset(result->children, 0, sizeof(result->children));
memset(result->childMaxVersion, 0, sizeof(result->childMaxVersion));
}
if constexpr (std::is_same_v<T, Node48> || std::is_same_v<T, Node256>) {
memset(result->maxOfMax, 0, sizeof(result->maxOfMax));
@@ -750,21 +766,21 @@ Node *&getChildExists(Node *self, uint8_t index) {
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: {
auto *self3 = static_cast<Node3 *>(self);
return self3->children[getNodeIndex(self3, index)].child;
return self3->children[getNodeIndex(self3, index)];
}
case Type_Node16: {
auto *self16 = static_cast<Node16 *>(self);
return self16->children[getNodeIndex(self16, index)].child;
return self16->children[getNodeIndex(self16, index)];
}
case Type_Node48: {
auto *self48 = static_cast<Node48 *>(self);
assert(self48->bitSet.test(index));
return self48->children[self48->index[index]].child;
return self48->children[self48->index[index]];
}
case Type_Node256: {
auto *self256 = static_cast<Node256 *>(self);
assert(self256->bitSet.test(index));
return self256->children[index].child;
return self256->children[index];
}
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
@@ -784,21 +800,21 @@ Node *getChild(Node *self, uint8_t index) {
case Type_Node3: {
auto *self3 = static_cast<Node3 *>(self);
int i = getNodeIndex(self3, index);
return i < 0 ? nullptr : self3->children[i].child;
return i < 0 ? nullptr : self3->children[i];
}
case Type_Node16: {
auto *self16 = static_cast<Node16 *>(self);
int i = getNodeIndex(self16, index);
return i < 0 ? nullptr : self16->children[i].child;
return i < 0 ? nullptr : self16->children[i];
}
case Type_Node48: {
auto *self48 = static_cast<Node48 *>(self);
int i = self48->index[index];
return i < 0 ? nullptr : self48->children[i].child;
return i < 0 ? nullptr : self48->children[i];
}
case Type_Node256: {
auto *self256 = static_cast<Node256 *>(self);
return self256->children[index].child;
return self256->children[index];
}
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
@@ -914,26 +930,26 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
auto *self3 = static_cast<Node3 *>(self);
int i = getNodeIndex(self3, index);
if (i >= 0) {
return self3->children[i].child;
return self3->children[i];
}
} break;
case Type_Node16: {
auto *self16 = static_cast<Node16 *>(self);
int i = getNodeIndex(self16, index);
if (i >= 0) {
return self16->children[i].child;
return self16->children[i];
}
} break;
case Type_Node48: {
auto *self48 = static_cast<Node48 *>(self);
int secondIndex = self48->index[index];
if (secondIndex >= 0) {
return self48->children[secondIndex].child;
return self48->children[secondIndex];
}
} break;
case Type_Node256: {
auto *self256 = static_cast<Node256 *>(self);
if (auto &result = self256->children[index].child; result != nullptr) {
if (auto &result = self256->children[index]; result != nullptr) {
return result;
}
} break;
@@ -971,12 +987,16 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
memmove(self3->index + i + 1, self3->index + i,
self->numChildren - (i + 1));
memmove(self3->children + i + 1, self3->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
(self->numChildren - (i + 1)) *
sizeof(self3->children[0])); // NOLINT
memmove(self3->childMaxVersion + i + 1, self3->childMaxVersion + i,
(self->numChildren - (i + 1)) *
sizeof(self3->childMaxVersion[0]));
break;
}
}
self3->index[i] = index;
auto &result = self3->children[i].child;
auto &result = self3->children[i];
result = nullptr;
return result;
}
@@ -1008,7 +1028,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
memmove(self16->index + i + 1, self16->index + i,
self->numChildren - (i + 1));
memmove(self16->children + i + 1, self16->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
(self->numChildren - (i + 1)) * sizeof(self16->children[0]));
memmove(self16->childMaxVersion + i + 1, self16->childMaxVersion + i,
(self->numChildren - (i + 1)) *
sizeof(self16->childMaxVersion[0]));
}
#elif defined(HAS_ARM_NEON)
uint8x16_t indices;
@@ -1028,7 +1051,11 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
memmove(self16->index + i + 1, self16->index + i,
self->numChildren - (i + 1));
memmove(self16->children + i + 1, self16->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
(self->numChildren - (i + 1)) *
sizeof(self16->children[0])); // NOLINT
memmove(self16->childMaxVersion + i + 1, self16->childMaxVersion + i,
(self->numChildren - (i + 1)) *
sizeof(self16->childMaxVersion[0]));
}
#else
int i = 0;
@@ -1037,13 +1064,16 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
memmove(self16->index + i + 1, self16->index + i,
self->numChildren - (i + 1));
memmove(self16->children + i + 1, self16->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
(self->numChildren - (i + 1)) * sizeof(self16->children[0]));
memmove(self16->childMaxVersion + i + 1, self16->childMaxVersion + i,
(self->numChildren - (i + 1)) *
sizeof(self16->childMaxVersion[0]));
break;
}
}
#endif
self16->index[i] = index;
auto &result = self16->children[i].child;
auto &result = self16->children[i];
result = nullptr;
return result;
}
@@ -1066,7 +1096,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
int nextFree = self48->nextFree++;
self48->index[index] = nextFree;
self48->reverseIndex[nextFree] = index;
auto &result = self48->children[nextFree].child;
auto &result = self48->children[nextFree];
result = nullptr;
return result;
}
@@ -1076,7 +1106,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
auto *self256 = static_cast<Node256 *>(self);
++self->numChildren;
self256->bitSet.set(index);
return self256->children[index].child;
return self256->children[index];
}
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
@@ -1219,7 +1249,7 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
getInTree(self, impl) = newSelf;
allocators->node3.release(self3);
} else if (self->numChildren == 1 && !self->entryPresent) {
auto *child = self3->children[0].child;
auto *child = self3->children[0];
int minCapacity = self3->partialKeyLen + 1 + child->partialKeyLen;
if (minCapacity > child->getCapacity()) {
@@ -1332,7 +1362,11 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
sizeof(parent3->index[0]) *
(parent->numChildren - (nodeIndex + 1)));
memmove(parent3->children + nodeIndex, parent3->children + nodeIndex + 1,
sizeof(parent3->children[0]) *
sizeof(parent3->children[0]) * // NOLINT
(parent->numChildren - (nodeIndex + 1)));
memmove(parent3->childMaxVersion + nodeIndex,
parent3->childMaxVersion + nodeIndex + 1,
sizeof(parent3->childMaxVersion[0]) *
(parent->numChildren - (nodeIndex + 1)));
--parent->numChildren;
@@ -1346,7 +1380,11 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
sizeof(parent16->index[0]) *
(parent->numChildren - (nodeIndex + 1)));
memmove(parent16->children + nodeIndex, parent16->children + nodeIndex + 1,
sizeof(parent16->children[0]) *
sizeof(parent16->children[0]) * // NOLINT
(parent->numChildren - (nodeIndex + 1)));
memmove(parent16->childMaxVersion + nodeIndex,
parent16->childMaxVersion + nodeIndex + 1,
sizeof(parent16->childMaxVersion[0]) *
(parent->numChildren - (nodeIndex + 1)));
--parent->numChildren;
@@ -1365,16 +1403,18 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
if (toRemoveChildrenIndex != lastChildrenIndex) {
parent48->children[toRemoveChildrenIndex] =
parent48->children[lastChildrenIndex];
parent48->childMaxVersion[toRemoveChildrenIndex] =
parent48->childMaxVersion[lastChildrenIndex];
parent48->maxOfMax[toRemoveChildrenIndex >> Node48::kMaxOfMaxShift] =
std::max(parent48->maxOfMax[toRemoveChildrenIndex >>
Node48::kMaxOfMaxShift],
parent48->children[toRemoveChildrenIndex].childMaxVersion);
parent48->childMaxVersion[toRemoveChildrenIndex]);
auto parentIndex =
parent48->children[toRemoveChildrenIndex].child->parentsIndex;
parent48->children[toRemoveChildrenIndex]->parentsIndex;
parent48->index[parentIndex] = toRemoveChildrenIndex;
parent48->reverseIndex[toRemoveChildrenIndex] = parentIndex;
}
parent48->children[lastChildrenIndex].childMaxVersion = 0;
parent48->childMaxVersion[lastChildrenIndex] = 0;
--parent->numChildren;
@@ -1384,7 +1424,7 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
case Type_Node256: {
auto *parent256 = static_cast<Node256 *>(parent);
parent256->bitSet.reset(parentsIndex);
parent256->children[parentsIndex].child = nullptr;
parent256->children[parentsIndex] = nullptr;
--parent->numChildren;
@@ -1669,6 +1709,47 @@ downLeftSpine:
}
}
// Returns true if all in-bounds vs are <= readVersion
bool scan16(const int64_t *vs, const uint8_t *is, int begin, int end,
int64_t readVersion) {
#ifdef HAS_ARM_NEON
assert(end - begin < 256);
uint8x16_t indices;
memcpy(&indices, is, 16);
// 0xff for each in bounds
auto results =
vcltq_u8(vsubq_u8(indices, vdupq_n_u8(begin)), vdupq_n_u8(end - begin));
// 0xf for each 0xff
uint64_t mask = vget_lane_u64(
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(results), 4)), 0);
uint64_t compared = 0;
for (int i = 0; i < 16; ++i) {
compared |= (uint64_t(vs[i] > readVersion) << (i << 2));
}
return !(compared & mask);
#else
const unsigned shiftUpperBound = end - begin;
const unsigned shiftAmount = begin;
auto inBounds = [&](unsigned c) { return c - shiftAmount < shiftUpperBound; };
uint32_t compared = 0;
for (int i = 0; i < 16; ++i) {
compared |= ((vs[i] > readVersion) << i);
}
uint32_t mask = 0;
for (int i = 0; i < 16; ++i) {
mask |= inBounds(is[i]) << i;
}
return !(compared & mask);
#endif
}
// Return whether or not the max version among all keys starting with the search
// path of n + [child], where child in (begin, end) is <= readVersion. Does not
// account for the range version of firstGt(searchpath(n) + [end - 1])
@@ -1679,6 +1760,9 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
assume(-1 <= end);
assume(end <= 256);
assume(begin < end);
assert(!(begin == -1 && end == 256));
{
int c = getChildGeq(n, begin + 1);
if (c >= 0 && c < end) {
@@ -1708,34 +1792,31 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
auto *self = static_cast<Node3 *>(n);
bool result = true;
for (int i = 0; i < 3; ++i) {
result &= !((self->children[i].childMaxVersion > readVersion) &
result &= !((self->childMaxVersion[i] > readVersion) &
inBounds(self->index[i]));
}
return result;
} break;
case Type_Node16: {
auto *self = static_cast<Node16 *>(n);
bool result = true;
for (int i = 0; i < 16; ++i) {
result &= !((self->children[i].childMaxVersion > readVersion) &
inBounds(self->index[i]));
}
return result;
return scan16(self->childMaxVersion, self->index, begin, end, readVersion);
} break;
case Type_Node48: {
auto *self = static_cast<Node48 *>(n);
// Check all pages
bool result = true;
static_assert(Node48::kMaxOfMaxPageSize == 16);
for (int i = 0; i < Node48::kMaxOfMaxTotalPages; ++i) {
if (self->maxOfMax[i] > readVersion) {
for (int j = 0; j < Node48::kMaxOfMaxPageSize; ++j) {
int k = (i << Node48::kMaxOfMaxShift) + j;
result &= !((self->children[k].childMaxVersion > readVersion) &
inBounds(self->reverseIndex[k]));
if (!scan16(self->childMaxVersion + (i << Node48::kMaxOfMaxShift),
self->reverseIndex + (i << Node48::kMaxOfMaxShift), begin,
end, readVersion)) {
return false;
}
}
}
return result;
return true;
}
case Type_Node256: {
auto *self = static_cast<Node256 *>(n);
@@ -1744,8 +1825,7 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
bool result = true;
for (int i = 0; i < Node256::kMaxOfMaxPageSize; ++i) {
int j = (begin & ~(Node256::kMaxOfMaxPageSize - 1)) + i;
result &=
!((self->children[j].childMaxVersion > readVersion) & inBounds(j));
result &= !((self->childMaxVersion[j] > readVersion) & inBounds(j));
}
if (!result) {
return result;
@@ -1757,8 +1837,7 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
bool result = true;
for (int i = 0; i < Node256::kMaxOfMaxPageSize; ++i) {
int j = ((end - 1) & ~(Node256::kMaxOfMaxPageSize - 1)) + i;
result &=
!((self->children[j].childMaxVersion > readVersion) & inBounds(j));
result &= !((self->childMaxVersion[j] > readVersion) & inBounds(j));
}
if (!result) {
return result;
@@ -2649,22 +2728,22 @@ int64_t maxVersion(Node *n, ConflictSet::Impl *impl) {
case Type_Node3: {
auto *n3 = static_cast<Node3 *>(n);
int i = getNodeIndex(n3, index);
return n3->children[i].childMaxVersion;
return n3->childMaxVersion[i];
}
case Type_Node16: {
auto *n16 = static_cast<Node16 *>(n);
int i = getNodeIndex(n16, index);
return n16->children[i].childMaxVersion;
return n16->childMaxVersion[i];
}
case Type_Node48: {
auto *n48 = static_cast<Node48 *>(n);
assert(n48->bitSet.test(index));
return n48->children[n48->index[index]].childMaxVersion;
return n48->childMaxVersion[n48->index[index]];
}
case Type_Node256: {
auto *n256 = static_cast<Node256 *>(n);
assert(n256->bitSet.test(index));
return n256->children[index].childMaxVersion;
return n256->childMaxVersion[index];
}
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
@@ -2684,20 +2763,20 @@ void setMaxVersion(Node *n, ConflictSet::Impl *impl, int64_t newMax) {
case Type_Node3: {
auto *n3 = static_cast<Node3 *>(n);
int i = getNodeIndex(n3, index);
n3->children[i].childMaxVersion = newMax;
n3->childMaxVersion[i] = newMax;
return;
}
case Type_Node16: {
auto *n16 = static_cast<Node16 *>(n);
int i = getNodeIndex(n16, index);
n16->children[i].childMaxVersion = newMax;
n16->childMaxVersion[i] = newMax;
return;
}
case Type_Node48: {
auto *n48 = static_cast<Node48 *>(n);
assert(n48->bitSet.test(index));
int i = n48->index[index];
n48->children[i].childMaxVersion = newMax;
n48->childMaxVersion[i] = newMax;
n48->maxOfMax[i >> Node48::kMaxOfMaxShift] =
std::max(n48->maxOfMax[i >> Node48::kMaxOfMaxShift], newMax);
return;
@@ -2705,7 +2784,7 @@ void setMaxVersion(Node *n, ConflictSet::Impl *impl, int64_t newMax) {
case Type_Node256: {
auto *n256 = static_cast<Node256 *>(n);
assert(n256->bitSet.test(index));
n256->children[index].childMaxVersion = newMax;
n256->childMaxVersion[index] = newMax;
n256->maxOfMax[index >> Node256::kMaxOfMaxShift] =
std::max(n256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMax);
return;