Skip to content

Commit

Permalink
Merge pull request #7 from rafaelkallis/preview
Browse files Browse the repository at this point in the history
4.2
  • Loading branch information
rafaelkallis authored May 13, 2021
2 parents 89f0441 + 6e76377 commit ee08802
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 270 deletions.
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")

add_library(art INTERFACE)

Expand Down Expand Up @@ -53,6 +53,7 @@ add_executable(test
"${PROJECT_SOURCE_DIR}/test/node_16.cpp"
"${PROJECT_SOURCE_DIR}/test/node_48.cpp"
"${PROJECT_SOURCE_DIR}/test/node_256.cpp"
"${PROJECT_SOURCE_DIR}/test/tree_it.cpp"
)
target_link_libraries(test art doctest)

Expand All @@ -67,7 +68,7 @@ add_executable(bench
# "${PROJECT_SOURCE_DIR}/bench/node_16.cpp"
# "${PROJECT_SOURCE_DIR}/bench/node_48.cpp"
# "${PROJECT_SOURCE_DIR}/bench/node_256.cpp"
# "${PROJECT_SOURCE_DIR}/bench/query_iteration.cpp"
"${PROJECT_SOURCE_DIR}/bench/query_iteration.cpp"
"${PROJECT_SOURCE_DIR}/bench/query_sparse_uniform.cpp"
"${PROJECT_SOURCE_DIR}/bench/query_sparse_uniform_64.cpp"
"${PROJECT_SOURCE_DIR}/bench/query_sparse_zipf.cpp"
Expand Down
28 changes: 23 additions & 5 deletions include/art/child_it.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ template <class T> class child_it {
bool operator<=(const child_it &rhs) const;
bool operator>=(const child_it &rhs) const;

char get_partial_key() const;
node<T> *get_child_node() const;

private:
inner_node<T> *node_;
char cur_partial_key_;
int relative_index_;
inner_node<T> *node_ = nullptr;
char cur_partial_key_ = -128;
int relative_index_ = 0;
};

template <class T> child_it<T>::child_it(inner_node<T> *n) : child_it<T>(n, 0) {}
Expand Down Expand Up @@ -94,7 +97,9 @@ typename child_it<T>::pointer child_it<T>::operator->() const {

template <class T> child_it<T> &child_it<T>::operator++() {
++relative_index_;
if (relative_index_ == 0) {
if (relative_index_ < 0) {
return *this;
} else if (relative_index_ == 0) {
cur_partial_key_ = node_->next_partial_key(-128);
} else if (relative_index_ < node_->n_children()) {
cur_partial_key_ = node_->next_partial_key(cur_partial_key_ + 1);
Expand All @@ -110,7 +115,9 @@ template <class T> child_it<T> child_it<T>::operator++(int) {

template <class T> child_it<T> &child_it<T>::operator--() {
--relative_index_;
if (relative_index_ == node_->n_children() - 1) {
if (relative_index_ > node_->n_children() - 1) {
return *this;
} else if (relative_index_ == node_->n_children() - 1) {
cur_partial_key_ = node_->prev_partial_key(127);
} else if (relative_index_ >= 0) {
cur_partial_key_ = node_->prev_partial_key(cur_partial_key_ - 1);
Expand Down Expand Up @@ -148,6 +155,17 @@ template <class T> bool child_it<T>::operator>(const child_it<T> &rhs) const {
return (rhs < (*this));
}

template <class T>
char child_it<T>::get_partial_key() const {
return cur_partial_key_;
}

template <class T>
node<T> *child_it<T>::get_child_node() const {
assert(0 <= relative_index_ && relative_index_ < node_->n_children());
return *node_->find_child(cur_partial_key_);
}

} // namespace art

#endif
8 changes: 1 addition & 7 deletions include/art/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,7 @@ template <class T> class node {

template <class T>
int node<T>::check_prefix(const char *key, int /* key_len */) const {
// TODO(rafaelkallis): && i < key_len ??
for (int i = 0; i < prefix_len_; ++i) {
if (prefix_[i] != key[i]) {
return i;
}
}
return prefix_len_;
return std::mismatch(prefix_, prefix_ + prefix_len_, key).second - key;
}

} // namespace art
Expand Down
199 changes: 128 additions & 71 deletions include/art/tree_it.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <cstring>
#include <iostream>
#include <iterator>
#include <stack>
#include <vector>

namespace art {

Expand All @@ -21,8 +21,21 @@ template <class T> class leaf_node;

template <class T> class tree_it {
public:
struct step {
node<T> *node_;
int depth_;
child_it<T> child_it_;
child_it<T> child_it_end_;

step(int depth, child_it<T> c_it, child_it<T> c_it_end);
step(node<T> *node, int depth, child_it<T> c_it, child_it<T> c_it_end);

step &operator++();
step operator++(int);
};

tree_it() = default;
explicit tree_it(std::stack<node<T> *> traversal_stack);
explicit tree_it(std::vector<step> traversal_stack);

static tree_it<T> min(node<T> *root);
static tree_it<T> greater_equal(node<T> *root, const char *key);
Expand All @@ -41,30 +54,45 @@ template <class T> class tree_it {
bool operator==(const tree_it<T> &rhs) const;
bool operator!=(const tree_it<T> &rhs) const;

node<T> *get_node() const;
int get_depth() const;

private:
std::stack<node<T> *> traversal_stack_;
step &get_step();
const step &get_step() const;
void seek_leaf();

std::vector<step> traversal_stack_;
};

template <class T>
tree_it<T>::tree_it(std::stack<node<T> *> traversal_stack)
: traversal_stack_(traversal_stack) {
inner_node<T> *cur;
char child_partial_key;
node<T> *child;
std::reverse_iterator<child_it<T>> child_it, child_it_end;

/* preorder-traverse until leaf node found or no nodes are left */
while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) {
cur = static_cast<inner_node<T> *>(traversal_stack_.top());
traversal_stack_.pop();
child_it = cur->rbegin();
child_it_end = cur->rend();
for (; child_it != child_it_end; ++child_it) {
child_partial_key = *child_it;
child = *cur->find_child(child_partial_key);
traversal_stack_.push(child);
}
}
tree_it<T>::step::step(node<T> *node, int depth, child_it<T> c_it, child_it<T> c_it_end)
: node_(node), depth_(depth), child_it_(c_it), child_it_end_(c_it_end) {}

template <class T>
tree_it<T>::step::step(int depth, child_it<T> c_it, child_it<T> c_it_end)
: step(c_it != c_it_end ? c_it.get_child_node() : nullptr, depth, c_it, c_it_end) {}

template <class T>
typename tree_it<T>::step &tree_it<T>::step::operator++() {
assert(child_it_ != child_it_end_);
++child_it_;
node_ = child_it_ != child_it_end_
? child_it_.get_child_node()
: nullptr;
return *this;
}

template <class T>
typename tree_it<T>::step tree_it<T>::step::operator++(int) {
auto old = *this;
operator++();
return old;
}

template <class T>
tree_it<T>::tree_it(std::vector<step> traversal_stack) : traversal_stack_(traversal_stack) {
seek_leaf();
}

template <class T> tree_it<T> tree_it<T>::min(node<T> *root) {
Expand All @@ -73,76 +101,62 @@ template <class T> tree_it<T> tree_it<T>::min(node<T> *root) {

template <class T>
tree_it<T> tree_it<T>::greater_equal(node<T> *root, const char *key) {
if (root == nullptr) {
return tree_it<T>();
}
assert(root != nullptr);

int cur_depth, key_len = std::strlen(key), i;
node<T> *cur;
std::reverse_iterator<child_it<T>> child_it, child_it_end;
char partial_key;
std::stack<node<T> *> node_stack;
std::stack<int> depth_stack;
int key_len = std::strlen(key);
inner_node<T> *cur_inner_node;
child_it<T> child_it, child_it_end;
std::vector<tree_it<T>::step> traversal_stack;

node_stack.push(root);
depth_stack.push(0);
// sentinel child iterator for root
traversal_stack.push_back({root, 0, {nullptr, -2}, {nullptr, -1}});

while (true) {
cur = node_stack.top();
cur_depth = depth_stack.top();

if (cur_depth == key_len) {
return tree_it<T>(node_stack);
tree_it<T>::step &cur_step = traversal_stack.back();
node<T> *cur_node = cur_step.node_;
int cur_depth = cur_step.depth_;

int prefix_match_len = std::min<int>(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<T>(traversal_stack);
}
for (i = 0; i < cur->prefix_len_; ++i) {
if (cur_depth + i == key_len) {
return tree_it<T>(node_stack);
}
if (cur->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<T>(node_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<T>(traversal_stack);
}
node_stack.pop();
depth_stack.pop();
if (cur->is_leaf()) {
if (cur_node->is_leaf()) {
continue;
}
child_it = static_cast<inner_node<T> *>(cur)->rbegin();
child_it_end = static_cast<inner_node<T> *>(cur)->rend();
// seek subtree where search key is "lesser than or equal" the subtree partial key
cur_inner_node = static_cast<inner_node<T> *>(cur_node);
child_it = cur_inner_node->begin();
child_it_end = cur_inner_node->end();
// TODO more efficient with specialized node search method?
for (; child_it != child_it_end; ++child_it) {
partial_key = *child_it;
if (partial_key < key[cur_depth + cur->prefix_len_]) {
if (key[cur_depth + cur_node->prefix_len_] <= child_it.get_partial_key()) {
break;
}
node_stack.push(*static_cast<inner_node<T> *>(cur)->find_child(partial_key));
depth_stack.push(cur_depth + cur->prefix_len_ + 1);
}
traversal_stack.push_back({cur_depth + cur_node->prefix_len_ + 1, child_it, child_it_end});
}
}

template <class T> typename tree_it<T>::value_type tree_it<T>::operator*() {
return static_cast<leaf_node<T> *>(traversal_stack_.top())->value_;
assert(get_node()->is_leaf());
return static_cast<leaf_node<T> *>(get_node())->value_;
}

template <class T> typename tree_it<T>::pointer tree_it<T>::operator->() {
return &static_cast<leaf_node<T> *>(traversal_stack_.top())->value_;
assert(get_node()->is_leaf());
return &static_cast<leaf_node<T> *>(get_node())->value_;
}

template <class T> tree_it<T> &tree_it<T>::operator++() {
inner_node<T> *cur;
std::reverse_iterator<child_it<T>> it, it_end;

traversal_stack_.pop();
while (!traversal_stack_.empty() && !traversal_stack_.top()->is_leaf()) {
cur = static_cast<inner_node<T> *>(traversal_stack_.top());
traversal_stack_.pop();
for (it = cur->rbegin(), it_end = cur->rend(); it != it_end; ++it) {
traversal_stack_.push(*cur->find_child(*it));
}
};
assert(get_node()->is_leaf());
++get_step();
seek_leaf();
return *this;
}

Expand All @@ -155,13 +169,56 @@ template <class T> tree_it<T> tree_it<T>::operator++(int) {
template <class T> bool tree_it<T>::operator==(const tree_it<T> &rhs) const {
return (traversal_stack_.empty() && rhs.traversal_stack_.empty()) ||
(!traversal_stack_.empty() && !rhs.traversal_stack_.empty() &&
traversal_stack_.top() == rhs.traversal_stack_.top());
get_node() == rhs.get_node());
}

template <class T> bool tree_it<T>::operator!=(const tree_it<T> &rhs) const {
return !(*this == rhs);
}

template <class T>
node<T> * tree_it<T>::get_node() const {
return get_step().node_;
}

template <class T>
int tree_it<T>::get_depth() const {
return get_step().depth_;
}

template <class T>
typename tree_it<T>::step &tree_it<T>::get_step() {
assert(!traversal_stack_.empty());
return traversal_stack_.back();
}

template <class T>
const typename tree_it<T>::step &tree_it<T>::get_step() const {
assert(!traversal_stack_.empty());
return traversal_stack_.back();
}

template <class T>
void tree_it<T>::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()) {
return;
}
}

/* find leftmost leaf node */
while (!get_node()->is_leaf()) {
inner_node<T> *cur_inner_node = static_cast<inner_node<T> *>(get_node());
int depth = get_step().depth_ + get_node()->prefix_len_ + 1;
child_it<T> c_it = cur_inner_node->begin();
child_it<T> c_it_end = cur_inner_node->end();
traversal_stack_.push_back({depth, c_it, c_it_end});
}
}

} // namespace art

#endif
Loading

0 comments on commit ee08802

Please sign in to comment.