diff --git a/include/vase/shard.h b/include/vase/shard.h index 6f9162c..de0fa3f 100644 --- a/include/vase/shard.h +++ b/include/vase/shard.h @@ -17,44 +17,24 @@ struct Shard { std::atomic_uint32_t refs; Shard(ShardKind kind, uint32_t length, uint32_t lines, uint8_t height) - : kind(kind), length(length), lines(lines), height(height), refs(0) {}; + : kind(kind), length(length), lines(lines), height(height), refs(1) {}; virtual ~Shard() = default; -}; -struct ShardPtr { - Shard *ptr; - - ShardPtr(const ShardPtr &other) : ptr(other.ptr) { - if (ptr) - ptr->refs++; + static void retain(Shard *n) { + n->refs++; } - ShardPtr &operator=(const ShardPtr &other) { - if (ptr == other.ptr) - return *this; - if (ptr && --ptr->refs == 0) - delete ptr; - ptr = other.ptr; - if (ptr) - ptr->refs++; - return *this; - } - - ShardPtr(Shard *p = nullptr) : ptr(p) { - if (ptr) - ptr->refs++; - } - - ~ShardPtr() { - if (ptr && --ptr->refs == 0) - delete ptr; + static void release(Shard *n) { + if (!n || --n->refs > 0) + return; + delete n; } }; struct Branch : Shard { - ShardPtr left; - ShardPtr right; + Shard *left; + Shard *right; Branch(Shard *l, Shard *r) : Shard( @@ -63,7 +43,15 @@ struct Branch : Shard { l->lines + r->lines, 1 + std::max(l->height, r->height) ), - left(l), right(r) {}; + left(l), right(r) { + retain(left); + retain(right); + }; + + ~Branch() { + release(left); + release(right); + } }; struct Petal : Shard { @@ -76,10 +64,10 @@ struct Petal : Shard { source(source), pos(pos) {}; }; -std::pair split_shard(Shard *n, uint32_t offset); -ShardPtr concat_shard(ShardPtr left, ShardPtr right); -ShardPtr merge(Shard *a, Shard *b); -ShardPtr merge_leaves(Shard *a, Shard *b); -ShardPtr append_leaf(Shard *root, Shard *leaf); +std::pair split_shard(Shard *n, uint32_t offset); +Shard *concat_shard(Shard *left, Shard *right); +Shard *merge(Shard *a, Shard *b); +Shard *merge_leaves(Shard *a, Shard *b); +Shard *append_leaf(Shard *root, Shard *leaf); void print_shard(const Shard *shard, int depth = 0); diff --git a/include/vase/vase.h b/include/vase/vase.h index efd7f26..23534c0 100644 --- a/include/vase/vase.h +++ b/include/vase/vase.h @@ -9,41 +9,80 @@ struct Vase { OriginalBuffer original; AppendBuffer append; - std::vector undo; + /*std::vector undo; // TODO: later uint8_t top; // of the undo stack. - uint8_t max; // for redo when no edits have been done after some undo. + uint8_t max; // for redo when no edits have been done after some undo.*/ - ShardPtr root; + Shard *root; Vase(char *data, uint32_t length) : original(data, length), append() { root = new Petal(length, original.newlines.size(), &original, 0); } + ~Vase() { + Shard::release(root); + } + uint32_t length() { - return root.ptr->length; + return root->length; } std::string to_string() { std::string out; - flatten(root.ptr, out); + flatten(root, out); return out; } void type(uint32_t offset, char key) { uint32_t pos = append.key(key); - ShardPtr inserted = new Petal(1, key == '\n', &append, pos); - auto [left, right] = split_shard(root.ptr, offset); - left = append_leaf(left.ptr, inserted.ptr); - root = concat_shard(left, right); + Shard *inserted = new Petal(1, key == '\n', &append, pos); + auto [left, right] = split_shard(root, offset); + Shard *left2 = append_leaf(left, inserted); + Shard *new_root = concat_shard(left2, right); + Shard::release(left); + Shard::release(right); + Shard::release(left2); + Shard::release(inserted); + Shard::release(root); + root = new_root; } void insert(uint32_t offset, const char *data, uint32_t len) { uint32_t lines = 0; uint32_t pos = append.append(data, len, &lines); - ShardPtr inserted = new Petal(len, lines, &append, pos); - auto [left, right] = split_shard(root.ptr, offset); - left = append_leaf(left.ptr, inserted.ptr); - root = concat_shard(left, right); + Shard *inserted = new Petal(len, lines, &append, pos); + auto [left, right] = split_shard(root, offset); + Shard *left2 = append_leaf(left, inserted); + Shard *new_root = concat_shard(left2, right); + Shard::release(left); + Shard::release(right); + Shard::release(left2); + Shard::release(inserted); + Shard::release(root); + root = new_root; + } + + void erase(uint32_t cursor, int64_t amount) { + if (amount == 0) + return; + uint32_t start; + uint32_t count; + if (amount < 0) { + count = std::min(-amount, cursor); + start = cursor - count; + } else { + start = cursor; + count = amount; + } + auto [a, b] = split_shard(root, start); + auto [d, c] = split_shard(b, count); + Shard *new_root = concat_shard(a, c); + Shard::release(a); + Shard::release(b); + Shard::release(c); + Shard::release(d); + Shard::release(root); + root = new_root; } void flatten(Shard *s, std::string &out) { @@ -61,8 +100,8 @@ struct Vase { } } else { auto *b = static_cast(s); - flatten(b->left.ptr, out); - flatten(b->right.ptr, out); + flatten(b->left, out); + flatten(b->right, out); } } }; diff --git a/src/main.cc b/src/main.cc index d1a7e98..8b6df51 100644 --- a/src/main.cc +++ b/src/main.cc @@ -12,7 +12,7 @@ int main() { std::cout << vase.to_string() << "\n"; - print_shard(vase.root.ptr); + print_shard(vase.root); std::cout << "\n->\n\n"; @@ -26,7 +26,7 @@ int main() { vase.type(7, 'm'); vase.type(8, 'n'); - print_shard(vase.root.ptr); + print_shard(vase.root); std::cout << "\n" << vase.to_string(); diff --git a/src/vase/shard.cc b/src/vase/shard.cc index c698aa9..4a0e218 100644 --- a/src/vase/shard.cc +++ b/src/vase/shard.cc @@ -6,115 +6,116 @@ int height(Shard *n) { int balance_factor(Shard *n) { Branch *b = (Branch *)n; - return height(b->left.ptr) - height(b->right.ptr); + return height(b->left) - height(b->right); } -ShardPtr rotate_right(Branch *z) { - Branch *y = (Branch *)z->left.ptr; +Shard *rotate_right(Branch *z) { + Branch *y = (Branch *)z->left; - return new Branch( - y->left.ptr, - new Branch(y->right.ptr, z->right.ptr) - ); + Shard *middle = new Branch(y->right, z->right); + Shard *out = new Branch(y->left, middle); + + Shard::release(middle); + Shard::release(z); + + return out; } -ShardPtr rotate_left(Branch *z) { - Branch *y = (Branch *)z->right.ptr; +Shard *rotate_left(Branch *z) { + Branch *y = (Branch *)z->right; - return new Branch( - new Branch(z->left.ptr, y->left.ptr), - y->right.ptr - ); + Shard *middle = new Branch(z->left, y->left); + Shard *out = new Branch(middle, y->right); + + Shard::release(middle); + Shard::release(z); + + return out; } -ShardPtr balance(Shard *node) { +Shard *balance(Shard *node) { if (!node || node->kind == Shard::ShardKind::Petal) - return ShardPtr(node); + return node; Branch *b = (Branch *)node; - int bf = balance_factor(node); - // left heavy if (bf > 1) { - Branch *left = (Branch *)b->left.ptr; - - // Left-right case + Branch *left = (Branch *)b->left; if (balance_factor(left) < 0) { auto new_left = rotate_left(left); - - auto rebuilt = new Branch( - new_left.ptr, - b->right.ptr - ); - - return rotate_right((Branch *)rebuilt); + auto rebuilt = new Branch(new_left, b->right); + auto result = rotate_right((Branch *)rebuilt); + Shard::release(new_left); + return result; } - - // Left-left case return rotate_right(b); } - // right heavy if (bf < -1) { - Branch *right = (Branch *)b->right.ptr; - - // Right-left case + Branch *right = (Branch *)b->right; if (balance_factor(right) > 0) { auto new_right = rotate_right(right); - - auto rebuilt = new Branch( - b->left.ptr, - new_right.ptr - ); - - return rotate_left((Branch *)rebuilt); + auto rebuilt = new Branch(b->left, new_right); + auto result = rotate_left((Branch *)rebuilt); + Shard::release(new_right); + return result; } - - // Right-right case return rotate_left(b); } - return ShardPtr(node); + return node; } -ShardPtr merge(Shard *a, Shard *b) { +Shard *merge(Shard *a, Shard *b) { if (!a) - return ShardPtr(b); + return b ? (Shard::retain(b), b) : nullptr; if (!b) - return ShardPtr(a); + return (Shard::retain(a), a); if (a->height > b->height + 1) { Branch *ba = (Branch *)a; - auto r = merge(ba->right.ptr, b); - return balance(new Branch(ba->left.ptr, r.ptr)); + Shard *r = merge(ba->right, b); + Shard *out = balance(new Branch(ba->left, r)); + Shard::release(r); + return out; } if (b->height > a->height + 1) { Branch *bb = (Branch *)b; - auto l = merge(a, bb->left.ptr); - return balance(new Branch(l.ptr, bb->right.ptr)); + Shard *l = merge(a, bb->left); + Shard *out = balance(new Branch(l, bb->right)); + Shard::release(l); + return out; } return balance(new Branch(a, b)); } -std::pair split_shard(Shard *n, uint32_t offset) { +std::pair split_shard(Shard *n, uint32_t offset) { if (!n) return {nullptr, nullptr}; - if (offset == 0) - return {nullptr, ShardPtr(n)}; - if (offset == n->length) - return {ShardPtr(n), nullptr}; + if (offset == 0) { + Shard::retain(n); + return {nullptr, n}; + } + if (offset == n->length) { + Shard::retain(n); + return {n, nullptr}; + } if (n->kind == Shard::ShardKind::Branch) { Branch *b = (Branch *)n; - if (offset < b->left.ptr->length) { - auto [a, b2] = split_shard(b->left.ptr, offset); - return {a, merge(b2.ptr, b->right.ptr)}; + if (offset < b->left->length) { + auto [a, b2] = split_shard(b->left, offset); + Shard *right = merge(b2, b->right); + Shard::release(b2); + return {a, right}; } else { - auto [a, b2] = split_shard(b->right.ptr, offset - b->left.ptr->length); - return {merge(b->left.ptr, a.ptr), b2}; + auto [a, b2] = split_shard(b->right, offset - b->left->length); + Shard *left = merge(b->left, a); + Shard::release(a); + return {left, b2}; } } else { Petal *p = (Petal *)n; @@ -130,12 +131,11 @@ std::pair split_shard(Shard *n, uint32_t offset) { p->source, p->pos + offset ); - - return {ShardPtr(left), ShardPtr(right)}; + return {left, right}; } } -ShardPtr merge_leaves(Shard *a, Shard *b) { +Shard *merge_leaves(Shard *a, Shard *b) { if (a->kind != Shard::ShardKind::Petal || b->kind != Shard::ShardKind::Petal) return merge(a, b); Petal *pa = (Petal *)a; @@ -150,18 +150,20 @@ ShardPtr merge_leaves(Shard *a, Shard *b) { ); } -ShardPtr append_leaf(Shard *root, Shard *leaf) { +Shard *append_leaf(Shard *root, Shard *leaf) { if (!root) - return ShardPtr(leaf); + return leaf; if (root->kind == Shard::ShardKind::Petal) return merge_leaves(root, leaf); Branch *b = (Branch *)root; - auto new_right = append_leaf(b->right.ptr, leaf); - return balance(new Branch(b->left.ptr, new_right.ptr)); + auto new_right = append_leaf(b->right, leaf); + auto out = balance(new Branch(b->left, new_right)); + Shard::release(new_right); + return out; } -ShardPtr concat_shard(ShardPtr left, ShardPtr right) { - return merge(left.ptr, right.ptr); +Shard *concat_shard(Shard *left, Shard *right) { + return merge(left, right); } void print_shard(const Shard *shard, int depth) { @@ -186,10 +188,10 @@ void print_shard(const Shard *shard, int depth) { << "\n"; std::cout << indent << "├─ left:\n"; - print_shard(branch->left.ptr, depth + 2); + print_shard(branch->left, depth + 2); std::cout << indent << "└─ right:\n"; - print_shard(branch->right.ptr, depth + 2); + print_shard(branch->right, depth + 2); } else { auto *petal = static_cast(shard);