Compare commits
7 Commits
e35d698b21
...
e7719b6e0b
Author | SHA1 | Date | |
---|---|---|---|
e7719b6e0b | |||
83fedf1f9e | |||
8556caf360 | |||
9d13ca84f5 | |||
a79436ee9b | |||
e9c8537cf2 | |||
5b988efe6f |
@@ -154,9 +154,11 @@ if(BUILD_TESTING)
|
||||
file(GLOB CORPUS_TESTS ${CMAKE_SOURCE_DIR}/corpus/*)
|
||||
|
||||
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS}
|
||||
-fsanitize=address,undefined)
|
||||
target_link_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
target_compile_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||
target_link_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||
endif()
|
||||
target_compile_definitions(fuzz_driver PRIVATE ENABLE_FUZZ)
|
||||
target_include_directories(fuzz_driver
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
384
ConflictSet.cpp
384
ConflictSet.cpp
@@ -81,7 +81,7 @@ struct BitSet {
|
||||
int firstSetGeq(int i) const;
|
||||
|
||||
// Calls `f` with the index of each bit set in [begin, end)
|
||||
template <class F> void forEachInRange(F f, int begin, int end) {
|
||||
template <class F> void forEachInRange(F f, int begin, int end) const {
|
||||
// See section 3.1 in https://arxiv.org/pdf/1709.07821.pdf for details about
|
||||
// this approach
|
||||
|
||||
@@ -237,9 +237,18 @@ struct Child {
|
||||
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
|
||||
// children's parent pointers. The caller must then insert the new node into the
|
||||
// tree.
|
||||
|
||||
struct Node0 : Node {
|
||||
constexpr static auto kType = Type_Node0;
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
|
||||
void copyChildrenAndKeyFrom(const Node0 &other);
|
||||
void copyChildrenAndKeyFrom(const struct Node3 &other);
|
||||
};
|
||||
|
||||
struct Node3 : Node {
|
||||
@@ -250,16 +259,11 @@ struct Node3 : Node {
|
||||
Child children[kMaxNodes];
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
|
||||
void copyChildrenAndKeyFrom(const Node0 &other);
|
||||
void copyChildrenAndKeyFrom(const Node3 &other);
|
||||
void copyChildrenAndKeyFrom(const struct Node16 &other);
|
||||
};
|
||||
|
||||
inline void Node3::copyChildrenAndKeyFrom(const Node3 &other) {
|
||||
assert(numChildren == other.numChildren);
|
||||
assert(partialKeyLen == other.partialKeyLen);
|
||||
memcpy(index, other.index,
|
||||
sizeof(*this) - offsetof(Node3, index) + partialKeyLen);
|
||||
}
|
||||
|
||||
struct Node16 : Node {
|
||||
constexpr static auto kType = Type_Node16;
|
||||
constexpr static auto kMaxNodes = 16;
|
||||
@@ -268,35 +272,126 @@ struct Node16 : Node {
|
||||
Child children[kMaxNodes];
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
|
||||
void copyChildrenAndKeyFrom(const Node3 &other);
|
||||
void copyChildrenAndKeyFrom(const Node16 &other);
|
||||
void copyChildrenAndKeyFrom(const struct Node48 &other);
|
||||
};
|
||||
|
||||
inline void Node16::copyChildrenAndKeyFrom(const Node16 &other) {
|
||||
assert(numChildren == other.numChildren);
|
||||
assert(partialKeyLen == other.partialKeyLen);
|
||||
memcpy(index, other.index, sizeof(index));
|
||||
for (int i = 0; i < numChildren; ++i) {
|
||||
children[i] = other.children[i];
|
||||
}
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
struct Node48 : Node {
|
||||
constexpr static auto kType = Type_Node48;
|
||||
constexpr static auto kMaxNodes = 48;
|
||||
BitSet bitSet;
|
||||
Child children[kMaxNodes];
|
||||
int8_t nextFree;
|
||||
int8_t index[256];
|
||||
Child children[kMaxNodes];
|
||||
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
|
||||
void copyChildrenAndKeyFrom(const Node16 &other);
|
||||
void copyChildrenAndKeyFrom(const Node48 &other);
|
||||
void copyChildrenAndKeyFrom(const struct Node256 &other);
|
||||
};
|
||||
|
||||
struct Node256 : Node {
|
||||
constexpr static auto kType = Type_Node256;
|
||||
BitSet bitSet;
|
||||
Child children[256];
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
void copyChildrenAndKeyFrom(const Node48 &other);
|
||||
void copyChildrenAndKeyFrom(const Node256 &other);
|
||||
};
|
||||
|
||||
inline void Node0::copyChildrenAndKeyFrom(const Node0 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node0::copyChildrenAndKeyFrom(const Node3 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node3::copyChildrenAndKeyFrom(const Node0 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node3::copyChildrenAndKeyFrom(const Node3 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(index, other.index,
|
||||
sizeof(*this) - offsetof(Node3, index) + partialKeyLen);
|
||||
for (int i = 0; i < numChildren; ++i) {
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
}
|
||||
}
|
||||
|
||||
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(partialKey(), &other + 1, partialKeyLen);
|
||||
for (int i = 0; i < numChildren; ++i) {
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
}
|
||||
}
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Node16::copyChildrenAndKeyFrom(const Node16 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
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;
|
||||
}
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node16::copyChildrenAndKeyFrom(const Node48 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
int i = 0;
|
||||
other.bitSet.forEachInRange(
|
||||
[&](int c) {
|
||||
// Suppress a false positive -Waggressive-loop-optimizations warning
|
||||
// in gcc. `assume` doesn't work for some reason.
|
||||
if (!(i < Node16::kMaxNodes)) {
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
index[i] = c;
|
||||
children[i] = other.children[other.index[c]];
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
++i;
|
||||
},
|
||||
0, 256);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node48::copyChildrenAndKeyFrom(const Node16 &other) {
|
||||
assert(numChildren == other.numChildren);
|
||||
assert(partialKeyLen == other.partialKeyLen);
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
assert(numChildren == Node16::kMaxNodes);
|
||||
memset(index, -1, sizeof(index));
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
bitSet.init();
|
||||
@@ -306,20 +401,29 @@ 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;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
struct Node256 : Node {
|
||||
constexpr static auto kType = Type_Node256;
|
||||
BitSet bitSet;
|
||||
Child children[256];
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
};
|
||||
inline void Node48::copyChildrenAndKeyFrom(const Node48 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(&bitSet, &other.bitSet,
|
||||
offsetof(Node48, children) - offsetof(Node48, bitSet));
|
||||
for (int i = 0; i < numChildren; ++i) {
|
||||
children[i] = other.children[i];
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
}
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) {
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memset(index, -1, sizeof(index));
|
||||
nextFree = other.numChildren;
|
||||
bitSet = other.bitSet;
|
||||
int i = 0;
|
||||
@@ -332,9 +436,42 @@ inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) {
|
||||
}
|
||||
index[c] = i;
|
||||
children[i] = other.children[c];
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
++i;
|
||||
},
|
||||
0, 256);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node256::copyChildrenAndKeyFrom(const Node48 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memset(children, 0, sizeof(children));
|
||||
bitSet = other.bitSet;
|
||||
bitSet.forEachInRange(
|
||||
[&](int c) {
|
||||
children[c] = other.children[other.index[c]];
|
||||
assert(children[c].child->parent == &other);
|
||||
children[c].child->parent = this;
|
||||
},
|
||||
0, 256);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
inline void Node256::copyChildrenAndKeyFrom(const Node256 &other) {
|
||||
memcpy((char *)this + kNodeCopyBegin, (char *)&other + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memset(children, 0, sizeof(children));
|
||||
bitSet = other.bitSet;
|
||||
bitSet.forEachInRange(
|
||||
[&](int c) {
|
||||
children[c] = other.children[c];
|
||||
assert(children[c].child->parent == &other);
|
||||
children[c].child->parent = this;
|
||||
},
|
||||
0, 256);
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -667,28 +804,6 @@ int getChildGeq(Node *self, int child) {
|
||||
}
|
||||
}
|
||||
|
||||
void setChildrenParents(Node3 *n) {
|
||||
for (int i = 0; i < n->numChildren; ++i) {
|
||||
n->children[i].child->parent = n;
|
||||
}
|
||||
}
|
||||
|
||||
void setChildrenParents(Node16 *n) {
|
||||
for (int i = 0; i < n->numChildren; ++i) {
|
||||
n->children[i].child->parent = n;
|
||||
}
|
||||
}
|
||||
|
||||
void setChildrenParents(Node48 *n) {
|
||||
n->bitSet.forEachInRange(
|
||||
[&](int i) { n->children[n->index[i]].child->parent = n; }, 0, 256);
|
||||
}
|
||||
|
||||
void setChildrenParents(Node256 *n) {
|
||||
n->bitSet.forEachInRange([&](int i) { n->children[i].child->parent = n; }, 0,
|
||||
256);
|
||||
}
|
||||
|
||||
// Caller is responsible for assigning a non-null pointer to the returned
|
||||
// reference if null
|
||||
Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
@@ -734,9 +849,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
auto *self0 = static_cast<Node0 *>(self);
|
||||
|
||||
auto *newSelf = allocators->node3.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self0->partialKey(), self->partialKeyLen);
|
||||
newSelf->copyChildrenAndKeyFrom(*self0);
|
||||
allocators->node0.release(self0);
|
||||
self = newSelf;
|
||||
|
||||
@@ -746,16 +859,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
if (self->numChildren == Node3::kMaxNodes) {
|
||||
auto *self3 = static_cast<Node3 *>(self);
|
||||
auto *newSelf = allocators->node16.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
// TODO replace with memcpy?
|
||||
for (int i = 0; i < Node3::kMaxNodes; ++i) {
|
||||
newSelf->index[i] = self3->index[i];
|
||||
newSelf->children[i] = self3->children[i];
|
||||
}
|
||||
newSelf->copyChildrenAndKeyFrom(*self3);
|
||||
allocators->node3.release(self3);
|
||||
setChildrenParents(newSelf);
|
||||
self = newSelf;
|
||||
goto insert16;
|
||||
}
|
||||
@@ -782,11 +887,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
if (self->numChildren == Node16::kMaxNodes) {
|
||||
auto *self16 = static_cast<Node16 *>(self);
|
||||
auto *newSelf = allocators->node48.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
newSelf->copyChildrenAndKeyFrom(*self16);
|
||||
allocators->node16.release(self16);
|
||||
setChildrenParents(newSelf);
|
||||
self = newSelf;
|
||||
goto insert48;
|
||||
}
|
||||
@@ -816,20 +918,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
if (self->numChildren == 48) {
|
||||
auto *self48 = static_cast<Node48 *>(self);
|
||||
auto *newSelf = allocators->node256.allocate(self->partialKeyLen);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
newSelf->children[i].child = nullptr;
|
||||
}
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self48->partialKey(), self->partialKeyLen);
|
||||
newSelf->bitSet = self48->bitSet;
|
||||
newSelf->bitSet.forEachInRange(
|
||||
[&](int i) {
|
||||
newSelf->children[i] = self48->children[self48->index[i]];
|
||||
},
|
||||
0, 256);
|
||||
newSelf->copyChildrenAndKeyFrom(*self48);
|
||||
allocators->node48.release(self48);
|
||||
setChildrenParents(newSelf);
|
||||
self = newSelf;
|
||||
goto insert256;
|
||||
}
|
||||
@@ -889,9 +979,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
case Type_Node0: {
|
||||
auto *self0 = (Node0 *)self;
|
||||
auto *newSelf = allocators->node0.allocate(capacity);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self0->partialKey(), self->partialKeyLen);
|
||||
newSelf->copyChildrenAndKeyFrom(*self0);
|
||||
getInTree(self, impl) = newSelf;
|
||||
if constexpr (kUseFreeList) {
|
||||
allocators->node0.release(self0);
|
||||
@@ -904,11 +992,8 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
case Type_Node3: {
|
||||
auto *self3 = (Node3 *)self;
|
||||
auto *newSelf = allocators->node3.allocate(capacity);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
newSelf->copyChildrenAndKeyFrom(*self3);
|
||||
getInTree(self, impl) = newSelf;
|
||||
setChildrenParents(newSelf);
|
||||
if constexpr (kUseFreeList) {
|
||||
allocators->node3.release(self3);
|
||||
} else {
|
||||
@@ -920,11 +1005,8 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
case Type_Node16: {
|
||||
auto *self16 = (Node16 *)self;
|
||||
auto *newSelf = allocators->node16.allocate(capacity);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
newSelf->copyChildrenAndKeyFrom(*self16);
|
||||
getInTree(self, impl) = newSelf;
|
||||
setChildrenParents(newSelf);
|
||||
if constexpr (kUseFreeList) {
|
||||
allocators->node16.release(self16);
|
||||
} else {
|
||||
@@ -936,23 +1018,8 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
case Type_Node48: {
|
||||
auto *self48 = (Node48 *)self;
|
||||
auto *newSelf = allocators->node48.allocate(capacity);
|
||||
memset(newSelf->index, -1, sizeof(newSelf->index));
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self48->partialKey(), self->partialKeyLen);
|
||||
newSelf->bitSet = self48->bitSet;
|
||||
// TODO check codegen here?
|
||||
newSelf->nextFree = 0;
|
||||
newSelf->bitSet.forEachInRange(
|
||||
[&](int c) {
|
||||
int index = newSelf->nextFree;
|
||||
newSelf->index[c] = index;
|
||||
newSelf->children[index] = self48->children[self48->index[c]];
|
||||
++newSelf->nextFree;
|
||||
},
|
||||
0, 256);
|
||||
newSelf->copyChildrenAndKeyFrom(*self48);
|
||||
getInTree(self, impl) = newSelf;
|
||||
setChildrenParents(newSelf);
|
||||
if constexpr (kUseFreeList) {
|
||||
allocators->node48.release(self48);
|
||||
} else {
|
||||
@@ -964,17 +1031,8 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
case Type_Node256: {
|
||||
auto *self256 = (Node256 *)self;
|
||||
auto *newSelf = allocators->node256.allocate(capacity);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
newSelf->children[i].child = nullptr;
|
||||
}
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self256->partialKey(), self->partialKeyLen);
|
||||
newSelf->bitSet = self256->bitSet;
|
||||
newSelf->bitSet.forEachInRange(
|
||||
[&](int c) { newSelf->children[c] = self256->children[c]; }, 0, 256);
|
||||
newSelf->copyChildrenAndKeyFrom(*self256);
|
||||
getInTree(self, impl) = newSelf;
|
||||
setChildrenParents(newSelf);
|
||||
if constexpr (kUseFreeList) {
|
||||
allocators->node256.release(self256);
|
||||
} else {
|
||||
@@ -1017,67 +1075,54 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
|
||||
auto *self3 = (Node3 *)self;
|
||||
if (self->numChildren == 0) {
|
||||
auto *newSelf = allocators->node0.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
|
||||
newSelf->copyChildrenAndKeyFrom(*self3);
|
||||
getInTree(self, impl) = newSelf;
|
||||
allocators->node3.release(self3);
|
||||
} else if (self->numChildren == 1) {
|
||||
if (!self->entryPresent) {
|
||||
auto *child = self3->children[0].child;
|
||||
int minCapacity = self3->partialKeyLen + 1 + child->partialKeyLen;
|
||||
} else if (self->numChildren == 1 && !self->entryPresent) {
|
||||
auto *child = self3->children[0].child;
|
||||
int minCapacity = self3->partialKeyLen + 1 + child->partialKeyLen;
|
||||
|
||||
if (minCapacity > child->getCapacity()) {
|
||||
const bool update = child == dontInvalidate;
|
||||
freeAndMakeCapacityAtLeast</*kUseFreeList*/ true>(child, minCapacity,
|
||||
allocators, impl);
|
||||
if (update) {
|
||||
dontInvalidate = child;
|
||||
}
|
||||
if (minCapacity > child->getCapacity()) {
|
||||
const bool update = child == dontInvalidate;
|
||||
freeAndMakeCapacityAtLeast</*kUseFreeList*/ true>(child, minCapacity,
|
||||
allocators, impl);
|
||||
if (update) {
|
||||
dontInvalidate = child;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge partial key with child
|
||||
// Merge partial key with child
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "Merge %s into %s\n",
|
||||
getSearchPathPrintable(self).c_str(),
|
||||
getSearchPathPrintable(child).c_str());
|
||||
fprintf(stderr, "Merge %s into %s\n",
|
||||
getSearchPathPrintable(self).c_str(),
|
||||
getSearchPathPrintable(child).c_str());
|
||||
#endif
|
||||
|
||||
int64_t childMaxVersion = maxVersion(child, impl);
|
||||
int64_t childMaxVersion = maxVersion(child, impl);
|
||||
|
||||
// Construct new partial key for child
|
||||
memmove(child->partialKey() + self3->partialKeyLen + 1,
|
||||
child->partialKey(), child->partialKeyLen);
|
||||
memcpy(child->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
child->partialKey()[self3->partialKeyLen] = self3->index[0];
|
||||
child->partialKeyLen += 1 + self3->partialKeyLen;
|
||||
// Construct new partial key for child
|
||||
memmove(child->partialKey() + self3->partialKeyLen + 1,
|
||||
child->partialKey(), child->partialKeyLen);
|
||||
memcpy(child->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
child->partialKey()[self3->partialKeyLen] = self3->index[0];
|
||||
child->partialKeyLen += 1 + self3->partialKeyLen;
|
||||
|
||||
child->parent = self->parent;
|
||||
child->parentsIndex = self->parentsIndex;
|
||||
child->parent = self->parent;
|
||||
child->parentsIndex = self->parentsIndex;
|
||||
|
||||
// Max versions are stored in the parent, so we need to update it now
|
||||
// that we have a new parent.
|
||||
maxVersion(child, impl) = childMaxVersion;
|
||||
// Max versions are stored in the parent, so we need to update it now
|
||||
// that we have a new parent.
|
||||
maxVersion(child, impl) = childMaxVersion;
|
||||
|
||||
getInTree(self, impl) = child;
|
||||
allocators->node3.release(self3);
|
||||
}
|
||||
getInTree(self, impl) = child;
|
||||
allocators->node3.release(self3);
|
||||
}
|
||||
} break;
|
||||
case Type_Node16:
|
||||
if (self->numChildren + int(self->entryPresent) < kMinChildrenNode16) {
|
||||
auto *self16 = (Node16 *)self;
|
||||
auto *newSelf = allocators->node3.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self16->partialKey(), self->partialKeyLen);
|
||||
static_assert(Node3::kMaxNodes == kMinChildrenNode16 - 1);
|
||||
for (int i = 0; i < Node3::kMaxNodes; ++i) {
|
||||
newSelf->index[i] = self16->index[i];
|
||||
newSelf->children[i] = self16->children[i];
|
||||
}
|
||||
setChildrenParents(newSelf);
|
||||
newSelf->copyChildrenAndKeyFrom(*self16);
|
||||
getInTree(self, impl) = newSelf;
|
||||
allocators->node16.release(self16);
|
||||
}
|
||||
@@ -1086,26 +1131,7 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
|
||||
if (self->numChildren + int(self->entryPresent) < kMinChildrenNode48) {
|
||||
auto *self48 = (Node48 *)self;
|
||||
auto *newSelf = allocators->node16.allocate(self->partialKeyLen);
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
memcpy(newSelf->partialKey(), self48->partialKey(), self->partialKeyLen);
|
||||
|
||||
static_assert(Node16::kMaxNodes == kMinChildrenNode48 - 1);
|
||||
int i = 0;
|
||||
self48->bitSet.forEachInRange(
|
||||
[&](int c) {
|
||||
// Suppress a false positive -Waggressive-loop-optimizations warning
|
||||
// in gcc. `assume` doesn't work for some reason.
|
||||
if (!(i < Node16::kMaxNodes)) {
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
newSelf->index[i] = c;
|
||||
newSelf->children[i] = self48->children[self48->index[c]];
|
||||
++i;
|
||||
},
|
||||
0, 256);
|
||||
|
||||
setChildrenParents(newSelf);
|
||||
newSelf->copyChildrenAndKeyFrom(*self48);
|
||||
getInTree(self, impl) = newSelf;
|
||||
allocators->node48.release(self48);
|
||||
}
|
||||
@@ -1114,11 +1140,7 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
|
||||
if (self->numChildren + int(self->entryPresent) < kMinChildrenNode256) {
|
||||
auto *self256 = (Node256 *)self;
|
||||
auto *newSelf = allocators->node48.allocate(self->partialKeyLen);
|
||||
memset(newSelf->index, -1, sizeof(newSelf->index));
|
||||
memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin,
|
||||
kNodeCopySize);
|
||||
newSelf->copyChildrenAndKeyFrom(*self256);
|
||||
setChildrenParents(newSelf);
|
||||
getInTree(self, impl) = newSelf;
|
||||
allocators->node256.release(self256);
|
||||
}
|
||||
|
Reference in New Issue
Block a user