From: Jorge Gorbe Date: Tue, 4 Mar 2014 18:39:12 +0000 (+0100) Subject: Ported cons and nth methods, with all needed helpers. Added simple test. X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=dc313d846daaae222e0a1e2859c0f9833829c662;p=persistent-data-structures.git Ported cons and nth methods, with all needed helpers. Added simple test. --- diff --git a/persistent_vector.h b/persistent_vector.h index 0ac3f45..d792b76 100644 --- a/persistent_vector.h +++ b/persistent_vector.h @@ -2,12 +2,17 @@ #define PERSISTENT_VECTOR_H #include +#include +#include #include +#include #include +#include namespace persistent { class index_out_of_bounds_exception : public std::runtime_error { + public: index_out_of_bounds_exception(): std::runtime_error("Index out of bounds") { } @@ -18,7 +23,7 @@ namespace persistent { private: typedef std::shared_ptr NodePtr; typedef std::vector ElementVector; - typedef std::vector NodeVector; + typedef std::vector NodePtrVector; // U can be either T (for leaf nodes) or NodePtr (for inner nodes) template struct node { @@ -26,45 +31,69 @@ namespace persistent { node() : array() { array.reserve(32); + std::cerr << "Empty node created" << std::endl; + } + + node(const node& other): array(other.array) { std::cerr << "Node copied" << std::endl; } + node(const std::vector &array): array(array) { std::cerr << "Node constructed from array" << std::endl; } + ~node() { + std::cerr << "Node destroyed" << std::endl; } }; + typedef node LeafNode; + typedef node InnerNode; - uint64_t size; + uint64_t sz; uint32_t shift; NodePtr root; ElementVector tail; - static std::shared_ptr EMPTY_NODE; + static NodePtr EMPTY_NODE; public: - persistent_vector(uint64_t size, uint32_t shift, std::shared_ptr root, std::vector> &&tail) - : size(size) + persistent_vector(uint64_t size, uint32_t shift, NodePtr root, const ElementVector &tail) + : sz(size) , shift(shift) , root(root) , tail(tail) { } - persistent_vector() : persistent_vector(0, 5, EMPTY_NODE, std::vector>()) + persistent_vector() : persistent_vector(0, 5, EMPTY_NODE, ElementVector()) + { + } + + persistent_vector(const persistent_vector& other) + : sz(other.sz) + , shift(other.shift) + , root(other.root) + , tail(other.tail) { } + persistent_vector &operator=(persistent_vector other) + { + swap(other); + } + uint64_t tailoff() { - if (size < 32) + if (sz < 32) return 0; - return ((cnt-1) >> 5) << 5; + return ((sz-1) >> 5) << 5; } ElementVector &array_for(uint64_t i) { - if (i < size) { + if (i < sz) { if (i >= tailoff()) return tail; NodePtr node = root; for (uint32_t level = shift; level > 0; level -= 5) { - node = (node) node->array[(i >> level) & 0x1f]; + InnerNode *p = (InnerNode *) node.get(); + node = p->array[(i >> level) & 0x1f]; } - return node->array; + LeafNode *p = (LeafNode *) node.get(); + return p->array; } throw index_out_of_bounds_exception(); } @@ -75,15 +104,119 @@ namespace persistent { } const T& nth(uint64_t i, const T& notFound) { - if (i < size) { + if (i < sz) { return nth(i); } return notFound; } + + persistent_vector assocN(uint64_t i, const T& val) { + if (i < sz) { + if (i >= tailoff()) { + persistent_vector result(sz, shift, root, tail); + result.tail[i & 0x1f] = val; + return result; + } + return persistent_vector(sz, shift, do_assoc(shift, root, i, val), tail); + } + throw index_out_of_bounds_exception(); + } + + int size() { + return sz; + } + + persistent_vector cons(const T& val) { + uint64_t i = sz; + if (sz - tailoff() < 32) { + persistent_vector result(sz+1, shift, root, tail); + result.tail.push_back(val); + return result; + } + // tail full, push into tree + NodePtr new_root; + NodePtr tail_node = std::make_shared(tail); + uint32_t new_shift = shift; + // overflow root? + if ((sz >> 5) > (1 << shift)) { + new_root = std::make_shared(); + InnerNode *p = (InnerNode *) new_root.get(); + p->array.push_back(root); + p->array.push_back(new_path(shift, tail_node)); + new_shift += 5; + } else { + new_root = push_tail(shift, root, tail_node); + } + + return persistent_vector(sz + 1, new_shift, new_root, {val}); // old tail full, new tail contains only val + } + + + private: + static NodePtr do_assoc(uint32_t shift, NodePtr pNode, uint64_t i, const T& val) { + NodePtr ret; + if (shift == 0) { // leaf node + const LeafNode &node = *((LeafNode*) pNode.get()); + ret = std::make_shared(node); + ((LeafNode*)ret.get())->array[i & 0x1f] = val; + } else { // inner node + const InnerNode &node = *((InnerNode*) pNode.get()); + ret = std::make_shared(node); + uint64_t subidx = (i >> shift) & 0x1f; + ((InnerNode*)ret.get())->array[subidx] = do_assoc(shift-5, node.array[subidx], i, val); + } + return ret; + } + + NodePtr push_tail(uint32_t level, NodePtr parent, NodePtr tail_node) { + uint64_t subidx = ((sz - 1) >> level) & 0x1f; + NodePtr node_to_insert; + + const InnerNode &parentRef = *((InnerNode*) parent.get()); + NodePtr ret = std::make_shared(parentRef); + NodePtrVector &array = ((InnerNode*) ret.get())->array; + if (level == 5) { + node_to_insert = tail_node; + } else { + if (subidx < parentRef.array.size()) { + NodePtr child = parentRef.array[subidx]; + node_to_insert = push_tail(level-5, child, tail_node); + } else { + node_to_insert = new_path(level-5, tail_node); + } + } + + if (subidx < array.size()) { + array[subidx] = node_to_insert; + } else { + assert(subidx == array.size()); + array.push_back(node_to_insert); + } + + return ret; + } + + static NodePtr new_path(uint32_t level, NodePtr node) { + if (level == 0) + return node; + NodePtr ret = std::make_shared(); + ((InnerNode*) ret.get())->array.push_back(new_path(level-5, node)); + return ret; + } + + + void swap(persistent_vector &other) { + using std::swap; + swap(sz, other.sz); + swap(shift, other.shift); + swap(root, other.root); + swap(tail, other.tail); + } + }; - template std::shared_ptr persistent_vector::EMPTY_NODE = std::make_shared>(); + template std::shared_ptr persistent_vector::EMPTY_NODE = std::make_shared(); } diff --git a/test_vector.cc b/test_vector.cc new file mode 100644 index 0000000..f9a1f7b --- /dev/null +++ b/test_vector.cc @@ -0,0 +1,24 @@ +#include "persistent_vector.h" + +#include + +using persistent::persistent_vector; + +int main() { + persistent_vector v; + + auto v1 = v.cons(1); + auto v12 = v1.cons(2); + auto v13 = v1.cons(3); + auto v123 = v12.cons(3); + + std::cout << v123.nth(2) << std::endl; + + for (int i=0; i < 2000; ++i) { + auto v2 = v.cons(i); + v = v2; + } + + std::cout << v.nth(1500) << std::endl; + +}