| Index: CompactTrie.cpp |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/CompactTrie.cpp |
| @@ -0,0 +1,144 @@ |
| +#include <emscripten/bind.h> |
| + |
| +using namespace emscripten; |
| + |
| +class CompactTrieNode { |
| + public: |
| + ~CompactTrieNode() { |
| + CompactTrieNode* child = last_child; |
| + |
| + while (child) { |
| + CompactTrieNode* sibling = child->previous_sibling; |
| + delete child; |
| + child = sibling; |
| + } |
| + } |
| + |
| + std::string bytes() const { |
| + std::string str; |
| + const CompactTrieNode* node = this; |
| + |
| + do { |
| + str = node->key + str; |
| + node = node->parent; |
| + } while (node); |
| + |
| + return str; |
| + } |
| + |
| + private: |
| + std::string key; |
| + int value = 0; |
| + |
| + CompactTrieNode* parent = nullptr; |
| + CompactTrieNode* last_child = nullptr; |
| + CompactTrieNode* previous_sibling = nullptr; |
| + |
| + friend class CompactTrie; |
| +}; |
| + |
| +class CompactTrie { |
| + public: |
| + CompactTrie() {} |
| + |
| + CompactTrieNode* set(const std::string& key, int value) { |
| + std::string key_ = key; |
| + CompactTrieNode* node = &this->root; |
| + |
| + while (!key_.empty()) { |
| + CompactTrieNode* child = node->last_child; |
| + |
| + while (child && child->key[0] != key_[0]) |
| + child = child->previous_sibling; |
| + |
| + if (child) { |
| + size_t n = std::max(child->key.length(), key_.length()); |
|
Manish Jethani
2018/05/30 11:49:27
This should be std::min
|
| + size_t i = 0; |
|
Manish Jethani
2018/05/30 14:47:13
This could start at 1 instead of 0.
|
| + |
| + for (; i < n && child->key[i] == key_[i]; i++); |
| + |
| + if (i < child->key.length()) { |
| + CompactTrieNode* grandchild = new CompactTrieNode(); |
|
Manish Jethani
2018/05/30 14:47:13
Here we're basically splitting a child node into c
|
| + grandchild->key = child->key.substr(i); |
| + grandchild->last_child = child->last_child; |
| + grandchild->parent = child; |
| + |
| + CompactTrieNode* great_grandchild = grandchild->last_child; |
| + |
| + while (great_grandchild) { |
| + great_grandchild->parent = grandchild; |
| + great_grandchild = great_grandchild->previous_sibling; |
| + } |
| + |
| + child->key = child->key.substr(0, i); |
| + child->last_child = grandchild; |
| + } |
| + |
| + key_ = key_.substr(i); |
| + |
| + } else { |
| + child = new CompactTrieNode(); |
| + child->key = key_; |
| + child->previous_sibling = node->last_child; |
| + child->parent = node; |
| + |
| + node->last_child = child; |
| + |
| + key_.clear(); |
| + } |
| + |
| + node = child; |
| + } |
| + |
| + node->value = value; |
| + return node; |
| + } |
| + |
| + int get(const std::string& key) const { |
| + std::string key_ = key; |
| + const CompactTrieNode* node = &this->root; |
| + |
| + while (!key_.empty()) { |
| + CompactTrieNode* child = node->last_child; |
| + |
| + while (child && child->key[0] != key_[0]) |
| + child = child->previous_sibling; |
| + |
| + if (child) { |
| + size_t n = std::max(child->key.length(), key_.length()); |
|
Manish Jethani
2018/05/30 11:49:27
This should be std::min
|
| + size_t i = 0; |
|
Manish Jethani
2018/05/30 14:47:13
This could start at 1 instead of 0.
|
| + |
| + for (; i < n && child->key[i] == key_[i]; i++); |
| + |
| + if (i < child->key.length()) |
| + return 0; |
| + |
| + key_ = key_.substr(i); |
| + |
| + } else { |
| + return 0; |
| + } |
| + |
| + node = child; |
| + } |
| + |
| + return node->value; |
| + } |
| + |
| + private: |
| + CompactTrieNode root; |
| +}; |
| + |
| +EMSCRIPTEN_BINDINGS(CompactTrieNode) { |
| + class_<CompactTrieNode>("CompactTrieNode") |
| + .function("bytes", &CompactTrieNode::bytes) |
| + ; |
| +} |
| + |
| +EMSCRIPTEN_BINDINGS(CompactTrie) { |
| + class_<CompactTrie>("CompactTrie") |
| + .constructor() |
| + .function("set", &CompactTrie::set, allow_raw_pointers()) |
| + .function("get", &CompactTrie::get) |
| + ; |
| +} |