Use switch for type dispatch throughout

This commit is contained in:
2024-03-13 10:52:18 -07:00
parent ee86b5289b
commit 797e6b4a3e

View File

@@ -439,36 +439,26 @@ int getNodeIndex(Node16 *self, uint8_t index) {
// Precondition - an entry for index must exist in the node // Precondition - an entry for index must exist in the node
Node *&getChildExists(Node *self, uint8_t index) { Node *&getChildExists(Node *self, uint8_t index) {
if (self->type <= Type::Node16) { switch (self->type) {
case Type::Node0:
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
return self16->children[getNodeIndex(self16, index)].child; return self16->children[getNodeIndex(self16, index)].child;
} else if (self->type == Type::Node48) { }
case Type::Node48: {
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
assert(self48->bitSet.test(index)); assert(self48->bitSet.test(index));
return self48->children[self48->index[index]].child; return self48->children[self48->index[index]].child;
} else { }
case Type::Node256: {
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
assert(self256->bitSet.test(index)); assert(self256->bitSet.test(index));
return self256->children[index].child; return self256->children[index].child;
} }
__builtin_unreachable(); // GCOVR_EXCL_LINE
} }
// Precondition - an entry for index must exist in the node
int64_t getChildMaxVersion(Node *self, uint8_t index) {
if (self->type <= Type::Node16) {
auto *self16 = static_cast<Node16 *>(self);
return self16->children[getNodeIndex(self16, index)].childMaxVersion;
} else if (self->type == Type::Node48) {
auto *self48 = static_cast<Node48 *>(self);
assert(self48->bitSet.test(index));
return self48->children[self48->index[index]].childMaxVersion;
} else {
auto *self256 = static_cast<Node256 *>(self);
assert(self256->bitSet.test(index));
return self256->children[index].childMaxVersion;
}
__builtin_unreachable(); // GCOVR_EXCL_LINE
} }
// Precondition - an entry for index must exist in the node // Precondition - an entry for index must exist in the node
@@ -477,31 +467,38 @@ int64_t &maxVersion(Node *n, ConflictSet::Impl *);
Node *&getInTree(Node *n, ConflictSet::Impl *); Node *&getInTree(Node *n, ConflictSet::Impl *);
Node *getChild(Node *self, uint8_t index) { Node *getChild(Node *self, uint8_t index) {
if (self->type <= Type::Node16) { switch (self->type) {
case Type::Node0:
return nullptr;
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
int i = getNodeIndex(self16, index); int i = getNodeIndex(self16, index);
if (i >= 0) { return i < 0 ? nullptr : self16->children[i].child;
return self16->children[i].child;
} }
return nullptr; case Type::Node48: {
} else if (self->type == Type::Node48) {
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
int secondIndex = self48->index[index]; int i = self48->index[index];
if (secondIndex >= 0) { return i < 0 ? nullptr : self48->children[i].child;
return self48->children[secondIndex].child;
} }
return nullptr; case Type::Node256: {
} else {
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
return self256->children[index].child; return self256->children[index].child;
} }
} }
}
int getChildGeq(Node *self, int child) { int getChildGeq(Node *self, int child) {
if (child > 255) { if (child > 255) {
return -1; return -1;
} }
if (self->type <= Type::Node16) { switch (self->type) {
case Type::Node0:
return -1;
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
#ifdef HAS_AVX #ifdef HAS_AVX
__m128i key_vec = _mm_set1_epi8(child); __m128i key_vec = _mm_set1_epi8(child);
@@ -554,13 +551,17 @@ int getChildGeq(Node *self, int child) {
return self16->index[i]; return self16->index[i];
} }
} }
return -1;
#endif #endif
} else { }
case Type::Node48:
[[fallthrough]];
case Type::Node256: {
static_assert(offsetof(Node48, bitSet) == offsetof(Node256, bitSet)); static_assert(offsetof(Node48, bitSet) == offsetof(Node256, bitSet));
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
return self48->bitSet.firstSetGeq(child); return self48->bitSet.firstSetGeq(child);
} }
return -1; }
} }
void setChildrenParents(Node4 *n) { void setChildrenParents(Node4 *n) {
@@ -591,26 +592,35 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
NodeAllocators *allocators) { NodeAllocators *allocators) {
// Fast path for if it exists already // Fast path for if it exists already
if (self->type <= Type::Node16) { switch (self->type) {
case Type::Node0:
break;
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
int i = getNodeIndex(self16, index); int i = getNodeIndex(self16, index);
if (i >= 0) { if (i >= 0) {
return self16->children[i].child; return self16->children[i].child;
} }
} else if (self->type == Type::Node48) { } break;
case Type::Node48: {
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
int secondIndex = self48->index[index]; int secondIndex = self48->index[index];
if (secondIndex >= 0) { if (secondIndex >= 0) {
return self48->children[secondIndex].child; return self48->children[secondIndex].child;
} }
} else { } break;
case Type::Node256: {
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
if (auto &result = self256->children[index].child; result != nullptr) { if (auto &result = self256->children[index].child; result != nullptr) {
return result; return result;
} }
} break;
} }
if (self->type == Type::Node0) { switch (self->type) {
case Type::Node0: {
auto *self0 = static_cast<Node0 *>(self); auto *self0 = static_cast<Node0 *>(self);
auto *newSelf = allocators->node4.allocate(self->partialKeyLen); auto *newSelf = allocators->node4.allocate(self->partialKeyLen);
@@ -621,8 +631,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
self = newSelf; self = newSelf;
goto insert16; goto insert16;
}
} else if (self->type == Type::Node4) { case Type::Node4: {
auto *self4 = static_cast<Node4 *>(self); auto *self4 = static_cast<Node4 *>(self);
if (self->numChildren == 4) { if (self->numChildren == 4) {
@@ -641,9 +651,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
} }
goto insert16; goto insert16;
}
} else if (self->type == Type::Node16) { case Type::Node16: {
if (self->numChildren == 16) { if (self->numChildren == 16) {
auto *self16 = static_cast<Node16 *>(self); auto *self16 = static_cast<Node16 *>(self);
auto *newSelf = allocators->node48.allocate(self->partialKeyLen); auto *newSelf = allocators->node48.allocate(self->partialKeyLen);
@@ -683,7 +692,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
auto &result = self16->children[i].child; auto &result = self16->children[i].child;
result = nullptr; result = nullptr;
return result; return result;
} else if (self->type == Type::Node48) { }
case Type::Node48: {
if (self->numChildren == 48) { if (self->numChildren == 48) {
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
@@ -713,8 +723,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
auto &result = self48->children[nextFree].child; auto &result = self48->children[nextFree].child;
result = nullptr; result = nullptr;
return result; return result;
} else { }
assert(self->type == Type::Node256); case Type::Node256: {
insert256: insert256:
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
++self->numChildren; ++self->numChildren;
@@ -722,6 +732,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
return self256->children[index].child; return self256->children[index].child;
} }
} }
}
Node *nextPhysical(Node *node) { Node *nextPhysical(Node *node) {
int index = -1; int index = -1;
@@ -1040,7 +1051,12 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
break; break;
} }
if (parent->type <= Type::Node16) { switch (parent->type) {
case Type::Node0:
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *parent16 = static_cast<Node16 *>(parent); auto *parent16 = static_cast<Node16 *>(parent);
int nodeIndex = getNodeIndex(parent16, parentsIndex); int nodeIndex = getNodeIndex(parent16, parentsIndex);
assert(nodeIndex >= 0); assert(nodeIndex >= 0);
@@ -1050,7 +1066,8 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
memmove(parent16->children + nodeIndex, parent16->children + nodeIndex + 1, memmove(parent16->children + nodeIndex, parent16->children + nodeIndex + 1,
sizeof(parent16->children[0]) * sizeof(parent16->children[0]) *
(parent->numChildren - (nodeIndex + 1))); (parent->numChildren - (nodeIndex + 1)));
} else if (parent->type == Type::Node48) { } break;
case Type::Node48: {
auto *parent48 = static_cast<Node48 *>(parent); auto *parent48 = static_cast<Node48 *>(parent);
parent48->bitSet.reset(parentsIndex); parent48->bitSet.reset(parentsIndex);
int8_t toRemoveChildrenIndex = int8_t toRemoveChildrenIndex =
@@ -1064,11 +1081,14 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
parent48->index[parent48->children[toRemoveChildrenIndex] parent48->index[parent48->children[toRemoveChildrenIndex]
.child->parentsIndex] = toRemoveChildrenIndex; .child->parentsIndex] = toRemoveChildrenIndex;
} }
} else { } break;
case Type::Node256: {
auto *parent256 = static_cast<Node256 *>(parent); auto *parent256 = static_cast<Node256 *>(parent);
parent256->bitSet.reset(parentsIndex); parent256->bitSet.reset(parentsIndex);
parent256->children[parentsIndex].child = nullptr; parent256->children[parentsIndex].child = nullptr;
} break;
} }
--parent->numChildren; --parent->numChildren;
if (parent->numChildren == 0 && !parent->entryPresent && if (parent->numChildren == 0 && !parent->entryPresent &&
parent->parent != nullptr) { parent->parent != nullptr) {
@@ -1357,7 +1377,8 @@ downLeftSpine:
} }
// Return the max version among all keys starting with the search path of n + // Return the max version among all keys starting with the search path of n +
// [child], where child in (begin, end) // [child], where child in (begin, end). Does not account for the range version
// of firstGt(searchpath(n) + [end - 1])
int64_t maxBetweenExclusive(Node *n, int begin, int end) { int64_t maxBetweenExclusive(Node *n, int begin, int end) {
assume(-1 <= begin); assume(-1 <= begin);
assume(begin <= 256); assume(begin <= 256);
@@ -1379,7 +1400,8 @@ int64_t maxBetweenExclusive(Node *n, int begin, int end) {
} }
switch (n->type) { switch (n->type) {
case Type::Node0: case Type::Node0:
[[fallthrough]]; // We would have returned above, after not finding a child
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type::Node4: case Type::Node4:
[[fallthrough]]; [[fallthrough]];
case Type::Node16: { case Type::Node16: {
@@ -2239,20 +2261,28 @@ int64_t &maxVersion(Node *n, ConflictSet::Impl *impl) {
if (n == nullptr) { if (n == nullptr) {
return impl->rootMaxVersion; return impl->rootMaxVersion;
} }
if (n->type <= Type::Node16) { switch (n->type) {
case Type::Node0:
__builtin_unreachable(); // GCOVR_EXCL_LINE
case Type::Node4:
[[fallthrough]];
case Type::Node16: {
auto *n16 = static_cast<Node16 *>(n); auto *n16 = static_cast<Node16 *>(n);
int i = getNodeIndex(n16, index); int i = getNodeIndex(n16, index);
return n16->children[i].childMaxVersion; return n16->children[i].childMaxVersion;
} else if (n->type == Type::Node48) { }
case Type::Node48: {
auto *n48 = static_cast<Node48 *>(n); auto *n48 = static_cast<Node48 *>(n);
assert(n48->bitSet.test(index)); assert(n48->bitSet.test(index));
return n48->children[n48->index[index]].childMaxVersion; return n48->children[n48->index[index]].childMaxVersion;
} else { }
case Type::Node256: {
auto *n256 = static_cast<Node256 *>(n); auto *n256 = static_cast<Node256 *>(n);
assert(n256->bitSet.test(index)); assert(n256->bitSet.test(index));
return n256->children[index].childMaxVersion; return n256->children[index].childMaxVersion;
} }
} }
}
Node *&getInTree(Node *n, ConflictSet::Impl *impl) { Node *&getInTree(Node *n, ConflictSet::Impl *impl) {
return n->parent == nullptr ? impl->root return n->parent == nullptr ? impl->root
@@ -2494,16 +2524,6 @@ Iterator firstGeq(Node *n, std::string_view key) {
expected = std::max(expected, borrowed.n->entry.rangeVersion); expected = std::max(expected, borrowed.n->entry.rangeVersion);
} }
} }
if (node->parent != nullptr &&
getChildMaxVersion(node->parent, node->parentsIndex) !=
maxVersion(node, impl)) {
fprintf(stderr,
"%s has max version %" PRId64
" . But parent has child max version %" PRId64 "\n",
getSearchPathPrintable(node).c_str(), maxVersion(node, impl),
getChildMaxVersion(node->parent, node->parentsIndex));
success = false;
}
if (maxVersion(node, impl) > oldestVersion && if (maxVersion(node, impl) > oldestVersion &&
maxVersion(node, impl) != expected) { maxVersion(node, impl) != expected) {
fprintf(stderr, "%s has max version %" PRId64 " . Expected %" PRId64 "\n", fprintf(stderr, "%s has max version %" PRId64 " . Expected %" PRId64 "\n",