Skip to content

Commit

Permalink
Simply DirectoryTree::find with non_exact=true (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
koolkdev authored Dec 3, 2024
1 parent 1ceaac2 commit 8b41f01
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 87 deletions.
122 changes: 35 additions & 87 deletions src/directory_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,110 +247,58 @@ class DirectoryTree : public SubBlockAllocator<DirectoryTreeHeader> {
parent_node parent{dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset)};
auto prefix = parent.prefix();
auto [key_it, prefix_it] = std::ranges::mismatch(std::ranges::subrange(current_key, key.end()), prefix);
std::strong_ordering status = std::strong_ordering::less;
if (key_it == key.end()) {
// Got to end of our key
if (prefix_it == prefix.end()) {
// Full match, check if there is a node
if (parent.has_leaf()) {
// Found exact match!
return {block().get(), std::move(parents), parent.leaf_ref()};
}
if (prefix_it == prefix.end() && parent.has_leaf()) {
// Found exact match!
return {block().get(), std::move(parents), parent.leaf_ref()};
}
} else if (prefix_it == prefix.end()) {
// We matched the prefix
auto iterator = parent.find(*key_it, exact_match);
if (iterator != parent.end() && (*iterator).key() == *key_it) {
if (iterator != parent.end() && *key_it >= (*iterator).key()) {
current_key = key_it + 1;
node_offset = (*iterator).value();
parents.emplace_back(parent, iterator);
continue;
if ((*iterator).key() != *key_it) {
status = std::strong_ordering::greater;
parent = {dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset)};
} else {
continue;
}
} else if (parent.has_leaf()) {
status = std::strong_ordering::equal;
}
} else if (*key_it >= *prefix_it) {
status = std::strong_ordering::greater;
}
if (exact_match)

if (exact_match) {
return end();
}

// Hit mistmach with non exact match, find which child to return.
if (parent.has_leaf()) {
assert(parent.has_leaf());
// We have a leaf, find cases when we need to return it or the previous node
bool before_leaf = false;
bool exact_leaf = false;
if (parent.size() == 0 && prefix_it == prefix.end()) {
// If we have no child and matched the whole prefix, we are at least bigger than leaf key.
exact_leaf = true;
} else if (prefix_it != prefix.end()) {
// We have a mistmach so just compare the prefix
if (std::lexicographical_compare(key_it, key.end(), prefix_it, prefix.end())) {
before_leaf = true;
} else if (parent.size() == 0) {
// If we are after and have no child, so it is the exact leaf
exact_leaf = true;
}
} else {
auto iterator = parent.find(*key_it, exact_match);
assert(iterator != parent.end());
if ((*iterator).key() > *key_it) {
// We are smaller than smallest key, so we should return the leaf
exact_leaf = true;
}
}
if (before_leaf || exact_leaf) {
// If we are smaller we overshoot, or we have no child so we may return the leaf node
iterator res{block().get(), std::move(parents), parent.leaf_ref()};
if (before_leaf) {
// We overshoot, go to prev
if (res != begin())
--res;
} // Otherwise parent.size() == 0 so we are bigger than res
return res;
if (status != std::strong_ordering::greater) {
// Go to the next leaf and back
while (!parent.has_leaf()) {
parents.emplace_back(parent, parent.begin());
node_offset = (*parents.back().iterator).value();
parent = dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset);
}
iterator res{block().get(), std::move(parents), parent.leaf_ref()};
if (status == std::strong_ordering::less && res != begin())
--res;
return res;
} else {
// For non leaf node, handle the case where we overshoot and need to go to prev node
bool smaller = false;
if (prefix_it != prefix.end() && std::lexicographical_compare(key_it, key.end(), prefix_it, prefix.end())) {
smaller = true;
} else if (prefix_it == prefix.end()) {
auto iterator = parent.find(*key_it, exact_match);
assert(iterator != parent.end());
if ((*iterator).key() > *key_it) {
smaller = true;
}
}
if (smaller) {
// Go to the next leaf and back
do {
parents.emplace_back(parent, parent.begin());
node_offset = (*parents.back().iterator).value();
parent = dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset);
} while (!parent.has_leaf());
iterator res{block().get(), std::move(parents), parent.leaf_ref()};
if (res != begin())
--res;
return res;
// Go to last leaf from here.
while (parent.size()) {
parents.emplace_back(parent, --parent.end());
node_offset = (*parents.back().iterator).value();
parent = dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset);
}
assert(parent.has_leaf());
return {block().get(), std::move(parents), parent.leaf_ref()};
}
assert(parent.size() > 0);
// Ok, now we just need to select the appropiate child that we are bigger than, and go the the last leaf of it.
typename parent_node::iterator iterator;
if (prefix_it != prefix.end()) {
// Prefix mismatch (and not smaller than because we already handle it), got to last.
iterator = --parent.end();
} else {
// Prefix match and find will return the last child that we are bigger from (as we handled the smaller than
// cases)
iterator = parent.find(*key_it, exact_match);
}
node_offset = (*iterator).value();
parents.emplace_back(parent, iterator);
parent = dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset);
// Go to last leaf from here.
while (parent.size()) {
parents.emplace_back(parent, --parent.end());
node_offset = (*parents.back().iterator).value();
parent = dir_tree_node_ref<LeafValueType>::load(block().get(), node_offset);
}
assert(parent.has_leaf());
return {block().get(), std::move(parents), parent.leaf_ref()};
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/directory_tree_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ TEST_CASE("DirectoryTreeTests") {
for (const auto& [key, result] : kExpectedResults) {
auto it = dir_tree.find(key, /*exact_match=*/false);
REQUIRE(it != dir_tree.end());
CAPTURE(key);
CHECK((*it).key() == result);
}
}
Expand Down

0 comments on commit 8b41f01

Please sign in to comment.