From e80441b15514408bc585a1cebd0c6f955bdd496a Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 7 May 2021 22:21:29 +0200 Subject: [PATCH 01/18] feat: iteration key carry --- include/art/tree_it.hpp | 160 +++++++++++++++++++++++++++++++--------- test/art.cpp | 31 ++++++++ 2 files changed, 157 insertions(+), 34 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 585fcdb..1eb91fe 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace art { @@ -22,7 +24,7 @@ template class leaf_node; template class tree_it { public: tree_it() = default; - explicit tree_it(std::stack *> traversal_stack); + explicit tree_it(std::stack *> traversal_stack, std::stack key_stack, std::stack depth_stack); static tree_it min(node *root); static tree_it greater_equal(node *root, const char *key); @@ -41,30 +43,61 @@ template class tree_it { bool operator==(const tree_it &rhs) const; bool operator!=(const tree_it &rhs) const; + template void key(OutputIterator key) const; + const std::string key() const; + + int depth() const; + private: std::stack *> traversal_stack_; + /* important: also delete [] key on pop */ + std::stack key_stack_; + std::stack depth_stack_; }; template -tree_it::tree_it(std::stack *> traversal_stack) - : traversal_stack_(traversal_stack) { - inner_node *cur; +tree_it::tree_it(std::stack *> traversal_stack, std::stack key_stack, std::stack depth_stack) + : traversal_stack_(traversal_stack), key_stack_(key_stack), depth_stack_(depth_stack) { + assert((traversal_stack.size() == key_stack.size())); + assert((traversal_stack.size() == depth_stack.size())); + + inner_node *cur_node; + const char* cur_key; + char* child_key; + int cur_depth; char child_partial_key; node *child; std::reverse_iterator> child_it, child_it_end; - /* preorder-traverse until leaf node found or no nodes are left */ + /* seek: preorder-traverse until leaf node found or no nodes are left */ while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) { - cur = static_cast *>(traversal_stack_.top()); + cur_node = static_cast *>(traversal_stack_.top()); + cur_key = key_stack_.top(); + cur_depth = depth_stack_.top(); traversal_stack_.pop(); - child_it = cur->rbegin(); - child_it_end = cur->rend(); + key_stack_.pop(); + depth_stack_.pop(); + child_it = cur_node->rbegin(); + child_it_end = cur_node->rend(); for (; child_it != child_it_end; ++child_it) { child_partial_key = *child_it; - child = *cur->find_child(child_partial_key); + child = *cur_node->find_child(child_partial_key); + + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; + std::copy(cur_key, cur_key + cur_depth, child_key); + std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); + child_key[cur_depth + cur_node->prefix_len_] = child_partial_key; + traversal_stack_.push(child); + key_stack_.push(child_key); + depth_stack_.push(cur_depth + cur_node->prefix_len_ + 1); } + delete [] cur_key; } + + assert((traversal_stack.size() == key_stack.size())); + assert((traversal_stack.size() == depth_stack.size())); } template tree_it tree_it::min(node *root) { @@ -77,49 +110,65 @@ tree_it tree_it::greater_equal(node *root, const char *key) { return tree_it(); } + node *cur_node; + const char* cur_key; int cur_depth, key_len = std::strlen(key), i; - node *cur; std::reverse_iterator> child_it, child_it_end; - char partial_key; + char partial_key, *child_key; std::stack *> node_stack; + std::stack key_stack; std::stack depth_stack; node_stack.push(root); + key_stack.push(nullptr); depth_stack.push(0); while (true) { - cur = node_stack.top(); + cur_node = node_stack.top(); + cur_key = key_stack.top(); cur_depth = depth_stack.top(); if (cur_depth == key_len) { - return tree_it(node_stack); + return tree_it(node_stack, key_stack, depth_stack); } - for (i = 0; i < cur->prefix_len_; ++i) { + for (i = 0; i < cur_node->prefix_len_; ++i) { if (cur_depth + i == key_len) { - return tree_it(node_stack); + return tree_it(node_stack, key_stack, depth_stack); } - if (cur->prefix_[i] < key[cur_depth + i]) { + if (cur_node->prefix_[i] < key[cur_depth + i]) { node_stack.pop(); - /* optional because depth_stack is not used outside this method */ - /* depth_stack.pop(); */ - return tree_it(node_stack); + key_stack.pop(); + depth_stack.pop(); + delete [] cur_key; + return tree_it(node_stack, key_stack, depth_stack); } } node_stack.pop(); + key_stack.pop(); depth_stack.pop(); - if (cur->is_leaf()) { - continue; - } - child_it = static_cast *>(cur)->rbegin(); - child_it_end = static_cast *>(cur)->rend(); - for (; child_it != child_it_end; ++child_it) { - partial_key = *child_it; - if (partial_key < key[cur_depth + cur->prefix_len_]) { - break; + if (!cur_node->is_leaf()) { + // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? + child_it = static_cast *>(cur_node)->rbegin(); + child_it_end = static_cast *>(cur_node)->rend(); + for (; child_it != child_it_end; ++child_it) + { + partial_key = *child_it; + if (partial_key < key[cur_depth + cur_node->prefix_len_]) + { + break; + } + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; + std::copy(cur_key, cur_key + cur_depth, child_key); + std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); + child_key[cur_depth + cur_node->prefix_len_] = partial_key; + + node_stack.push(*static_cast *>(cur_node)->find_child(partial_key)); + key_stack.push(child_key); + depth_stack.push(cur_depth + cur_node->prefix_len_ + 1); } - node_stack.push(*static_cast *>(cur)->find_child(partial_key)); - depth_stack.push(cur_depth + cur->prefix_len_ + 1); } + delete [] cur_key; } } @@ -132,17 +181,41 @@ template typename tree_it::pointer tree_it::operator->() { } template tree_it &tree_it::operator++() { - inner_node *cur; + assert((traversal_stack_.size() == key_stack_.size())); + assert((traversal_stack_.size() == depth_stack_.size())); + + inner_node *cur_node; + const char *cur_key; + char *child_key; + int cur_depth; std::reverse_iterator> it, it_end; + delete [] key_stack_.top(); traversal_stack_.pop(); + key_stack_.pop(); + depth_stack_.pop(); while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) { - cur = static_cast *>(traversal_stack_.top()); + cur_node = static_cast *>(traversal_stack_.top()); + cur_key = key_stack_.top(); + cur_depth = depth_stack_.top(); traversal_stack_.pop(); - for (it = cur->rbegin(), it_end = cur->rend(); it != it_end; ++it) { - traversal_stack_.push(*cur->find_child(*it)); + key_stack_.pop(); + depth_stack_.pop(); + for (it = cur_node->rbegin(), it_end = cur_node->rend(); it != it_end; ++it) { + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; + std::copy(cur_key, cur_key + cur_depth, child_key); + std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); + child_key[cur_depth + cur_node->prefix_len_] = *it; + + traversal_stack_.push(*cur_node->find_child(*it)); + key_stack_.push(child_key); + depth_stack_.push(cur_depth + cur_node->prefix_len_ + 1); } + delete [] cur_key; }; + + assert((traversal_stack_.size() == depth_stack_.size())); return *this; } @@ -162,6 +235,25 @@ template bool tree_it::operator!=(const tree_it &rhs) const { return !(*this == rhs); } +template +template +void tree_it::key(OutputIterator key) const { + std::copy(key_stack_.top(), key_stack_.top() + depth_stack_.top(), key); + std::copy(traversal_stack_.top()->prefix_, traversal_stack_.top()->prefix_ + traversal_stack_.top()->prefix_len_, key + depth_stack_.top()); +} + +template +const std::string tree_it::key() const { + std::string str(depth() - 1, 0); + key(str.begin()); + return str; +} + +template +int tree_it::depth() const { + return depth_stack_.top() + traversal_stack_.top()->prefix_len_; +} + } // namespace art #endif diff --git a/test/art.cpp b/test/art.cpp index cc55beb..0cf7a4e 100644 --- a/test/art.cpp +++ b/test/art.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using std::array; using std::hash; @@ -331,40 +332,70 @@ TEST_SUITE("art") { auto it = m.begin(); auto it_end = m.end(); + std::unique_ptr managed_passed_key(new char[20]); + char *passed_key = managed_passed_key.get(); // 0 REQUIRE(it != it_end); REQUIRE_EQ(&int0, *it); + REQUIRE_EQ(3, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 3, "aa")); + REQUIRE_EQ("aa", it.key()); ++it; // 1 REQUIRE(it != it_end); REQUIRE_EQ(&int1, *it); + REQUIRE_EQ(5, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 5, "aaaa")); + REQUIRE_EQ("aaaa", it.key()); ++it; // 2 REQUIRE(it != it_end); REQUIRE_EQ(&int2, *it); + REQUIRE_EQ(8, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 8, "aaaaaaa")); + REQUIRE_EQ("aaaaaaa", it.key()); ++it; // 3 REQUIRE(it != it_end); REQUIRE_EQ(&int3, *it); + REQUIRE_EQ(11, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 11, "aaaaaaaaaa")); + REQUIRE_EQ("aaaaaaaaaa", it.key()); ++it; // 4 REQUIRE(it != it_end); REQUIRE_EQ(&int4, *it); + REQUIRE_EQ(10, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 10, "aaaaaaaba")); + REQUIRE_EQ("aaaaaaaba", it.key()); ++it; // 5 REQUIRE(it != it_end); REQUIRE_EQ(&int5, *it); + REQUIRE_EQ(8, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 8, "aaaabaa")); + REQUIRE_EQ("aaaabaa", it.key()); ++it; // 6 REQUIRE(it != it_end); REQUIRE_EQ(&int6, *it); + REQUIRE_EQ(11, it.depth()); + it.key(passed_key); + REQUIRE(std::equal(passed_key, passed_key + 11, "aaaabaaaaa")); + REQUIRE_EQ("aaaabaaaaa", it.key()); ++it; // 7 (overflow) From 991d0e9e90df9aba6d56adf0b838b5eddb3ea7ee Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 7 May 2021 22:30:18 +0200 Subject: [PATCH 02/18] feat: iterator destructor --- include/art/tree_it.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 1eb91fe..093d108 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -25,6 +25,7 @@ template class tree_it { public: tree_it() = default; explicit tree_it(std::stack *> traversal_stack, std::stack key_stack, std::stack depth_stack); + ~tree_it(); static tree_it min(node *root); static tree_it greater_equal(node *root, const char *key); @@ -100,6 +101,13 @@ tree_it::tree_it(std::stack *> traversal_stack, std::stack tree_it::~tree_it() { + while (!key_stack_.empty()) { + delete [] key_stack_.top(); + key_stack_.pop(); + } +} + template tree_it tree_it::min(node *root) { return tree_it::greater_equal(root, ""); } From 681e939a422b52cb1744007570c5e47d1bba1565 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 7 May 2021 22:31:53 +0200 Subject: [PATCH 03/18] refactor: unused directives --- include/art/tree_it.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 093d108..2f208e8 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include namespace art { From d0ac82475fd594de44c2c61543c4ec157c14ab4e Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sat, 8 May 2021 15:26:02 +0200 Subject: [PATCH 04/18] feat: shared stack during iteration --- include/art/art.hpp | 4 +- include/art/tree_it.hpp | 218 ++++++++++++++++++---------------------- 2 files changed, 103 insertions(+), 119 deletions(-) diff --git a/include/art/art.hpp b/include/art/art.hpp index a297fba..14830ac 100644 --- a/include/art/art.hpp +++ b/include/art/art.hpp @@ -385,7 +385,9 @@ template tree_it art::begin(const char *key) { return tree_it::greater_equal(this->root_, key); } -template tree_it art::end() { return tree_it(); } +template tree_it art::end() { + return tree_it(); +} } // namespace art diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 2f208e8..1288e34 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -21,8 +21,15 @@ template class leaf_node; template class tree_it { public: + struct step { + node *node_; + int depth_; + /* important: also delete [] key on pop */ + const char *key_; + }; + tree_it() = default; - explicit tree_it(std::stack *> traversal_stack, std::stack key_stack, std::stack depth_stack); + explicit tree_it(std::stack traversal_stack); ~tree_it(); static tree_it min(node *root); @@ -48,61 +55,44 @@ template class tree_it { int depth() const; private: - std::stack *> traversal_stack_; - /* important: also delete [] key on pop */ - std::stack key_stack_; - std::stack depth_stack_; + std::stack traversal_stack_; }; template -tree_it::tree_it(std::stack *> traversal_stack, std::stack key_stack, std::stack depth_stack) - : traversal_stack_(traversal_stack), key_stack_(key_stack), depth_stack_(depth_stack) { - assert((traversal_stack.size() == key_stack.size())); - assert((traversal_stack.size() == depth_stack.size())); - - inner_node *cur_node; - const char* cur_key; +tree_it::tree_it(std::stack::step> traversal_stack) : traversal_stack_(traversal_stack) { + tree_it::step cur, child; + inner_node *cur_in_node; + int child_depth; char* child_key; - int cur_depth; - char child_partial_key; - node *child; + node *child_node; std::reverse_iterator> child_it, child_it_end; /* seek: preorder-traverse until leaf node found or no nodes are left */ - while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) { - cur_node = static_cast *>(traversal_stack_.top()); - cur_key = key_stack_.top(); - cur_depth = depth_stack_.top(); + while (!traversal_stack_.empty() && !traversal_stack_.top().node_->is_leaf()) { + cur = traversal_stack_.top(); traversal_stack_.pop(); - key_stack_.pop(); - depth_stack_.pop(); - child_it = cur_node->rbegin(); - child_it_end = cur_node->rend(); - for (; child_it != child_it_end; ++child_it) { - child_partial_key = *child_it; - child = *cur_node->find_child(child_partial_key); + cur_in_node = static_cast *>(cur.node_); + for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { + child_node = *cur_in_node->find_child(*child_it); + child_depth = cur.depth_ + cur_in_node->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; - std::copy(cur_key, cur_key + cur_depth, child_key); - std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); - child_key[cur_depth + cur_node->prefix_len_] = child_partial_key; + child_key = new char[cur.depth_ + cur_in_node->prefix_len_ + 1]; + std::copy(cur.key_, cur.key_ + cur.depth_, child_key); + std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur.depth_); + child_key[cur.depth_ + cur_in_node->prefix_len_] = *child_it; + child = {child_node, child_depth, child_key}; traversal_stack_.push(child); - key_stack_.push(child_key); - depth_stack_.push(cur_depth + cur_node->prefix_len_ + 1); } - delete [] cur_key; + delete [] cur.key_; } - - assert((traversal_stack.size() == key_stack.size())); - assert((traversal_stack.size() == depth_stack.size())); } template tree_it::~tree_it() { - while (!key_stack_.empty()) { - delete [] key_stack_.top(); - key_stack_.pop(); + while (!traversal_stack_.empty()) { + delete [] traversal_stack_.top().key_; + traversal_stack_.pop(); } } @@ -116,112 +106,96 @@ tree_it tree_it::greater_equal(node *root, const char *key) { return tree_it(); } - node *cur_node; - const char* cur_key; - int cur_depth, key_len = std::strlen(key), i; - std::reverse_iterator> child_it, child_it_end; - char partial_key, *child_key; - std::stack *> node_stack; - std::stack key_stack; - std::stack depth_stack; + tree_it::step cur, child; + int key_len = std::strlen(key), child_depth, i; + node *child_node; + inner_node *cur_in_node; + std::reverse_iterator> it, it_end; + char *child_key; + std::stack::step> traversal_stack; - node_stack.push(root); - key_stack.push(nullptr); - depth_stack.push(0); + child = {root, 0, nullptr}; + traversal_stack.push(child); while (true) { - cur_node = node_stack.top(); - cur_key = key_stack.top(); - cur_depth = depth_stack.top(); + cur = traversal_stack.top(); - if (cur_depth == key_len) { - return tree_it(node_stack, key_stack, depth_stack); + if (cur.depth_ == key_len) { + return tree_it(traversal_stack); } - for (i = 0; i < cur_node->prefix_len_; ++i) { - if (cur_depth + i == key_len) { - return tree_it(node_stack, key_stack, depth_stack); + for (i = 0; i < cur.node_->prefix_len_; ++i) { + if (cur.depth_ + i == key_len) { + return tree_it(traversal_stack); } - if (cur_node->prefix_[i] < key[cur_depth + i]) { - node_stack.pop(); - key_stack.pop(); - depth_stack.pop(); - delete [] cur_key; - return tree_it(node_stack, key_stack, depth_stack); + if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { + delete [] cur.key_; + traversal_stack.pop(); + return tree_it(traversal_stack); } } - node_stack.pop(); - key_stack.pop(); - depth_stack.pop(); - if (!cur_node->is_leaf()) { + traversal_stack.pop(); + if (!cur.node_->is_leaf()) { // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? - child_it = static_cast *>(cur_node)->rbegin(); - child_it_end = static_cast *>(cur_node)->rend(); - for (; child_it != child_it_end; ++child_it) - { - partial_key = *child_it; - if (partial_key < key[cur_depth + cur_node->prefix_len_]) - { + cur_in_node = static_cast *>(cur.node_); + for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { + if (*it < key[cur.depth_ + cur.node_->prefix_len_]) { break; } + child_node = *cur_in_node->find_child(*it); + child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; - std::copy(cur_key, cur_key + cur_depth, child_key); - std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); - child_key[cur_depth + cur_node->prefix_len_] = partial_key; - - node_stack.push(*static_cast *>(cur_node)->find_child(partial_key)); - key_stack.push(child_key); - depth_stack.push(cur_depth + cur_node->prefix_len_ + 1); + child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; + std::copy(cur.key_, cur.key_ + cur.depth_, child_key); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); + child_key[cur.depth_ + cur.node_->prefix_len_] = *it; + + child = {child_node, child_depth, child_key}; + traversal_stack.push(child); } } - delete [] cur_key; + delete [] cur.key_; } } template typename tree_it::value_type tree_it::operator*() { - return static_cast *>(traversal_stack_.top())->value_; + assert((traversal_stack_.top().node_->is_leaf())); + return static_cast *>(traversal_stack_.top().node_)->value_; } template typename tree_it::pointer tree_it::operator->() { - return &static_cast *>(traversal_stack_.top())->value_; + assert((traversal_stack_.top().node_->is_leaf())); + return &static_cast *>(traversal_stack_.top().node_)->value_; } template tree_it &tree_it::operator++() { - assert((traversal_stack_.size() == key_stack_.size())); - assert((traversal_stack_.size() == depth_stack_.size())); - - inner_node *cur_node; - const char *cur_key; + tree_it::step cur, child; + inner_node *cur_in_node; + node *child_node; + int child_depth; char *child_key; - int cur_depth; std::reverse_iterator> it, it_end; - delete [] key_stack_.top(); + delete [] traversal_stack_.top().key_; traversal_stack_.pop(); - key_stack_.pop(); - depth_stack_.pop(); - while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) { - cur_node = static_cast *>(traversal_stack_.top()); - cur_key = key_stack_.top(); - cur_depth = depth_stack_.top(); + while (!traversal_stack_.empty() && !traversal_stack_.top().node_->is_leaf()) { + cur = traversal_stack_.top(); + cur_in_node = static_cast *>(cur.node_); traversal_stack_.pop(); - key_stack_.pop(); - depth_stack_.pop(); - for (it = cur_node->rbegin(), it_end = cur_node->rend(); it != it_end; ++it) { + for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { + child_node = *cur_in_node->find_child(*it); + child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur_depth + cur_node->prefix_len_ + 1]; - std::copy(cur_key, cur_key + cur_depth, child_key); - std::copy(cur_node->prefix_, cur_node->prefix_ + cur_node->prefix_len_, child_key + cur_depth); - child_key[cur_depth + cur_node->prefix_len_] = *it; - - traversal_stack_.push(*cur_node->find_child(*it)); - key_stack_.push(child_key); - depth_stack_.push(cur_depth + cur_node->prefix_len_ + 1); + child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; + std::copy(cur.key_, cur.key_ + cur.depth_, child_key); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); + child_key[cur.depth_ + cur.node_->prefix_len_] = *it; + + child = {child_node, child_depth, child_key}; + traversal_stack_.push(child); } - delete [] cur_key; + delete [] cur.key_; }; - assert((traversal_stack_.size() == depth_stack_.size())); return *this; } @@ -232,9 +206,15 @@ template tree_it tree_it::operator++(int) { } template bool tree_it::operator==(const tree_it &rhs) const { - return (traversal_stack_.empty() && rhs.traversal_stack_.empty()) || - (!traversal_stack_.empty() && !rhs.traversal_stack_.empty() && - traversal_stack_.top() == rhs.traversal_stack_.top()); + if (traversal_stack_.empty() && rhs.traversal_stack_.empty()) { + /* both are empty */ + return true; + } + if (traversal_stack_.empty() || rhs.traversal_stack_.empty()) { + /* one is empty */ + return false; + } + return traversal_stack_.top().node_ == rhs.traversal_stack_.top().node_; } template bool tree_it::operator!=(const tree_it &rhs) const { @@ -244,8 +224,9 @@ template bool tree_it::operator!=(const tree_it &rhs) const { template template void tree_it::key(OutputIterator key) const { - std::copy(key_stack_.top(), key_stack_.top() + depth_stack_.top(), key); - std::copy(traversal_stack_.top()->prefix_, traversal_stack_.top()->prefix_ + traversal_stack_.top()->prefix_len_, key + depth_stack_.top()); + tree_it::step cur = traversal_stack_.top(); + std::copy(cur.key_, cur.key_ + cur.depth_, key); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, key + cur.depth_); } template @@ -257,7 +238,8 @@ const std::string tree_it::key() const { template int tree_it::depth() const { - return depth_stack_.top() + traversal_stack_.top()->prefix_len_; + tree_it::step cur = traversal_stack_.top(); + return cur.depth_ + cur.node_->prefix_len_; } } // namespace art From b8b75ab0f36023c1a5b2974b53524975cbeeb640 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 09:54:26 +0200 Subject: [PATCH 05/18] refactor: seek leaf, step ptr --- include/art/tree_it.hpp | 164 ++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 90 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 1288e34..022f178 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -29,7 +29,7 @@ template class tree_it { }; tree_it() = default; - explicit tree_it(std::stack traversal_stack); + explicit tree_it(std::stack traversal_stack); ~tree_it(); static tree_it min(node *root); @@ -55,43 +55,20 @@ template class tree_it { int depth() const; private: - std::stack traversal_stack_; + void seek_leaf(); + std::stack traversal_stack_; }; template -tree_it::tree_it(std::stack::step> traversal_stack) : traversal_stack_(traversal_stack) { - tree_it::step cur, child; - inner_node *cur_in_node; - int child_depth; - char* child_key; - node *child_node; - std::reverse_iterator> child_it, child_it_end; - - /* seek: preorder-traverse until leaf node found or no nodes are left */ - while (!traversal_stack_.empty() && !traversal_stack_.top().node_->is_leaf()) { - cur = traversal_stack_.top(); - traversal_stack_.pop(); - cur_in_node = static_cast *>(cur.node_); - for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { - child_node = *cur_in_node->find_child(*child_it); - child_depth = cur.depth_ + cur_in_node->prefix_len_ + 1; - - /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur.depth_ + cur_in_node->prefix_len_ + 1]; - std::copy(cur.key_, cur.key_ + cur.depth_, child_key); - std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur.depth_); - child_key[cur.depth_ + cur_in_node->prefix_len_] = *child_it; - - child = {child_node, child_depth, child_key}; - traversal_stack_.push(child); - } - delete [] cur.key_; - } +tree_it::tree_it(std::stack::step *> traversal_stack) : traversal_stack_(traversal_stack) { + seek_leaf(); } -template tree_it::~tree_it() { +template +tree_it::~tree_it() { while (!traversal_stack_.empty()) { - delete [] traversal_stack_.top().key_; + delete [] traversal_stack_.top()->key_; + delete traversal_stack_.top(); traversal_stack_.pop(); } } @@ -106,96 +83,72 @@ tree_it tree_it::greater_equal(node *root, const char *key) { return tree_it(); } - tree_it::step cur, child; + tree_it::step *cur; int key_len = std::strlen(key), child_depth, i; node *child_node; inner_node *cur_in_node; std::reverse_iterator> it, it_end; char *child_key; - std::stack::step> traversal_stack; + std::stack::step *> traversal_stack; - child = {root, 0, nullptr}; - traversal_stack.push(child); + traversal_stack.push(new tree_it::step {root, 0, nullptr}); while (true) { cur = traversal_stack.top(); - - if (cur.depth_ == key_len) { + if (cur->depth_ == key_len) { return tree_it(traversal_stack); } - for (i = 0; i < cur.node_->prefix_len_; ++i) { - if (cur.depth_ + i == key_len) { + for (i = 0; i < cur->node_->prefix_len_; ++i) { + if (cur->depth_ + i == key_len) { return tree_it(traversal_stack); } - if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { - delete [] cur.key_; + if (cur->node_->prefix_[i] < key[cur->depth_ + i]) { traversal_stack.pop(); + delete [] cur->key_; + delete cur; return tree_it(traversal_stack); } } traversal_stack.pop(); - if (!cur.node_->is_leaf()) { + if (!cur->node_->is_leaf()) { // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? - cur_in_node = static_cast *>(cur.node_); + cur_in_node = static_cast *>(cur->node_); for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { - if (*it < key[cur.depth_ + cur.node_->prefix_len_]) { + if (*it < key[cur->depth_ + cur->node_->prefix_len_]) { break; } child_node = *cur_in_node->find_child(*it); - child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; + child_depth = cur->depth_ + cur->node_->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; - std::copy(cur.key_, cur.key_ + cur.depth_, child_key); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); - child_key[cur.depth_ + cur.node_->prefix_len_] = *it; + child_key = new char[cur->depth_ + cur->node_->prefix_len_ + 1]; + std::copy(cur->key_, cur->key_ + cur->depth_, child_key); + std::copy(cur->node_->prefix_, cur->node_->prefix_ + cur->node_->prefix_len_, child_key + cur->depth_); + child_key[cur->depth_ + cur->node_->prefix_len_] = *it; - child = {child_node, child_depth, child_key}; - traversal_stack.push(child); + traversal_stack.push(new tree_it::step {child_node, child_depth, child_key}); } } - delete [] cur.key_; + delete [] cur->key_; + delete cur; } } template typename tree_it::value_type tree_it::operator*() { - assert((traversal_stack_.top().node_->is_leaf())); - return static_cast *>(traversal_stack_.top().node_)->value_; + assert((traversal_stack_.top()->node_->is_leaf())); + return static_cast *>(traversal_stack_.top()->node_)->value_; } template typename tree_it::pointer tree_it::operator->() { - assert((traversal_stack_.top().node_->is_leaf())); - return &static_cast *>(traversal_stack_.top().node_)->value_; + assert((traversal_stack_.top()->node_->is_leaf())); + return &static_cast *>(traversal_stack_.top()->node_)->value_; } template tree_it &tree_it::operator++() { - tree_it::step cur, child; - inner_node *cur_in_node; - node *child_node; - int child_depth; - char *child_key; - std::reverse_iterator> it, it_end; - - delete [] traversal_stack_.top().key_; + assert(!traversal_stack_.empty()); + delete [] traversal_stack_.top()->key_; + delete traversal_stack_.top(); traversal_stack_.pop(); - while (!traversal_stack_.empty() && !traversal_stack_.top().node_->is_leaf()) { - cur = traversal_stack_.top(); - cur_in_node = static_cast *>(cur.node_); - traversal_stack_.pop(); - for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { - child_node = *cur_in_node->find_child(*it); - child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; - /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; - std::copy(cur.key_, cur.key_ + cur.depth_, child_key); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); - child_key[cur.depth_ + cur.node_->prefix_len_] = *it; - - child = {child_node, child_depth, child_key}; - traversal_stack_.push(child); - } - delete [] cur.key_; - }; - + seek_leaf(); return *this; } @@ -214,7 +167,7 @@ template bool tree_it::operator==(const tree_it &rhs) const { /* one is empty */ return false; } - return traversal_stack_.top().node_ == rhs.traversal_stack_.top().node_; + return traversal_stack_.top()->node_ == rhs.traversal_stack_.top()->node_; } template bool tree_it::operator!=(const tree_it &rhs) const { @@ -224,9 +177,9 @@ template bool tree_it::operator!=(const tree_it &rhs) const { template template void tree_it::key(OutputIterator key) const { - tree_it::step cur = traversal_stack_.top(); - std::copy(cur.key_, cur.key_ + cur.depth_, key); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, key + cur.depth_); + tree_it::step * cur = traversal_stack_.top(); + std::copy(cur->key_, cur->key_ + cur->depth_, key); + std::copy(cur->node_->prefix_, cur->node_->prefix_ + cur->node_->prefix_len_, key + cur->depth_); } template @@ -238,8 +191,39 @@ const std::string tree_it::key() const { template int tree_it::depth() const { - tree_it::step cur = traversal_stack_.top(); - return cur.depth_ + cur.node_->prefix_len_; + tree_it::step * cur = traversal_stack_.top(); + return cur->depth_ + cur->node_->prefix_len_; +} + +template +void tree_it::seek_leaf() { + tree_it::step * cur; + inner_node *cur_in_node; + node *child_node; + int child_depth; + char* child_key; + std::reverse_iterator> child_it, child_it_end; + + /* preorder-traverse until leaf node found or no nodes are left */ + while (!traversal_stack_.empty() && !traversal_stack_.top()->node_->is_leaf()) { + cur = traversal_stack_.top(); + traversal_stack_.pop(); + cur_in_node = static_cast *>(cur->node_); + for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { + child_node = *cur_in_node->find_child(*child_it); + child_depth = cur->depth_ + cur_in_node->prefix_len_ + 1; + + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + child_key = new char[cur->depth_ + cur_in_node->prefix_len_ + 1]; + std::copy(cur->key_, cur->key_ + cur->depth_, child_key); + std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur->depth_); + child_key[cur->depth_ + cur_in_node->prefix_len_] = *child_it; + + traversal_stack_.push(new tree_it::step {child_node, child_depth, child_key}); + } + delete [] cur->key_; + delete cur; + } } } // namespace art From f230295aea3ae6574241e23ea353c586d94e2ec0 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 10:48:36 +0200 Subject: [PATCH 06/18] refactor: tree_it uses deque instead of stack --- include/art/tree_it.hpp | 91 +++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index f07173e..29b5a6b 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -29,7 +29,7 @@ template class tree_it { }; tree_it() = default; - explicit tree_it(std::deque traversal_stack); + explicit tree_it(std::deque traversal_stack); ~tree_it(); static tree_it min(node *root); @@ -56,19 +56,18 @@ template class tree_it { private: void seek_leaf(); - std::deque traversal_stack_; + std::deque traversal_stack_; }; template -tree_it::tree_it(std::deque::step *> traversal_stack) : traversal_stack_(traversal_stack) { +tree_it::tree_it(std::deque::step> traversal_stack) : traversal_stack_(traversal_stack) { seek_leaf(); } template tree_it::~tree_it() { while (!traversal_stack_.empty()) { - delete [] traversal_stack_.back()->key_; - delete traversal_stack_.back(); + delete [] traversal_stack_.back().key_; traversal_stack_.pop_back(); } } @@ -83,70 +82,67 @@ tree_it tree_it::greater_equal(node *root, const char *key) { return tree_it(); } - tree_it::step *cur; + tree_it::step cur; int key_len = std::strlen(key), child_depth, i; node *child_node; inner_node *cur_in_node; std::reverse_iterator> it, it_end; char *child_key; - std::deque::step *> traversal_stack; + std::deque::step> traversal_stack; - traversal_stack.push(new tree_it::step {root, 0, nullptr}); + traversal_stack.push_back({root, 0, nullptr}); while (true) { cur = traversal_stack.back(); - if (cur->depth_ == key_len) { + if (cur.depth_ == key_len) { return tree_it(traversal_stack); } - for (i = 0; i < cur->node_->prefix_len_; ++i) { - if (cur->depth_ + i == key_len) { + for (i = 0; i < cur.node_->prefix_len_; ++i) { + if (cur.depth_ + i == key_len) { return tree_it(traversal_stack); } - if (cur->node_->prefix_[i] < key[cur->depth_ + i]) { + if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { traversal_stack.pop_back(); - delete [] cur->key_; - delete cur; + delete [] cur.key_; return tree_it(traversal_stack); } } traversal_stack.pop_back(); - if (!cur->node_->is_leaf()) { + if (!cur.node_->is_leaf()) { // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? - cur_in_node = static_cast *>(cur->node_); + cur_in_node = static_cast *>(cur.node_); for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { - if (*it < key[cur->depth_ + cur->node_->prefix_len_]) { + if (*it < key[cur.depth_ + cur.node_->prefix_len_]) { break; } child_node = *cur_in_node->find_child(*it); - child_depth = cur->depth_ + cur->node_->prefix_len_ + 1; + child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur->depth_ + cur->node_->prefix_len_ + 1]; - std::copy(cur->key_, cur->key_ + cur->depth_, child_key); - std::copy(cur->node_->prefix_, cur->node_->prefix_ + cur->node_->prefix_len_, child_key + cur->depth_); - child_key[cur->depth_ + cur->node_->prefix_len_] = *it; + child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; + std::copy(cur.key_, cur.key_ + cur.depth_, child_key); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); + child_key[cur.depth_ + cur.node_->prefix_len_] = *it; - traversal_stack.push(new tree_it::step {child_node, child_depth, child_key}); + traversal_stack.push_back({child_node, child_depth, child_key}); } } - delete [] cur->key_; - delete cur; + delete [] cur.key_; } } template typename tree_it::value_type tree_it::operator*() { - assert((traversal_stack_.back()->node_->is_leaf())); - return static_cast *>(traversal_stack_.back()->node_)->value_; + assert((traversal_stack_.back().node_->is_leaf())); + return static_cast *>(traversal_stack_.back().node_)->value_; } template typename tree_it::pointer tree_it::operator->() { - assert((traversal_stack_.back()->node_->is_leaf())); - return &static_cast *>(traversal_stack_.back()->node_)->value_; + assert((traversal_stack_.back().node_->is_leaf())); + return &static_cast *>(traversal_stack_.back().node_)->value_; } template tree_it &tree_it::operator++() { assert(!traversal_stack_.empty()); - delete [] traversal_stack_.back()->key_; - delete traversal_stack_.back(); + delete [] traversal_stack_.back().key_; traversal_stack_.pop_back(); seek_leaf(); return *this; @@ -167,7 +163,7 @@ template bool tree_it::operator==(const tree_it &rhs) const { /* one is empty */ return false; } - return traversal_stack_.back()->node_ == rhs.traversal_stack_.back()->node_; + return traversal_stack_.back().node_ == rhs.traversal_stack_.back().node_; } template bool tree_it::operator!=(const tree_it &rhs) const { @@ -177,9 +173,9 @@ template bool tree_it::operator!=(const tree_it &rhs) const { template template void tree_it::key(OutputIterator key) const { - tree_it::step * cur = traversal_stack_.back(); - std::copy(cur->key_, cur->key_ + cur->depth_, key); - std::copy(cur->node_->prefix_, cur->node_->prefix_ + cur->node_->prefix_len_, key + cur->depth_); + tree_it::step cur = traversal_stack_.back(); + std::copy(cur.key_, cur.key_ + cur.depth_, key); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, key + cur.depth_); } template @@ -191,13 +187,13 @@ const std::string tree_it::key() const { template int tree_it::depth() const { - tree_it::step * cur = traversal_stack_.back(); - return cur->depth_ + cur->node_->prefix_len_; + tree_it::step cur = traversal_stack_.back(); + return cur.depth_ + cur.node_->prefix_len_; } template void tree_it::seek_leaf() { - tree_it::step * cur; + tree_it::step cur; inner_node *cur_in_node; node *child_node; int child_depth; @@ -205,24 +201,23 @@ void tree_it::seek_leaf() { std::reverse_iterator> child_it, child_it_end; /* preorder-traverse until leaf node found or no nodes are left */ - while (!traversal_stack_.empty() && !traversal_stack_.back()->node_->is_leaf()) { + while (!traversal_stack_.empty() && !traversal_stack_.back().node_->is_leaf()) { cur = traversal_stack_.back(); traversal_stack_.pop_back(); - cur_in_node = static_cast *>(cur->node_); + cur_in_node = static_cast *>(cur.node_); for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { child_node = *cur_in_node->find_child(*child_it); - child_depth = cur->depth_ + cur_in_node->prefix_len_ + 1; + child_depth = cur.depth_ + cur_in_node->prefix_len_ + 1; /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur->depth_ + cur_in_node->prefix_len_ + 1]; - std::copy(cur->key_, cur->key_ + cur->depth_, child_key); - std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur->depth_); - child_key[cur->depth_ + cur_in_node->prefix_len_] = *child_it; + child_key = new char[cur.depth_ + cur_in_node->prefix_len_ + 1]; + std::copy(cur.key_, cur.key_ + cur.depth_, child_key); + std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur.depth_); + child_key[cur.depth_ + cur_in_node->prefix_len_] = *child_it; - traversal_stack_.push(new tree_it::step {child_node, child_depth, child_key}); + traversal_stack_.push_back({child_node, child_depth, child_key}); } - delete [] cur->key_; - delete cur; + delete [] cur.key_; } } From 45a901f03605faa5a1e105956e0ab9cd08498625 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 10:49:19 +0200 Subject: [PATCH 07/18] chore: removed vscode dir --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index baccda7..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "deque": "cpp" - } -} \ No newline at end of file From 2b2d28085d314bb758decacd644736519801d987 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 14:42:23 +0200 Subject: [PATCH 08/18] feat: tree_it step rule of three --- include/art/tree_it.hpp | 101 ++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 29b5a6b..c04245c 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -22,15 +22,19 @@ template class leaf_node; template class tree_it { public: struct step { - node *node_; + node *node_; // no ownership int depth_; - /* important: also delete [] key on pop */ - const char *key_; + char *key_; // ownership + + step(); + explicit step(node *node, int depth); + step(const step &other); + step& operator=(const step &other); + ~step(); }; tree_it() = default; explicit tree_it(std::deque traversal_stack); - ~tree_it(); static tree_it min(node *root); static tree_it greater_equal(node *root, const char *key); @@ -60,18 +64,49 @@ template class tree_it { }; template -tree_it::tree_it(std::deque::step> traversal_stack) : traversal_stack_(traversal_stack) { - seek_leaf(); +tree_it::step::step() : node_(nullptr), depth_(0), key_(nullptr) {} + +template +tree_it::step::step(node *node, int depth) : node_(node), depth_(depth), key_(depth ? new char[depth] : nullptr) {} + +template +tree_it::step::step(const tree_it::step &other) : step(other.node_, other.depth_) { + std::copy(other.key_, other.key_ + other.depth_, key_); } -template -tree_it::~tree_it() { - while (!traversal_stack_.empty()) { - delete [] traversal_stack_.back().key_; - traversal_stack_.pop_back(); +template +typename tree_it::step& tree_it::step::operator=(const tree_it::step &other) { + if (this != &other) { + node *node = other.node_; + int depth = other.depth_; + char *key = depth ? new char[depth] : nullptr; + std::copy(other.key_, other.key_ + other.depth_, key); + + node_ = node; + depth_ = depth; + delete [] key_; + key_ = key; } + return *this; } +template +tree_it::step::~step() { + delete [] key_; +} + +template +tree_it::tree_it(std::deque::step> traversal_stack) : traversal_stack_(traversal_stack) { + seek_leaf(); +} + +// template +// tree_it::~tree_it() { +// while (!traversal_stack_.empty()) { +// traversal_stack_.pop_back(); +// } +// } + template tree_it tree_it::min(node *root) { return tree_it::greater_equal(root, ""); } @@ -82,15 +117,13 @@ tree_it tree_it::greater_equal(node *root, const char *key) { return tree_it(); } - tree_it::step cur; - int key_len = std::strlen(key), child_depth, i; - node *child_node; + tree_it::step cur, child; + int key_len = std::strlen(key), i; inner_node *cur_in_node; std::reverse_iterator> it, it_end; - char *child_key; std::deque::step> traversal_stack; - traversal_stack.push_back({root, 0, nullptr}); + traversal_stack.push_back(tree_it::step(root, 0)); while (true) { cur = traversal_stack.back(); @@ -103,7 +136,6 @@ tree_it tree_it::greater_equal(node *root, const char *key) { } if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { traversal_stack.pop_back(); - delete [] cur.key_; return tree_it(traversal_stack); } } @@ -115,18 +147,14 @@ tree_it tree_it::greater_equal(node *root, const char *key) { if (*it < key[cur.depth_ + cur.node_->prefix_len_]) { break; } - child_node = *cur_in_node->find_child(*it); - child_depth = cur.depth_ + cur.node_->prefix_len_ + 1; + child = tree_it::step(*cur_in_node->find_child(*it), cur.depth_ + cur.node_->prefix_len_ + 1); /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur.depth_ + cur.node_->prefix_len_ + 1]; - std::copy(cur.key_, cur.key_ + cur.depth_, child_key); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child_key + cur.depth_); - child_key[cur.depth_ + cur.node_->prefix_len_] = *it; - - traversal_stack.push_back({child_node, child_depth, child_key}); + std::copy(cur.key_, cur.key_ + cur.depth_, child.key_); + std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child.key_ + cur.depth_); + child.key_[cur.depth_ + cur.node_->prefix_len_] = *it; + traversal_stack.push_back(child); } } - delete [] cur.key_; } } @@ -142,7 +170,6 @@ template typename tree_it::pointer tree_it::operator->() { template tree_it &tree_it::operator++() { assert(!traversal_stack_.empty()); - delete [] traversal_stack_.back().key_; traversal_stack_.pop_back(); seek_leaf(); return *this; @@ -193,11 +220,8 @@ int tree_it::depth() const { template void tree_it::seek_leaf() { - tree_it::step cur; + tree_it::step cur, child; inner_node *cur_in_node; - node *child_node; - int child_depth; - char* child_key; std::reverse_iterator> child_it, child_it_end; /* preorder-traverse until leaf node found or no nodes are left */ @@ -206,18 +230,13 @@ void tree_it::seek_leaf() { traversal_stack_.pop_back(); cur_in_node = static_cast *>(cur.node_); for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { - child_node = *cur_in_node->find_child(*child_it); - child_depth = cur.depth_ + cur_in_node->prefix_len_ + 1; - + child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur_in_node->prefix_len_ + 1); /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - child_key = new char[cur.depth_ + cur_in_node->prefix_len_ + 1]; - std::copy(cur.key_, cur.key_ + cur.depth_, child_key); - std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child_key + cur.depth_); - child_key[cur.depth_ + cur_in_node->prefix_len_] = *child_it; - - traversal_stack_.push_back({child_node, child_depth, child_key}); + std::copy(cur.key_, cur.key_ + cur.depth_, child.key_); + std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child.key_ + cur.depth_); + child.key_[cur.depth_ + cur_in_node->prefix_len_] = *child_it; + traversal_stack_.push_back(child); } - delete [] cur.key_; } } From f970e1ff4df117babd872da9e6dd2eb940a53186 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 14:56:13 +0200 Subject: [PATCH 09/18] feat: tree_it default constructor --- include/art/tree_it.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index c04245c..a83a5c0 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -28,12 +28,13 @@ template class tree_it { step(); explicit step(node *node, int depth); + explicit step(node *node, int depth, const char* key); step(const step &other); step& operator=(const step &other); ~step(); }; - tree_it() = default; + tree_it(); explicit tree_it(std::deque traversal_stack); static tree_it min(node *root); @@ -70,10 +71,13 @@ template tree_it::step::step(node *node, int depth) : node_(node), depth_(depth), key_(depth ? new char[depth] : nullptr) {} template -tree_it::step::step(const tree_it::step &other) : step(other.node_, other.depth_) { - std::copy(other.key_, other.key_ + other.depth_, key_); +tree_it::step::step(node *node, int depth, const char *key) : node_(node), depth_(depth), key_(depth ? new char[depth] : nullptr) { + std::copy(key, key + depth, key_); } +template +tree_it::step::step(const tree_it::step &other) : step(other.node_, other.depth_, other.key_) {} + template typename tree_it::step& tree_it::step::operator=(const tree_it::step &other) { if (this != &other) { @@ -95,6 +99,9 @@ tree_it::step::~step() { delete [] key_; } +template +tree_it::tree_it() : tree_it(std::deque::step>()) {} + template tree_it::tree_it(std::deque::step> traversal_stack) : traversal_stack_(traversal_stack) { seek_leaf(); From 0bdbb3e49a71b0802d038d38d70444d24ebda5e5 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 15:39:29 +0200 Subject: [PATCH 10/18] feat: rule of 5, std::copy_n --- include/art/tree_it.hpp | 56 ++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index a83a5c0..f53d529 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace art { @@ -30,8 +31,11 @@ template class tree_it { explicit step(node *node, int depth); explicit step(node *node, int depth, const char* key); step(const step &other); - step& operator=(const step &other); + step(step &&other); ~step(); + + step& operator=(const step &other); + step& operator=(step &&other) noexcept; }; tree_it(); @@ -72,19 +76,31 @@ tree_it::step::step(node *node, int depth) : node_(node), depth_(depth), k template tree_it::step::step(node *node, int depth, const char *key) : node_(node), depth_(depth), key_(depth ? new char[depth] : nullptr) { - std::copy(key, key + depth, key_); + std::copy_n(key, depth, key_); } template tree_it::step::step(const tree_it::step &other) : step(other.node_, other.depth_, other.key_) {} +template +tree_it::step::step(tree_it::step &&other) : node_(other.node_), depth_(other.depth_), key_(other.key_) { + other.node_ = nullptr; + other.depth_ = 0; + other.key_ = nullptr; +} + +template +tree_it::step::~step() { + delete [] key_; +} + template typename tree_it::step& tree_it::step::operator=(const tree_it::step &other) { if (this != &other) { node *node = other.node_; int depth = other.depth_; char *key = depth ? new char[depth] : nullptr; - std::copy(other.key_, other.key_ + other.depth_, key); + std::copy_n(other.key_, other.depth_, key); node_ = node; depth_ = depth; @@ -95,8 +111,19 @@ typename tree_it::step& tree_it::step::operator=(const tree_it::step &o } template -tree_it::step::~step() { - delete [] key_; +typename tree_it::step& tree_it::step::operator=(tree_it::step &&other) noexcept { + if (this != &other) { + node_ = other.node_; + other.node_ = nullptr; + + depth_ = other.depth_; + other.depth_ = 0; + + delete [] key_; + key_ = other.key_; + other.key_ = nullptr; + } + return *this; } template @@ -107,13 +134,6 @@ tree_it::tree_it(std::deque::step> traversal_stack) : traversal_st seek_leaf(); } -// template -// tree_it::~tree_it() { -// while (!traversal_stack_.empty()) { -// traversal_stack_.pop_back(); -// } -// } - template tree_it tree_it::min(node *root) { return tree_it::greater_equal(root, ""); } @@ -156,8 +176,8 @@ tree_it tree_it::greater_equal(node *root, const char *key) { } child = tree_it::step(*cur_in_node->find_child(*it), cur.depth_ + cur.node_->prefix_len_ + 1); /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - std::copy(cur.key_, cur.key_ + cur.depth_, child.key_); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, child.key_ + cur.depth_); + std::copy_n(cur.key_, cur.depth_, child.key_); + std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, child.key_ + cur.depth_); child.key_[cur.depth_ + cur.node_->prefix_len_] = *it; traversal_stack.push_back(child); } @@ -208,8 +228,8 @@ template template void tree_it::key(OutputIterator key) const { tree_it::step cur = traversal_stack_.back(); - std::copy(cur.key_, cur.key_ + cur.depth_, key); - std::copy(cur.node_->prefix_, cur.node_->prefix_ + cur.node_->prefix_len_, key + cur.depth_); + std::copy_n(cur.key_, cur.depth_, key); + std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, key + cur.depth_); } template @@ -239,8 +259,8 @@ void tree_it::seek_leaf() { for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur_in_node->prefix_len_ + 1); /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - std::copy(cur.key_, cur.key_ + cur.depth_, child.key_); - std::copy(cur_in_node->prefix_, cur_in_node->prefix_ + cur_in_node->prefix_len_, child.key_ + cur.depth_); + std::copy_n(cur.key_, cur.depth_, child.key_); + std::copy_n(cur_in_node->prefix_, cur_in_node->prefix_len_, child.key_ + cur.depth_); child.key_[cur.depth_ + cur_in_node->prefix_len_] = *child_it; traversal_stack_.push_back(child); } From 7f03519c9535c4a16f928318c445a04fe4fb8e0d Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 15:42:44 +0200 Subject: [PATCH 11/18] chore: removed unused utility directive --- include/art/tree_it.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index f53d529..91384d9 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -12,7 +12,6 @@ #include #include #include -#include namespace art { From 6d60339dacf42c993a596d12ec8f045aac5535e7 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 22:04:58 +0200 Subject: [PATCH 12/18] refactor: rename it to child_it --- include/art/tree_it.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 91384d9..3d8009d 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace art { @@ -146,7 +147,7 @@ tree_it tree_it::greater_equal(node *root, const char *key) { tree_it::step cur, child; int key_len = std::strlen(key), i; inner_node *cur_in_node; - std::reverse_iterator> it, it_end; + std::reverse_iterator> child_it, child_it_end; std::deque::step> traversal_stack; traversal_stack.push_back(tree_it::step(root, 0)); @@ -169,15 +170,15 @@ tree_it tree_it::greater_equal(node *root, const char *key) { if (!cur.node_->is_leaf()) { // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? cur_in_node = static_cast *>(cur.node_); - for (it = cur_in_node->rbegin(), it_end = cur_in_node->rend(); it != it_end; ++it) { - if (*it < key[cur.depth_ + cur.node_->prefix_len_]) { + for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { + if (*child_it < key[cur.depth_ + cur.node_->prefix_len_]) { break; } - child = tree_it::step(*cur_in_node->find_child(*it), cur.depth_ + cur.node_->prefix_len_ + 1); + child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur.node_->prefix_len_ + 1); /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ std::copy_n(cur.key_, cur.depth_, child.key_); std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, child.key_ + cur.depth_); - child.key_[cur.depth_ + cur.node_->prefix_len_] = *it; + child.key_[cur.depth_ + cur.node_->prefix_len_] = *child_it; traversal_stack.push_back(child); } } From f7a33900965666743ce093cc2fbeb8039a3a6ddc Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Sun, 9 May 2021 23:00:02 +0200 Subject: [PATCH 13/18] refactor: seek_leaf after key --- include/art/tree_it.hpp | 114 ++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 3d8009d..ca3038b 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -58,13 +58,15 @@ template class tree_it { bool operator==(const tree_it &rhs) const; bool operator!=(const tree_it &rhs) const; - template void key(OutputIterator key) const; + template void key(OutputIt key) const; const std::string key() const; int depth() const; private: - void seek_leaf(); + static void seek_leaf(std::deque& traversal_stack); + static void seek_leaf(std::deque& traversal_stack, const char *key, int key_len); + std::deque traversal_stack_; }; @@ -131,7 +133,7 @@ tree_it::tree_it() : tree_it(std::deque::step>()) {} template tree_it::tree_it(std::deque::step> traversal_stack) : traversal_stack_(traversal_stack) { - seek_leaf(); + seek_leaf(traversal_stack_); } template tree_it tree_it::min(node *root) { @@ -140,49 +142,12 @@ template tree_it tree_it::min(node *root) { template tree_it tree_it::greater_equal(node *root, const char *key) { - if (root == nullptr) { - return tree_it(); - } - - tree_it::step cur, child; - int key_len = std::strlen(key), i; - inner_node *cur_in_node; - std::reverse_iterator> child_it, child_it_end; std::deque::step> traversal_stack; - - traversal_stack.push_back(tree_it::step(root, 0)); - - while (true) { - cur = traversal_stack.back(); - if (cur.depth_ == key_len) { - return tree_it(traversal_stack); - } - for (i = 0; i < cur.node_->prefix_len_; ++i) { - if (cur.depth_ + i == key_len) { - return tree_it(traversal_stack); - } - if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { - traversal_stack.pop_back(); - return tree_it(traversal_stack); - } - } - traversal_stack.pop_back(); - if (!cur.node_->is_leaf()) { - // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? - cur_in_node = static_cast *>(cur.node_); - for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { - if (*child_it < key[cur.depth_ + cur.node_->prefix_len_]) { - break; - } - child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur.node_->prefix_len_ + 1); - /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ - std::copy_n(cur.key_, cur.depth_, child.key_); - std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, child.key_ + cur.depth_); - child.key_[cur.depth_ + cur.node_->prefix_len_] = *child_it; - traversal_stack.push_back(child); - } - } + if (root != nullptr) { + traversal_stack.push_back(tree_it::step(root, 0)); } + seek_leaf(traversal_stack, key, std::strlen(key)); + return tree_it(traversal_stack); } template typename tree_it::value_type tree_it::operator*() { @@ -198,7 +163,7 @@ template typename tree_it::pointer tree_it::operator->() { template tree_it &tree_it::operator++() { assert(!traversal_stack_.empty()); traversal_stack_.pop_back(); - seek_leaf(); + seek_leaf(traversal_stack_); return *this; } @@ -225,8 +190,8 @@ template bool tree_it::operator!=(const tree_it &rhs) const { } template -template -void tree_it::key(OutputIterator key) const { +template +void tree_it::key(OutputIt key) const { tree_it::step cur = traversal_stack_.back(); std::copy_n(cur.key_, cur.depth_, key); std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, key + cur.depth_); @@ -246,15 +211,15 @@ int tree_it::depth() const { } template -void tree_it::seek_leaf() { +void tree_it::seek_leaf(std::deque::step> &traversal_stack) { tree_it::step cur, child; inner_node *cur_in_node; std::reverse_iterator> child_it, child_it_end; /* preorder-traverse until leaf node found or no nodes are left */ - while (!traversal_stack_.empty() && !traversal_stack_.back().node_->is_leaf()) { - cur = traversal_stack_.back(); - traversal_stack_.pop_back(); + while (!traversal_stack.empty() && !traversal_stack.back().node_->is_leaf()) { + cur = traversal_stack.back(); + traversal_stack.pop_back(); cur_in_node = static_cast *>(cur.node_); for (child_it = cur_in_node->rbegin(), child_it_end = cur_in_node->rend(); child_it != child_it_end; ++child_it) { child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur_in_node->prefix_len_ + 1); @@ -262,7 +227,52 @@ void tree_it::seek_leaf() { std::copy_n(cur.key_, cur.depth_, child.key_); std::copy_n(cur_in_node->prefix_, cur_in_node->prefix_len_, child.key_ + cur.depth_); child.key_[cur.depth_ + cur_in_node->prefix_len_] = *child_it; - traversal_stack_.push_back(child); + traversal_stack.push_back(child); + } + } +} + +template +void tree_it::seek_leaf(std::deque::step> &traversal_stack, const char *key, int key_len) { + tree_it::step cur, child; + int i; + inner_node *cur_in_node; + std::reverse_iterator> child_it, child_it_end; + + while (!traversal_stack.empty()) { + cur = traversal_stack.back(); + if (cur.depth_ == key_len) { + seek_leaf(traversal_stack); + return; + } + for (i = 0; i < cur.node_->prefix_len_; ++i) { + if (cur.depth_ + i == key_len) { + seek_leaf(traversal_stack); + return; + } + if (cur.node_->prefix_[i] < key[cur.depth_ + i]) { + traversal_stack.pop_back(); + seek_leaf(traversal_stack); + return; + } + } + traversal_stack.pop_back(); + if (!cur.node_->is_leaf()) { + // TODO: the following part is 1:1 with seek in constructor, is it possible to de-duplicate? + cur_in_node = static_cast *>(cur.node_); + child_it = cur_in_node->rbegin(); + child_it_end = cur_in_node->rend(); + for (; child_it != child_it_end; ++child_it) { + if (*child_it < key[cur.depth_ + cur.node_->prefix_len_]) { + break; + } + child = tree_it::step(*cur_in_node->find_child(*child_it), cur.depth_ + cur.node_->prefix_len_ + 1); + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + std::copy_n(cur.key_, cur.depth_, child.key_); + std::copy_n(cur.node_->prefix_, cur.node_->prefix_len_, child.key_ + cur.depth_); + child.key_[cur.depth_ + cur.node_->prefix_len_] = *child_it; + traversal_stack.push_back(child); + } } } } From 6b827ecb469d8c4885c1849d25d6ff63db7df5f0 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 14 May 2021 14:40:56 +0200 Subject: [PATCH 14/18] feat: test pass --- include/art/tree_it.hpp | 62 ++++++++++++++++++++++++++--------------- test/tree_it.cpp | 39 +++++++++++--------------- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index eb7dcfe..06fa59c 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -23,7 +23,7 @@ template class leaf_node; template class tree_it { public: struct step { - node *node_; // no ownership + node *child_node_; // no ownership int depth_; char *key_; // ownership child_it child_it_; @@ -44,7 +44,7 @@ template class tree_it { }; tree_it(); - explicit tree_it(std::vector traversal_stack); + explicit tree_it(node *root, std::vector traversal_stack); static tree_it min(node *root); static tree_it greater_equal(node *root, const char *key); @@ -64,18 +64,20 @@ template class tree_it { bool operator!=(const tree_it &rhs) const; template void key(OutputIt key) const; + int get_key_len() const; const std::string key() const; - int get_depth() const; + private: step &get_step(); const step &get_step() const; - node *get_node() const; const char *get_key() const; + int get_depth() const; void seek_leaf(); + node *root_; std::vector traversal_stack_; }; @@ -85,7 +87,7 @@ tree_it::step::step() template tree_it::step::step(int depth, child_it c_it, child_it c_it_end) - : node_(c_it != c_it_end ? c_it.get_child_node() : nullptr), + : child_node_(c_it != c_it_end ? c_it.get_child_node() : nullptr), depth_(depth), key_(depth ? new char[depth] : nullptr), child_it_(c_it), @@ -93,7 +95,7 @@ tree_it::step::step(int depth, child_it c_it, child_it c_it_end) template tree_it::step::step(node *node, int depth, const char *key, child_it c_it, child_it c_it_end) - : node_(node), + : child_node_(node), depth_(depth), key_(depth ? new char[depth] : nullptr), child_it_(c_it), @@ -105,9 +107,12 @@ template typename tree_it::step &tree_it::step::operator++() { assert(child_it_ != child_it_end_); ++child_it_; - node_ = child_it_ != child_it_end_ + child_node_ = child_it_ != child_it_end_ ? child_it_.get_child_node() : nullptr; + key_[depth_ - 1] = child_it_ != child_it_end_ + ? child_it_.get_partial_key() + : '\0'; return *this; } @@ -120,16 +125,16 @@ typename tree_it::step tree_it::step::operator++(int) { template tree_it::step::step(const tree_it::step &other) - : step(other.node_, other.depth_, other.key_, other.child_it_, other.child_it_end_) {} + : step(other.child_node_, other.depth_, other.key_, other.child_it_, other.child_it_end_) {} template tree_it::step::step(tree_it::step &&other) - : node_(other.node_), + : child_node_(other.child_node_), depth_(other.depth_), key_(other.key_), child_it_(other.child_it_), child_it_end_(other.child_it_end_) { - other.node_ = nullptr; + other.child_node_ = nullptr; other.depth_ = 0; other.key_ = nullptr; other.child_it_ = {}; @@ -144,14 +149,14 @@ tree_it::step::~step() { template typename tree_it::step& tree_it::step::operator=(const tree_it::step &other) { if (this != &other) { - node *node = other.node_; + node *node = other.child_node_; int depth = other.depth_; char *key = depth ? new char[depth] : nullptr; std::copy_n(other.key_, other.depth_, key); child_it c_it = other.child_it_; child_it c_it_end = other.child_it_end_; - node_ = node; + child_node_ = node; depth_ = depth; delete [] key_; key_ = key; @@ -164,8 +169,8 @@ typename tree_it::step& tree_it::step::operator=(const tree_it::step &o template typename tree_it::step& tree_it::step::operator=(tree_it::step &&other) noexcept { if (this != &other) { - node_ = other.node_; - other.node_ = nullptr; + child_node_ = other.child_node_; + other.child_node_ = nullptr; depth_ = other.depth_; other.depth_ = 0; @@ -184,10 +189,10 @@ typename tree_it::step& tree_it::step::operator=(tree_it::step &&other) } template -tree_it::tree_it() : tree_it(std::vector::step>()) {} +tree_it::tree_it() {} template -tree_it::tree_it(std::vector traversal_stack) : traversal_stack_(traversal_stack) { +tree_it::tree_it(node *root, std::vector traversal_stack) : root_(root), traversal_stack_(traversal_stack) { seek_leaf(); } @@ -207,18 +212,18 @@ tree_it tree_it::greater_equal(node *root, const char *key) { while (true) { tree_it::step &cur_step = traversal_stack.back(); - node *cur_node = cur_step.node_; + node *cur_node = cur_step.child_node_; int cur_depth = cur_step.depth_; int prefix_match_len = std::min(cur_node->check_prefix(key + cur_depth, key_len - cur_depth), key_len - cur_depth); // if search key "equals" the prefix if (key_len == cur_depth + prefix_match_len) { - return tree_it(traversal_stack); + return tree_it(root, traversal_stack); } // if search key is "greater than" the prefix if (prefix_match_len < cur_node->prefix_len_ && key[cur_depth + prefix_match_len] > cur_node->prefix_[prefix_match_len]) { ++cur_step; - return tree_it(traversal_stack); + return tree_it(root, traversal_stack); } if (cur_node->is_leaf()) { continue; @@ -233,7 +238,13 @@ tree_it tree_it::greater_equal(node *root, const char *key) { break; } } - traversal_stack.push_back({cur_depth + cur_node->prefix_len_ + 1, c_it, c_it_end}); + int depth = cur_depth + cur_node->prefix_len_ + 1; + tree_it::step child(depth, c_it, c_it_end); + /* compute child key: cur_key + cur_node->prefix_ + child_partial_key */ + std::copy_n(cur_step.key_, cur_depth, child.key_); + std::copy_n(cur_node->prefix_, cur_node->prefix_len_, child.key_ + cur_depth); + child.key_[cur_depth + cur_node->prefix_len_] = c_it.get_partial_key(); + traversal_stack.push_back(child); } } @@ -283,6 +294,11 @@ void tree_it::key(OutputIt key) const { std::copy_n(get_node()->prefix_, get_node()->prefix_len_, key + get_depth()); } +template +int tree_it::get_key_len() const { + return get_depth() + get_node()->prefix_len_; +} + template const std::string tree_it::key() const { std::string str(get_depth() + get_node()->prefix_len_ - 1, 0); @@ -295,7 +311,9 @@ void tree_it::seek_leaf() { /* traverse up until a node on the right is found or stack gets empty */ for (; get_step().child_it_ == get_step().child_it_end_; ++get_step()) { traversal_stack_.pop_back(); - if (traversal_stack_.empty()) { + if (get_step().child_node_ == root_) { // root guard + traversal_stack_.pop_back(); + assert(traversal_stack_.empty()); return; } } @@ -317,7 +335,7 @@ void tree_it::seek_leaf() { template node * tree_it::get_node() const { - return get_step().node_; + return get_step().child_node_; } template diff --git a/test/tree_it.cpp b/test/tree_it.cpp index 30af8ad..bffd740 100644 --- a/test/tree_it.cpp +++ b/test/tree_it.cpp @@ -59,69 +59,62 @@ TEST_SUITE("tree_it") { auto it = m.begin(); auto it_end = m.end(); - std::unique_ptr managed_passed_key(new char[20]); - char *passed_key = managed_passed_key.get(); + std::string key; + key.reserve(20); // 0 REQUIRE(it != it_end); REQUIRE_EQ(&int0, *it); - REQUIRE_EQ(3, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 3, "aa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 3, "aa")); REQUIRE_EQ("aa", it.key()); ++it; // 1 REQUIRE(it != it_end); REQUIRE_EQ(&int1, *it); - REQUIRE_EQ(5, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 5, "aaaa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 5, "aaaa")); REQUIRE_EQ("aaaa", it.key()); ++it; // 2 REQUIRE(it != it_end); REQUIRE_EQ(&int2, *it); - REQUIRE_EQ(8, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 8, "aaaaaaa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 8, "aaaaaaa")); REQUIRE_EQ("aaaaaaa", it.key()); ++it; // 3 REQUIRE(it != it_end); REQUIRE_EQ(&int3, *it); - REQUIRE_EQ(11, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 11, "aaaaaaaaaa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 11, "aaaaaaaaaa")); REQUIRE_EQ("aaaaaaaaaa", it.key()); ++it; // 4 REQUIRE(it != it_end); REQUIRE_EQ(&int4, *it); - REQUIRE_EQ(10, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 10, "aaaaaaaba")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 10, "aaaaaaaba")); REQUIRE_EQ("aaaaaaaba", it.key()); ++it; // 5 REQUIRE(it != it_end); REQUIRE_EQ(&int5, *it); - REQUIRE_EQ(8, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 8, "aaaabaa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 8, "aaaabaa")); REQUIRE_EQ("aaaabaa", it.key()); ++it; // 6 REQUIRE(it != it_end); REQUIRE_EQ(&int6, *it); - REQUIRE_EQ(11, it.get_depth()); - it.key(passed_key); - REQUIRE(std::equal(passed_key, passed_key + 11, "aaaabaaaaa")); + it.key(key.begin()); + REQUIRE(std::equal(key.begin(), key.begin() + 11, "aaaabaaaaa")); REQUIRE_EQ("aaaabaaaaa", it.key()); ++it; From dae941b19c6d2e9bbb48090b0cff7355bf400ac1 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 14 May 2021 22:58:24 +0200 Subject: [PATCH 15/18] feat: T template argument non pointer --- bench/delete.cpp | 2 +- bench/insert.cpp | 2 +- bench/mixed.cpp | 2 +- bench/mixed_dense.cpp | 2 +- bench/query_iteration.cpp | 8 ++-- bench/query_sparse_uniform.cpp | 2 +- bench/query_sparse_uniform_64.cpp | 2 +- bench/query_sparse_zipf.cpp | 2 +- include/art/art.hpp | 37 +++++++++-------- include/art/inner_node.hpp | 3 +- include/art/leaf_node.hpp | 6 +-- include/art/tree_it.hpp | 2 +- src/example.cpp | 47 +++++++++++----------- test/art.cpp | 8 ++-- test/inner_node.cpp | 20 +++++----- test/node.cpp | 2 +- test/node_16.cpp | 26 ++++++------ test/node_256.cpp | 66 +++++++++++++++---------------- test/node_4.cpp | 24 +++++------ test/node_48.cpp | 26 ++++++------ test/tree_it.cpp | 8 ++-- 21 files changed, 149 insertions(+), 148 deletions(-) diff --git a/bench/delete.cpp b/bench/delete.cpp index 81e3b5b..b251a33 100644 --- a/bench/delete.cpp +++ b/bench/delete.cpp @@ -15,7 +15,7 @@ using picobench::state; PICOBENCH_SUITE("delete"); static void art_delete_sparse(state &s) { - art::art m; + art::art m; int v = 1; std::mt19937_64 g1(0); for (auto i __attribute__((unused)) : s) { diff --git a/bench/insert.cpp b/bench/insert.cpp index 90d3bcc..6381fa0 100644 --- a/bench/insert.cpp +++ b/bench/insert.cpp @@ -17,7 +17,7 @@ using picobench::state; PICOBENCH_SUITE("insert"); static void art_insert_sparse(state &s) { - art::art m; + art::art m; int v = 1; std::mt19937_64 rng(0); for (auto i __attribute__((unused)) : s) { diff --git a/bench/mixed.cpp b/bench/mixed.cpp index 0cd4ff2..fbd385e 100644 --- a/bench/mixed.cpp +++ b/bench/mixed.cpp @@ -28,7 +28,7 @@ using std::unordered_map; PICOBENCH_SUITE("mixed"); static void art_mixed_sparse(state &s) { - art::art m; + art::art m; fast_zipf rng(10000000); hash h; string k; diff --git a/bench/mixed_dense.cpp b/bench/mixed_dense.cpp index 1ac6cba..621f2f5 100644 --- a/bench/mixed_dense.cpp +++ b/bench/mixed_dense.cpp @@ -44,7 +44,7 @@ static void art_mixed(state &s) { int v = 1; fast_zipf rng(n); - art::art m; + art::art m; string k; for (auto i __attribute__((unused)) : s) { k = dataset[rng()]; diff --git a/bench/query_iteration.cpp b/bench/query_iteration.cpp index f20fb7f..a2eb057 100644 --- a/bench/query_iteration.cpp +++ b/bench/query_iteration.cpp @@ -22,11 +22,11 @@ using std::unordered_map; PICOBENCH_SUITE("query iteration"); static void full_scan_zipf(state &s) { - art::art m; + art::art m; hash h; int v = 1; int *v_ptr = &v; - art::tree_it it, it_end; + art::tree_it it, it_end; fast_zipf rng(1000000); for (int i = 0; i < 100000; ++i) { m.set(to_string(h(rng())).c_str(), v_ptr); @@ -38,11 +38,11 @@ static void full_scan_zipf(state &s) { PICOBENCH(full_scan_zipf).iterations({1000}); static void full_scan_uniform(state &s) { - art::art m; + art::art m; hash h; int v = 1; int *v_ptr = &v; - art::tree_it it, it_end; + art::tree_it it, it_end; mt19937_64 rng(0); for (int i = 0; i < 100000; ++i) { m.set(to_string(h(rng())).c_str(), v_ptr); diff --git a/bench/query_sparse_uniform.cpp b/bench/query_sparse_uniform.cpp index c5e891e..4f77df3 100644 --- a/bench/query_sparse_uniform.cpp +++ b/bench/query_sparse_uniform.cpp @@ -24,7 +24,7 @@ using std::unordered_map; PICOBENCH_SUITE("query sparse uniform"); static void art_q_s_u(state &s) { - art::art m; + art::art m; hash h; int v = 1; int *v_ptr = &v; diff --git a/bench/query_sparse_uniform_64.cpp b/bench/query_sparse_uniform_64.cpp index 7ce5d12..11eb0a1 100644 --- a/bench/query_sparse_uniform_64.cpp +++ b/bench/query_sparse_uniform_64.cpp @@ -27,7 +27,7 @@ PICOBENCH_SUITE("query sparse uniform base 64 keys"); std::string to_base64(const std::string& string_); static void art_q_s_u(state &s) { - art::art m; + art::art m; hash h; int v = 1; int *v_ptr = &v; diff --git a/bench/query_sparse_zipf.cpp b/bench/query_sparse_zipf.cpp index edcbb55..e1b2a94 100644 --- a/bench/query_sparse_zipf.cpp +++ b/bench/query_sparse_zipf.cpp @@ -23,7 +23,7 @@ using std::unordered_map; PICOBENCH_SUITE("query sparse zipf"); static void art_q_s_z(state &s) { - art::art m; + art::art m; hash h; int v = 1; int *v_ptr = &v; diff --git a/include/art/art.hpp b/include/art/art.hpp index 14830ac..ef2e7cd 100644 --- a/include/art/art.hpp +++ b/include/art/art.hpp @@ -27,7 +27,7 @@ template class art { * @param key - The key to find. * @return the value associated with the key or a nullptr. */ - T *get(const char *key) const; + T get(const char *key) const; /** * Associates the given key with the given value. @@ -39,7 +39,7 @@ template class art { * @return a nullptr if no other value is associated with they or the * previously associated value. */ - T *set(const char *key, T *value); + T set(const char *key, T value); /** * Deletes the given key and returns it's associated value. @@ -50,7 +50,7 @@ template class art { * @param key - The key to delete. * @return the values assciated with they key or a nullptr otherwise. */ - T *del(const char *key); + T del(const char *key); /** * Forward iterator that traverses the tree in lexicographic order. @@ -97,33 +97,35 @@ template art::~art() { } } -template T *art::get(const char *key) const { +template +T art::get(const char *key) const { node *cur = root_, **child; int depth = 0, key_len = std::strlen(key) + 1; while (cur != nullptr) { if (cur->prefix_len_ != cur->check_prefix(key + depth, key_len - depth)) { /* prefix mismatch */ - return nullptr; + return T{}; } if (cur->prefix_len_ == key_len - depth) { /* exact match */ - return cur->is_leaf() ? static_cast*>(cur)->value_ : nullptr; + return cur->is_leaf() ? static_cast*>(cur)->value_ : T{}; } child = static_cast*>(cur)->find_child(key[depth + cur->prefix_len_]); depth += (cur->prefix_len_ + 1); cur = child != nullptr ? *child : nullptr; } - return nullptr; + return T{}; } -template T *art::set(const char *key, T *value) { +template +T art::set(const char *key, T value) { int key_len = std::strlen(key) + 1, depth = 0, prefix_match_len; if (root_ == nullptr) { root_ = new leaf_node(value); root_->prefix_ = new char[key_len]; std::copy(key, key + key_len + 1, root_->prefix_); root_->prefix_len_ = key_len; - return nullptr; + return T{}; } node **cur = &root_, **child; @@ -155,7 +157,7 @@ template T *art::set(const char *key, T *value) { /* cur must be a leaf */ auto cur_leaf = static_cast*>(*cur); - T *old_value = cur_leaf->value_; + T old_value = cur_leaf->value_; cur_leaf->value_ = value; return old_value; } @@ -205,7 +207,7 @@ template T *art::set(const char *key, T *value) { new_parent->set_child(key[depth + prefix_match_len], new_node); *cur = new_parent; - return nullptr; + return T{}; } /* must be inner node */ @@ -235,7 +237,7 @@ template T *art::set(const char *key, T *value) { new_node->prefix_); new_node->prefix_len_ = key_len - depth - (**cur).prefix_len_ - 1; (**cur_inner).set_child(child_partial_key, new_node); - return nullptr; + return T{}; } /* propagate down and repeat: @@ -251,11 +253,12 @@ template T *art::set(const char *key, T *value) { } } -template T *art::del(const char *key) { +template +T art::del(const char *key) { int depth = 0, key_len = std::strlen(key) + 1; if (root_ == nullptr) { - return nullptr; + return T{}; } /* pointer to parent, current and child node */ @@ -270,13 +273,13 @@ template T *art::del(const char *key) { (**cur).check_prefix(key + depth, key_len - depth)) { /* prefix mismatch => key doesn't exist */ - return nullptr; + return T{}; } if (key_len == depth + (**cur).prefix_len_) { /* exact match */ if (!(**cur).is_leaf()) { - return nullptr; + return T{}; } auto value = static_cast*>(*cur)->value_; auto n_siblings = par != nullptr ? (**par).n_children() - 1 : 0; @@ -374,7 +377,7 @@ template T *art::del(const char *key) { par = reinterpret_cast**>(cur); cur = (**par).find_child(cur_partial_key); } - return nullptr; + return T{}; } template tree_it art::begin() { diff --git a/include/art/inner_node.hpp b/include/art/inner_node.hpp index 1003805..83e2f2e 100644 --- a/include/art/inner_node.hpp +++ b/include/art/inner_node.hpp @@ -21,13 +21,12 @@ namespace art { template class inner_node : public node { public: - virtual ~inner_node() = default; - inner_node() = default; inner_node(const inner_node &other) = default; inner_node(inner_node &&other) noexcept = default; inner_node &operator=(const inner_node &other) = default; inner_node &operator=(inner_node &&other) noexcept = default; + virtual ~inner_node() = default; bool is_leaf() const override; diff --git a/include/art/leaf_node.hpp b/include/art/leaf_node.hpp index 6ff388e..aeaaeaf 100644 --- a/include/art/leaf_node.hpp +++ b/include/art/leaf_node.hpp @@ -14,14 +14,14 @@ template class art; template class leaf_node : public node { public: - explicit leaf_node(T *value); + explicit leaf_node(T value); bool is_leaf() const override; - T *value_; + T value_; }; template -leaf_node::leaf_node(T *value): value_(value) {} +leaf_node::leaf_node(T value): value_(value) {} template bool leaf_node::is_leaf() const { return true; } diff --git a/include/art/tree_it.hpp b/include/art/tree_it.hpp index 06fa59c..4870e04 100644 --- a/include/art/tree_it.hpp +++ b/include/art/tree_it.hpp @@ -50,7 +50,7 @@ template class tree_it { static tree_it greater_equal(node *root, const char *key); using iterator_category = std::forward_iterator_tag; - using value_type = T *; + using value_type = T; using difference_type = int; using pointer = value_type *; /* using reference = const value_type &; */ diff --git a/src/example.cpp b/src/example.cpp index 91b3e0b..1fc59ce 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using std::string; @@ -22,7 +23,7 @@ void art_bench() { file.close(); fast_zipf rng(n); - art::art m; + art::art m; /* std::map m; */ /* std::unordered_map m; */ int v = 1; @@ -35,7 +36,7 @@ void art_bench() { } /* void art_sparse_uniform() { */ -/* art::art m; */ +/* art::art m; */ /* int n = 1000; */ /* int v = 1; */ /* std::mt19937_64 rng1(0); */ @@ -70,7 +71,7 @@ void art_bench() { /* } */ /* void art_compressions_dense_insert() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* std::string k; */ /* int i; */ @@ -85,7 +86,7 @@ void art_bench() { /* } */ /* void art_compressions_dense_delete() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* std::string k; */ /* int i; */ @@ -105,7 +106,7 @@ void art_bench() { /* } */ /* void art_compressions_paths_insert() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* auto file = std::ifstream("dataset.txt"); */ /* std::string line; */ @@ -122,7 +123,7 @@ void art_bench() { /* } */ /* void art_compressions_paths_delete() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* auto file = std::ifstream("dataset.txt"); */ /* std::string line; */ @@ -145,7 +146,7 @@ void art_bench() { /* } */ /* void art_compressions_sparse_insert() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* std::mt19937_64 rng1(0); */ /* std::string k; */ @@ -161,7 +162,7 @@ void art_bench() { /* } */ /* void art_compressions_sparse_delete() { */ -/* art::art m; */ +/* art::art m; */ /* int v = 1; */ /* std::mt19937_64 rng1(0); */ /* std::string k; */ @@ -183,7 +184,7 @@ void art_bench() { /* } */ void casual_stress_test(int n) { - art::art m; + art::art m; int v = 1; std::mt19937_64 rng1(0); std::string k; @@ -213,23 +214,20 @@ int main() { /* art_compressions_dense_delete(); */ /* casual_stress_test(16 * 1000 * 1000); */ - int int0 = 0; - int int1 = 1; - int int2 = 2; - int int3 = 4; - int int4 = 5; - int int5 = 5; - int int6 = 6; + + // + // simple example + // art::art m; - m.set("aa", &int0); - m.set("aaaa", &int1); - m.set("aaaaaaa", &int2); - m.set("aaaaaaaaaa", &int3); - m.set("aaaaaaaba", &int4); - m.set("aaaabaa", &int5); - m.set("aaaabaaaaa", &int6); + m.set("aa", 0); + m.set("aaaa", 1); + m.set("aaaaaaa", 2); + m.set("aaaaaaaaaa", 3); + m.set("aaaaaaaba", 4); + m.set("aaaabaa", 5); + m.set("aaaabaaaaa", 6); /* The above statements construct the following tree: * @@ -249,7 +247,8 @@ int main() { auto it = m.begin(); auto it_end = m.end(); for (int i = 0; it != it_end; ++i, ++it) { - std::cout << i << ": " << **it << std::endl; + std::cout << it.key() << " -> " << *it << std::endl; } + return 0; } diff --git a/test/art.cpp b/test/art.cpp index 358911b..086ae6f 100644 --- a/test/art.cpp +++ b/test/art.cpp @@ -25,7 +25,7 @@ TEST_SUITE("art") { TEST_CASE("set") { - art::art trie; + art::art trie; int dummy_value_1; int dummy_value_2; @@ -79,7 +79,7 @@ TEST_SUITE("art") { values[i] = new int(); } - art::art m; + art::art m; for (int i = 0; i < n; i += 1) { m.set(keys[i].c_str(), values[i]); @@ -119,7 +119,7 @@ TEST_SUITE("art") { auto key9 = "aaaaaaaaaac"; auto int9 = 9; - art::art m; + art::art m; m.set(key0, &int0); m.set(key1, &int1); @@ -274,7 +274,7 @@ TEST_SUITE("art") { } TEST_CASE("monte carlo delete") { - art::art m; + art::art m; mt19937_64 rng1(0); for (int i = 0; i < 1000000; ++i) { auto k = to_string(rng1()); diff --git a/test/inner_node.cpp b/test/inner_node.cpp index 14725aa..af790eb 100644 --- a/test/inner_node.cpp +++ b/test/inner_node.cpp @@ -28,12 +28,12 @@ using std::string; TEST_SUITE("inner_node") { TEST_CASE("iteration") { - node_4 m; + node_4 m; - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); m.set_child(0, &n0); m.set_child(5, &n1); @@ -103,12 +103,12 @@ TEST_SUITE("inner_node") { } TEST_CASE("reverse iteration") { - node_4 m; + node_4 m; - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); m.set_child(0, &n0); m.set_child(5, &n1); diff --git a/test/node.cpp b/test/node.cpp index 737cb6b..bf26b48 100644 --- a/test/node.cpp +++ b/test/node.cpp @@ -28,7 +28,7 @@ using std::string; TEST_SUITE("node") { TEST_CASE("check_prefix") { - leaf_node node(nullptr); + leaf_node node(nullptr); string key = "000100001"; int key_len = key.length() + 1; // +1 for \0 string prefix = "0000"; diff --git a/test/node_16.cpp b/test/node_16.cpp index 71a1ee3..f082503 100644 --- a/test/node_16.cpp +++ b/test/node_16.cpp @@ -22,14 +22,14 @@ TEST_SUITE("node 16") { TEST_CASE("monte carlo") { /* set up */ array partial_keys; - array *, 256> children; + array *, 256> children; for (int i = 0; i < 256; i += 1) { /* populate partial_keys with all values in the partial_keys_t domain */ partial_keys[i] = i; /* populate child nodes */ - children[i] = new leaf_node(nullptr); + children[i] = new leaf_node(nullptr); } /* rng */ @@ -38,7 +38,7 @@ TEST_SUITE("node 16") { for (int experiment = 0; experiment < 1000; experiment += 1) { /* test subject */ - node_16 node; + node_16 node; /* shuffle in order to make a seemingly random insertion order */ shuffle(partial_keys.begin(), partial_keys.end(), g); @@ -68,15 +68,15 @@ TEST_SUITE("node 16") { } TEST_CASE("delete child") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); - leaf_node n4(nullptr); - leaf_node n5(nullptr); - leaf_node n6(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); + leaf_node n4(nullptr); + leaf_node n5(nullptr); + leaf_node n6(nullptr); - node_16 subject; + node_16 subject; subject.set_child(1, &n1); subject.set_child(2, &n2); @@ -141,7 +141,7 @@ TEST_SUITE("node 16") { } TEST_CASE("next partial key") { - node_16 n; + node_16 n; SUBCASE("completely empty node") { REQUIRE_THROWS_AS(n.next_partial_key(0), std::out_of_range); @@ -189,7 +189,7 @@ TEST_SUITE("node 16") { } TEST_CASE("previous partial key") { - node_16 n; + node_16 n; SUBCASE("completely empty node") { REQUIRE_THROWS_AS(n.prev_partial_key(127), std::out_of_range); diff --git a/test/node_256.cpp b/test/node_256.cpp index 71436e7..48d60b3 100644 --- a/test/node_256.cpp +++ b/test/node_256.cpp @@ -22,12 +22,12 @@ TEST_SUITE("node 256") { TEST_CASE("monte carlo") { /* set up */ array partial_keys; - array *, 256> children; + array *, 256> children; for (int i = 0; i < 256; i += 1) { /* populate partial_keys with all values in the char domain */ partial_keys[i] = i - 128; - children[i] = new leaf_node(nullptr); + children[i] = new leaf_node(nullptr); } /* rng */ @@ -35,7 +35,7 @@ TEST_SUITE("node 256") { for (int experiment = 0; experiment < 100; experiment += 1) { /* test subject */ - node_256 node; + node_256 node; /* shuffle in order to make a seemingly random insertion order */ shuffle(partial_keys.begin(), partial_keys.end(), g); @@ -64,15 +64,15 @@ TEST_SUITE("node 256") { } TEST_CASE("delete child") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); - leaf_node n4(nullptr); - leaf_node n5(nullptr); - leaf_node n6(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); + leaf_node n4(nullptr); + leaf_node n5(nullptr); + leaf_node n6(nullptr); - node_256 subject; + node_256 subject; subject.set_child(1, &n1); subject.set_child(2, &n2); @@ -137,14 +137,14 @@ TEST_SUITE("node 256") { } TEST_CASE("next partial key") { - node_256 n; + node_256 n; SUBCASE("completely empty node") { REQUIRE_THROWS_AS(n.next_partial_key(-128), std::out_of_range); } SUBCASE("child at -128") { - leaf_node n0(nullptr); + leaf_node n0(nullptr); n.set_child(-128, &n0); REQUIRE_EQ(-128, n.next_partial_key(-128)); for (int i = 1; i < 256; ++i) { @@ -153,7 +153,7 @@ TEST_SUITE("node 256") { } SUBCASE("child at 127") { - leaf_node n0(nullptr); + leaf_node n0(nullptr); n.set_child(127, &n0); for (int i = 0; i < 256; ++i) { REQUIRE_EQ(127, n.next_partial_key(i - 128)); @@ -161,10 +161,10 @@ TEST_SUITE("node 256") { } SUBCASE("dense children") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); n.set_child(0, &n0); n.set_child(1, &n1); n.set_child(2, &n2); @@ -177,10 +177,10 @@ TEST_SUITE("node 256") { } SUBCASE("sparse children") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); n.set_child(0, &n0); n.set_child(5, &n1); n.set_child(10, &n2); @@ -194,7 +194,7 @@ TEST_SUITE("node 256") { } TEST_CASE("previous partial key") { - node_256 n; + node_256 n; SUBCASE("completely empty node") { for (int i = 0; i < 256; ++i) { @@ -203,7 +203,7 @@ TEST_SUITE("node 256") { } SUBCASE("child at -128") { - leaf_node n0(nullptr); + leaf_node n0(nullptr); n.set_child(-128, &n0); for (int i = 0; i < 256; ++i) { REQUIRE_EQ(-128, n.prev_partial_key(i - 128)); @@ -211,7 +211,7 @@ TEST_SUITE("node 256") { } SUBCASE("child at 127") { - leaf_node n0(nullptr); + leaf_node n0(nullptr); n.set_child(127, &n0); REQUIRE_EQ(127, n.prev_partial_key(127)); for (int i = 0; i < 255; ++i) { @@ -220,10 +220,10 @@ TEST_SUITE("node 256") { } SUBCASE("dense children") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); n.set_child(1, &n0); n.set_child(2, &n1); n.set_child(3, &n2); @@ -237,10 +237,10 @@ TEST_SUITE("node 256") { } SUBCASE("sparse children") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); n.set_child(1, &n0); n.set_child(5, &n1); n.set_child(10, &n2); diff --git a/test/node_4.cpp b/test/node_4.cpp index 511928c..39e6346 100644 --- a/test/node_4.cpp +++ b/test/node_4.cpp @@ -23,14 +23,14 @@ TEST_SUITE("node 4") { TEST_CASE("monte carlo insert") { /* set up */ array partial_keys; - array *, 256> children; + array *, 256> children; for (int i = 0; i < 256; i += 1) { /* populate partial_keys with all values in the partial_keys_t domain */ partial_keys[i] = i; /* populate child nodes */ - children[i] = new leaf_node(nullptr); + children[i] = new leaf_node(nullptr); } /* rng */ @@ -39,7 +39,7 @@ TEST_SUITE("node 4") { for (int experiment = 0; experiment < 10000; experiment += 1) { /* test subject */ - node_4 node; + node_4 node; /* shuffle in order to make a seemingly random insertion order */ shuffle(partial_keys.begin(), partial_keys.end(), g); @@ -69,15 +69,15 @@ TEST_SUITE("node 4") { } TEST_CASE("delete child") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); - leaf_node n4(nullptr); - leaf_node n5(nullptr); - leaf_node n6(nullptr); - - node_4 subject; + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); + leaf_node n4(nullptr); + leaf_node n5(nullptr); + leaf_node n6(nullptr); + + node_4 subject; subject.set_child(1, &n1); subject.set_child(2, &n2); diff --git a/test/node_48.cpp b/test/node_48.cpp index 4e04487..7a41d97 100644 --- a/test/node_48.cpp +++ b/test/node_48.cpp @@ -21,14 +21,14 @@ TEST_SUITE("node 48") { TEST_CASE("monte carlo") { /* set up */ array partial_keys; - array *, 256> children; + array *, 256> children; for (int i = 0; i < 256; i += 1) { /* populate partial_keys with all values in the partial_keys_t domain */ partial_keys[i] = i - 128; /* populate child nodes */ - children[i] = new leaf_node(nullptr); + children[i] = new leaf_node(nullptr); } /* rng */ @@ -36,7 +36,7 @@ TEST_SUITE("node 48") { for (int experiment = 0; experiment < 10000; experiment += 1) { /* test subject */ - node_48 node; + node_48 node; /* shuffle in order to make a seemingly random insertion order */ shuffle(partial_keys.begin(), partial_keys.end(), g); @@ -67,15 +67,15 @@ TEST_SUITE("node 48") { } TEST_CASE("delete child") { - leaf_node n0(nullptr); - leaf_node n1(nullptr); - leaf_node n2(nullptr); - leaf_node n3(nullptr); - leaf_node n4(nullptr); - leaf_node n5(nullptr); - leaf_node n6(nullptr); + leaf_node n0(nullptr); + leaf_node n1(nullptr); + leaf_node n2(nullptr); + leaf_node n3(nullptr); + leaf_node n4(nullptr); + leaf_node n5(nullptr); + leaf_node n6(nullptr); - node_48 subject; + node_48 subject; subject.set_child(1, &n1); subject.set_child(2, &n2); @@ -140,7 +140,7 @@ TEST_SUITE("node 48") { } TEST_CASE("next partial key") { - node_48 n; + node_48 n; SUBCASE("completely empty node") { for (int i = 0; i < 256; ++i) { @@ -189,7 +189,7 @@ TEST_SUITE("node 48") { } TEST_CASE("previous partial key") { - node_48 n; + node_48 n; SUBCASE("completely empty node") { REQUIRE_THROWS_AS(n.prev_partial_key(127), std::out_of_range); diff --git a/test/tree_it.cpp b/test/tree_it.cpp index bffd740..7929e92 100644 --- a/test/tree_it.cpp +++ b/test/tree_it.cpp @@ -32,7 +32,7 @@ TEST_SUITE("tree_it") { int int5 = 5; int int6 = 6; - art::art m; + art::art m; m.set("aa", &int0); m.set("aaaa", &int1); @@ -126,7 +126,7 @@ TEST_SUITE("tree_it") { int n = 0x10000; char key[5]; int value; - art::art m; + art::art m; for (int i = 0; i < n; ++i) { std::snprintf(key, 5, "%04X", i); m.set(key, &value); @@ -152,7 +152,7 @@ TEST_SUITE("tree_it") { int int5 = 5; int int6 = 6; - art::art m; + art::art m; m.set("aa", &int0); m.set("aaaa", &int1); @@ -208,7 +208,7 @@ TEST_SUITE("tree_it") { int n = 1 << (n_bytes * 4); char keys[n][n_bytes + 1]; int value; - art::art m; + art::art m; for (int i = 0; i < n; ++i) { std::snprintf(keys[i], n_bytes + 1, "%04X", i); // note: change format if you change n_bytes m.set(keys[i], &value); From 7f0dd0ae78a907e6514ece94e8ad2a8a0eecd111 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Fri, 14 May 2021 23:22:02 +0200 Subject: [PATCH 16/18] Update README.md --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cdbcab7..a3414d4 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,13 @@ compression reduces the tree height and horizontal compression decreases a node using namespace art; int main() { - art m; + art> m; - int v = 2; - // set k to v - m.set("k", &v); + // set k + m.set("k", std::make_shared(new MyResource())); - // get value of k - int * v_ptr = m.get("k"); + // get k + std::shared_ptr ptr = m.get("k"); // delete k m.del("k"); @@ -100,6 +99,9 @@ query sparse zipf: =============================================================================== ``` +You can replicate using `make release && make bench` + + ## References * [The Adaptive Radix Tree: ARTful Indexing for Main-Memory Databases](http://www-db.in.tum.de/~leis/papers/ART.pdf) From 4284be785d79b3a87b6c1173c6be2b1de271bbb7 Mon Sep 17 00:00:00 2001 From: Rafael Kallis Date: Thu, 27 Jan 2022 09:50:04 +0100 Subject: [PATCH 17/18] docs: art::get return Co-authored-by: Evance Soumaoro --- include/art/art.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/art/art.hpp b/include/art/art.hpp index ef2e7cd..5ceae94 100644 --- a/include/art/art.hpp +++ b/include/art/art.hpp @@ -25,7 +25,7 @@ template class art { * Finds the value associated with the given key. * * @param key - The key to find. - * @return the value associated with the key or a nullptr. + * @return the value associated with the key or a default constructed value. */ T get(const char *key) const; From ae5935365e299745c203ee0b0146e4e44f6f1585 Mon Sep 17 00:00:00 2001 From: Xu Jianghe Date: Thu, 9 Jun 2022 18:47:13 +0800 Subject: [PATCH 18/18] bugfix: 'node_16::grow()' creates inconsistent node_48 --- include/art/node_16.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/art/node_16.hpp b/include/art/node_16.hpp index 93a4026..8801363 100644 --- a/include/art/node_16.hpp +++ b/include/art/node_16.hpp @@ -112,6 +112,7 @@ template inner_node *node_16::grow() { auto new_node = new node_48(); new_node->prefix_ = this->prefix_; new_node->prefix_len_ = this->prefix_len_; + new_node->n_children_ = this->n_children_; std::copy(this->children_, this->children_ + this->n_children_, new_node->children_); for (int i = 0; i < n_children_; ++i) { new_node->indexes_[(uint8_t) this->keys_[i]] = i;