Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/*.csv
build/
.DS_Store
.DS_Store
results/
165 changes: 159 additions & 6 deletions ART.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,23 @@ namespace ART {

class ART {
public:
ArtNode* root; // pointer to root node
ArtNode* fp; // fast path
std::array<ArtNode*, maxPrefixLength> fp_path; // fp path
size_t fp_path_length; // stores real length of fp path
ArtNode* fp_leaf;
ArtNode* root; // pointer to root node of tree
ArtNode* fp; // pointer to fast path node
std::array<ArtNode*, maxPrefixLength> fp_path; // path that leads to fp
size_t fp_path_length; // stores length of fp path
ArtNode* fp_leaf; // pointer to leaf node in fast path
size_t fp_depth; // depth that will be used during fp insertion
ArtNode** fp_ref; // reference to fp node, used for insertion

// constructor
ART() { root = NULL; }
ART()
: root(nullptr),
fp(nullptr),
fp_path{nullptr},
fp_path_length(0),
fp_leaf(nullptr),
fp_depth(0),
fp_ref(nullptr) {}

void insert(uint8_t key[], uintptr_t value) {
insert(this, root, &root, key, 0, value, maxPrefixLength);
Expand All @@ -58,6 +67,97 @@ class ART {
depth, maxKeyLength);
}

void printTree() { printTree(this->root, 0); }

// Method to verify the tail path after each insertion
bool verifyTailPath() {
if (this->fp_path_length == 0) {
return true;
}

ArtNode* current = this->root;
// Traverse the tree following the fp_path
for (size_t i = 0; i < this->fp_path_length; i++) {
if (i == this->fp_path_length - 1) {
if (current == this->fp) {
Comment thread
cangokmen marked this conversation as resolved.
if (getLeafValue(maximum(current)) ==
getLeafValue(this->fp_leaf)) {
return true;
} else {
printf(
Comment thread
cangokmen marked this conversation as resolved.
Outdated
"Error: fp_leaf mismatch. Expected %lu, got %lu.\n",
getLeafValue(maximum(current)),
getLeafValue(this->fp_leaf));
return false;
}
} else {
printf(
Comment thread
cangokmen marked this conversation as resolved.
Outdated
"Error: last node in fp_path is not the fp. Expected "
"%p, got %p.\n",
static_cast<void*>(current),
static_cast<void*>(this->fp));
return false;
}
}

// Move to the rightmost child
switch (current->type) {
case NodeType4: {
Node4* node = static_cast<Node4*>(current);
if (node->count > 0) {
current = node->child[node->count - 1];
} else {
printf("Error: NodeType4 has no children.\n");
Comment thread
cangokmen marked this conversation as resolved.
Outdated
return false;
}
break;
}
case NodeType16: {
Node16* node = static_cast<Node16*>(current);
if (node->count > 0) {
current = node->child[node->count - 1];
} else {
printf("Error: NodeType16 has no children.\n");
Comment thread
cangokmen marked this conversation as resolved.
Outdated
return false;
}
break;
}
case NodeType48: {
Node48* node = static_cast<Node48*>(current);
unsigned pos = 255;
while (pos > 0 && node->childIndex[pos] == emptyMarker)
pos--;
if (node->childIndex[pos] != emptyMarker) {
current = node->child[node->childIndex[pos]];
} else {
printf("Error: NodeType48 has no valid children.\n");
Comment thread
cangokmen marked this conversation as resolved.
Outdated
return false;
}
break;
}
case NodeType256: {
Node256* node = static_cast<Node256*>(current);
unsigned pos = 255;
while (pos > 0 && !node->child[pos]) pos--;
if (node->child[pos]) {
current = node->child[pos];
} else {
printf("Error: NodeType256 has no valid children.\n");
Comment thread
cangokmen marked this conversation as resolved.
Outdated
return false;
}
break;
}
default:
printf("Error: Unknown node type.\n");
Comment thread
cangokmen marked this conversation as resolved.
Outdated
return false;
}
}

// If we exit the loop without returning, the path is incorrect
printf("Error: fp_path does not lead to the fp.\n");
return false;
}

private:
// Void insert function
void insert(ART* tree, ArtNode* node, ArtNode** nodeRef, uint8_t key[],
Expand Down Expand Up @@ -321,5 +421,58 @@ class ART {
delete queue;
return result;
}

void printTree(ArtNode* node, int depth) {
if (!node) return;

// Indent based on depth
for (int i = 0; i < depth; i++) {
printf(" ");
}

if (isLeaf(node)) {
printf("Leaf(%lu)\n", getLeafValue(node));
return;
}

switch (node->type) {
case NodeType4: {
Node4* n = static_cast<Node4*>(node);
printf("Node4 [%p]\n", static_cast<void*>(n));
for (unsigned i = 0; i < n->count; i++) {
printTree(n->child[i], depth + 1);
}
break;
}
case NodeType16: {
Node16* n = static_cast<Node16*>(node);
printf("Node16 [%p]\n", static_cast<void*>(n));
for (unsigned i = 0; i < n->count; i++) {
printTree(n->child[i], depth + 1);
}
break;
}
case NodeType48: {
Node48* n = static_cast<Node48*>(node);
printf("Node48 [%p]\n", static_cast<void*>(n));
for (unsigned i = 0; i < 256; i++) {
if (n->childIndex[i] != emptyMarker) {
printTree(n->child[n->childIndex[i]], depth + 1);
}
}
break;
}
case NodeType256: {
Node256* n = static_cast<Node256*>(node);
printf("Node256 [%p]\n", static_cast<void*>(n));
for (unsigned i = 0; i < 256; i++) {
if (n->child[i]) {
printTree(n->child[i], depth + 1);
}
}
break;
}
}
}
};
} // namespace ART
66 changes: 64 additions & 2 deletions ArtNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,16 @@ struct Node4 : ArtNode {
memset(child, 0, sizeof(child));
}

// Base ART insert function for Node4
void insertNode4(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child);
// Insert function used in base tail insert. Checks if fp structures need
// to be updated and updates if necessary
void tailInsertNode4(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child,
std::array<ArtNode*, maxPrefixLength>& temp_fp_path,
size_t& temp_fp_path_length, size_t depth_prev);
// Erase function for Node4
void eraseNode4(ART* tree, ArtNode** nodeRef, ArtNode** leafPlace);
};

Expand All @@ -84,8 +92,16 @@ struct Node16 : ArtNode {
memset(child, 0, sizeof(child));
}

// Base ART insert function for Node16
void insertNode16(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child);
// Insert function used in base tail insert. Checks if fp structures need
// to be updated and updates if necessary.
void tailInsertNode16(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child,
std::array<ArtNode*, maxPrefixLength>& temp_fp_path,
size_t& temp_fp_path_length, size_t depth_prev);
// Erase function for Node16
void eraseNode16(ART* tree, ArtNode** nodeRef, ArtNode** leafPlace);
};

Expand All @@ -99,8 +115,16 @@ struct Node48 : ArtNode {
memset(child, 0, sizeof(child));
}

// Base ART insert function for Node48
void insertNode48(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child);
// Insert function used in base tail insert. Checks if fp structures need
// to be updated and updates if necessary.
void tailInsertNode48(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child,
std::array<ArtNode*, maxPrefixLength>& temp_fp_path,
size_t& temp_fp_path_length, size_t depth_prev);
// Erase function for Node48
void eraseNode48(ART* tree, ArtNode** nodeRef, uint8_t keyByte);
};

Expand All @@ -110,8 +134,16 @@ struct Node256 : ArtNode {

Node256() : ArtNode(NodeType256) { memset(child, 0, sizeof(child)); }

// Base ART insert function for Node256
void insertNode256(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child);
// Insert function used in base tail insert. Checks if fp structures need
// to be updated and updates if necessary.
void tailInsertNode256(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
ArtNode* child,
std::array<ArtNode*, maxPrefixLength>& temp_fp_path,
size_t& temp_fp_path_length, size_t depth_prev);
// Erase function for Node256
void eraseNode256(ART* tree, ArtNode** nodeRef, uint8_t keyByte);
};

Expand Down Expand Up @@ -143,7 +175,8 @@ void Node4::insertNode4(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
if (this->count < 4) {
// Insert element
unsigned pos;
for (pos = 0; (pos < this->count) && (this->key[pos] < keyByte); pos++);
for (pos = 0; (pos < this->count) && (this->key[pos] < keyByte); pos++)
;
memmove(this->key + pos + 1, this->key + pos, this->count - pos);
Comment thread
cangokmen marked this conversation as resolved.
memmove(this->child + pos + 1, this->child + pos,
(this->count - pos) * sizeof(uintptr_t));
Expand Down Expand Up @@ -256,7 +289,8 @@ void Node48::insertNode48(ART* tree, ArtNode** nodeRef, uint8_t keyByte,
// Insert element
unsigned pos = this->count;
if (this->child[pos])
for (pos = 0; this->child[pos] != NULL; pos++);
for (pos = 0; this->child[pos] != NULL; pos++)
;
this->child[pos] = child;
this->childIndex[keyByte] = pos;
this->count++;
Expand Down Expand Up @@ -478,4 +512,32 @@ ArtNode* lookupPessimistic(ArtNode* node, uint8_t key[], unsigned keyLength,
return NULL;
}

void printFpPath(std::array<ArtNode*, maxPrefixLength> path,
size_t path_length) {
// Print the fp path for debugging
for (size_t i = 0; i < path_length; i++) {
if (isLeaf(path[i])) {
printf("Leaf(%lu)\n", getLeafValue(path[i]));
} else {
switch (path[i]->type) {
case NodeType4:
printf("Node4 %p\n", path[i]);
break;
case NodeType16:
printf("Node16 %p\n", path[i]);
break;
case NodeType48:
printf("Node48 %p\n", path[i]);
break;
case NodeType256:
printf("Node256 %p\n", path[i]);
break;
default:
printf("Unknown NodeType %p\n", path[i]);
break;
}
}
}
}

} // namespace ART
Loading