IMPLEMENT TREAP PERSISTENCE
This commit is contained in:
parent
9fd135e540
commit
495bf542cf
5 changed files with 347 additions and 103 deletions
23
editor.cpp
23
editor.cpp
|
@ -65,9 +65,6 @@ count_type Editor::get_number(string prompt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO undo
|
|
||||||
|
|
||||||
|
|
||||||
// Jump to end of line
|
// Jump to end of line
|
||||||
void Editor::jump_line_end() {
|
void Editor::jump_line_end() {
|
||||||
count_type line_size = file.get_line(file_offset+cur.r).size();
|
count_type line_size = file.get_line(file_offset+cur.r).size();
|
||||||
|
@ -150,6 +147,12 @@ find_result Editor::find(string text) {
|
||||||
}
|
}
|
||||||
return {false, position()};
|
return {false, position()};
|
||||||
}
|
}
|
||||||
|
void Editor::replace(position p, count_type length, string text) {
|
||||||
|
string line_text = file.get_line(p.r);
|
||||||
|
line_text.erase(p.c, length);
|
||||||
|
line_text.insert(p.c, text);
|
||||||
|
file.update(p.r, line_text);
|
||||||
|
}
|
||||||
|
|
||||||
bool Editor::take_action() {
|
bool Editor::take_action() {
|
||||||
move(cur);
|
move(cur);
|
||||||
|
@ -190,6 +193,12 @@ bool Editor::take_action() {
|
||||||
case 'w':
|
case 'w':
|
||||||
save();
|
save();
|
||||||
break;
|
break;
|
||||||
|
case 'u':
|
||||||
|
if(file.version() > 0) {
|
||||||
|
jump({file.undo(), 0});
|
||||||
|
print_file(file_offset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
mode = INSERT;
|
mode = INSERT;
|
||||||
current_insert = file.get_line(file_offset + cur.r, false);
|
current_insert = file.get_line(file_offset + cur.r, false);
|
||||||
|
@ -223,7 +232,7 @@ bool Editor::take_action() {
|
||||||
print_file(file_offset);
|
print_file(file_offset);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
selection.paste_selection(cur + file_offset);
|
file.compress_versions(selection.paste_selection(cur + file_offset));
|
||||||
print_file(file_offset);
|
print_file(file_offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -235,7 +244,7 @@ bool Editor::take_action() {
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case ESC:
|
case ESC:
|
||||||
mode = NORMAL;
|
mode = NORMAL;
|
||||||
file.set_line(cur.r, current_insert);
|
file.update(cur.r, current_insert);
|
||||||
print_text(cur.r, substitute_tabs(current_insert));
|
print_text(cur.r, substitute_tabs(current_insert));
|
||||||
current_insert = "";
|
current_insert = "";
|
||||||
break;
|
break;
|
||||||
|
@ -251,7 +260,7 @@ bool Editor::take_action() {
|
||||||
print_text(cur.r, substitute_tabs(current_insert));
|
print_text(cur.r, substitute_tabs(current_insert));
|
||||||
break;
|
break;
|
||||||
case ENTER:
|
case ENTER:
|
||||||
file.set_line(cur.r, current_insert);
|
file.update(cur.r, current_insert);
|
||||||
file.split_line(cur + file_offset);
|
file.split_line(cur + file_offset);
|
||||||
cur.r++; cur.c = 0; move(cur);
|
cur.r++; cur.c = 0; move(cur);
|
||||||
current_insert = file.get_line(cur.r);
|
current_insert = file.get_line(cur.r);
|
||||||
|
@ -288,7 +297,7 @@ bool Editor::take_action() {
|
||||||
mode = NORMAL;
|
mode = NORMAL;
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
selection.remove_selection(cur + file_offset);
|
file.compress_versions(selection.remove_selection(cur + file_offset)+1);
|
||||||
if(file_offset + cur.r >= file.size())
|
if(file_offset + cur.r >= file.size())
|
||||||
jump(cur + file_offset);
|
jump(cur + file_offset);
|
||||||
print_file(file_offset);
|
print_file(file_offset);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ constexpr int RANDOM_SEED = 666;
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
using std::stack;
|
||||||
typedef unsigned long long count_type;
|
typedef unsigned long long count_type;
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
|
@ -29,43 +31,76 @@ struct line {
|
||||||
count_type priority, size; // Treap innards
|
count_type priority, size; // Treap innards
|
||||||
string text; // Content
|
string text; // Content
|
||||||
line *left, *right; // Sons
|
line *left, *right; // Sons
|
||||||
|
line *next_in_version;
|
||||||
|
|
||||||
|
void set_left(line *_left) {
|
||||||
|
left = _left;
|
||||||
|
update_size();
|
||||||
|
}
|
||||||
|
void set_right(line *_right) {
|
||||||
|
right = _right;
|
||||||
|
update_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_size() { size = 1 + (left == nullptr ? 0 : left->size) + (right == nullptr ? 0 : right->size); }
|
||||||
|
|
||||||
line(count_type _p, string _t) :
|
line(count_type _p, string _t) :
|
||||||
priority(_p), text(_t), size(1), left(nullptr), right(nullptr) {}
|
priority(_p), text(_t), size(1), left(nullptr), right(nullptr), next_in_version(nullptr) {}
|
||||||
|
|
||||||
|
line(count_type _p, string _t, line *_left, line *_right, line *_next) :
|
||||||
|
priority(_p), text(_t), left(_left), right(_right), next_in_version(_next) {
|
||||||
|
update_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
line(line *l) :
|
||||||
|
priority(l->priority), text(l->text), left(l->left), right(l->right), next_in_version(nullptr) {
|
||||||
|
update_size();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
struct change { count_type row, count; };
|
struct change { count_type row, count; };
|
||||||
|
|
||||||
// Treap data structure
|
// Treap data structure
|
||||||
class Treap {
|
class Treap {
|
||||||
line *root;
|
stack<change> changes;
|
||||||
|
stack<line*> root;
|
||||||
|
line* get_root() { return root.top(); };
|
||||||
|
|
||||||
two_lines split(line *l, count_type k);
|
line* insert(line *l, count_type k, string s, bool new_version);
|
||||||
line* join(line *a, line *b);
|
line* remove(line *l, count_type k);
|
||||||
line* join(two_lines two) { return join(two.first, two.second); }
|
line* update(line *l, count_type k, string s, bool new_version);
|
||||||
|
|
||||||
|
line* pick_higher(line *l);
|
||||||
|
void delete_version(line *l);
|
||||||
count_type get_size(line *l);
|
count_type get_size(line *l);
|
||||||
|
count_type get_priority(line *l);
|
||||||
line* find(line *l, count_type k);
|
line* find(line *l, count_type k);
|
||||||
line* find(count_type k);
|
|
||||||
count_type bulk_find(vector<string> *vec, line *l, count_type k, count_type count);
|
count_type bulk_find(vector<string> *vec, line *l, count_type k, count_type count);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// General operations
|
// General operations
|
||||||
Treap() { srand(120); root = nullptr; }
|
Treap() { srand(RANDOM_SEED); root.push(nullptr); }
|
||||||
count_type size() { return get_size(root); }
|
void construct(vector<string> &line);
|
||||||
|
count_type size() { return get_size(get_root()); }
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// Line get operations
|
// Versioning
|
||||||
string get_line(count_type r, bool substitute_tab = 1);
|
count_type undo();
|
||||||
|
count_type version() { return root.size()-1; }
|
||||||
|
void compress_versions(count_type count);
|
||||||
|
|
||||||
|
// Line getters
|
||||||
|
string get_line(count_type r, bool substitute_tab = true);
|
||||||
vector<string> bulk_get_line(count_type r, count_type count);
|
vector<string> bulk_get_line(count_type r, count_type count);
|
||||||
count_type get_tab_offset(position p) { return ::get_tab_offset(p.c, get_line(p.r, 0)); }
|
count_type get_tab_offset(position p) { return ::get_tab_offset(p.c, get_line(p.r, 0)); }
|
||||||
|
|
||||||
// Line set operations
|
// Line meta-operations
|
||||||
void split_line(position p);
|
void insert(count_type k, string s, bool new_version = true);
|
||||||
void insert(count_type k, string s);
|
|
||||||
void remove(count_type k);
|
void remove(count_type k);
|
||||||
void set_line(count_type k, string s) { find(k)->text = s; }
|
void update(count_type k, string s, bool new_version = true);
|
||||||
|
|
||||||
// Substring operations
|
// Other line operations
|
||||||
|
void split_line(position p, bool should_compress = true);
|
||||||
|
void merge_line(count_type k, bool should_compress = true);
|
||||||
void insert(position p, string t);
|
void insert(position p, string t);
|
||||||
void remove(position p, count_type len = 1);
|
void remove(position p, count_type len = 1);
|
||||||
};
|
};
|
||||||
|
@ -85,7 +120,8 @@ public:
|
||||||
count_type size() { return file->size(); }
|
count_type size() { return file->size(); }
|
||||||
|
|
||||||
void copy_selection(position p);
|
void copy_selection(position p);
|
||||||
void paste_selection(position p);
|
count_type remove_selection(position p);
|
||||||
|
count_type paste_selection(position p);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
8
main.cpp
8
main.cpp
|
@ -48,10 +48,14 @@ int main(int argc, const char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load file
|
// Load file
|
||||||
Treap file;
|
|
||||||
string line;
|
string line;
|
||||||
|
vector<string> lines;
|
||||||
while (std::getline(infile, line))
|
while (std::getline(infile, line))
|
||||||
file.insert(file.size(), line);
|
lines.push_back(line);
|
||||||
|
|
||||||
|
// Create a treap from file
|
||||||
|
Treap file;
|
||||||
|
file.construct(lines);
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
initscr();
|
initscr();
|
||||||
|
|
|
@ -24,13 +24,6 @@ void Selection::apply_on_selection(position p, F func, G func2) {
|
||||||
count_type size = ((start.r == end.r) ? end.c+1 : start_line.size()) - start.c;
|
count_type size = ((start.r == end.r) ? end.c+1 : start_line.size()) - start.c;
|
||||||
func2(start.r, start.c, size, file, &content);
|
func2(start.r, start.c, size, file, &content);
|
||||||
}
|
}
|
||||||
// Removing selection
|
|
||||||
void Selection::remove_selection(position p) {
|
|
||||||
apply_on_selection(p,
|
|
||||||
[](count_type r, Treap *file, Treap *sel){ file->remove(r); },
|
|
||||||
[](count_type r, count_type start_c, count_type size, Treap *file, Treap *sel) { file->remove({r, start_c-file->get_tab_offset({r, start_c})}, size); }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Copying selection
|
// Copying selection
|
||||||
void Selection::copy_selection(position p) {
|
void Selection::copy_selection(position p) {
|
||||||
apply_on_selection(p,
|
apply_on_selection(p,
|
||||||
|
@ -38,20 +31,40 @@ void Selection::copy_selection(position p) {
|
||||||
[](count_type r, count_type start_c, count_type size, Treap *file, Treap *sel) { sel->insert(0, file->get_line(r, false).substr(start_c - file->get_tab_offset({r, start_c}), size)); }
|
[](count_type r, count_type start_c, count_type size, Treap *file, Treap *sel) { sel->insert(0, file->get_line(r, false).substr(start_c - file->get_tab_offset({r, start_c}), size)); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Removing selection
|
||||||
|
count_type Selection::remove_selection(position p) {
|
||||||
|
apply_on_selection(p,
|
||||||
|
[](count_type r, Treap *file, Treap *sel){ file->remove(r); },
|
||||||
|
[](count_type r, count_type start_c, count_type size, Treap *file, Treap *sel) { file->remove({r, start_c-file->get_tab_offset({r, start_c})}, size); }
|
||||||
|
);
|
||||||
|
|
||||||
|
count_type min = p.r, max = pos.r;
|
||||||
|
if(min > max)
|
||||||
|
min = pos.r, max = p.r;
|
||||||
|
|
||||||
|
if(max > min) {
|
||||||
|
file->merge_line(min+1, false);
|
||||||
|
return max - min + 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
// Pasting selection
|
// Pasting selection
|
||||||
void Selection::paste_selection(position p) {
|
count_type Selection::paste_selection(position p) {
|
||||||
if(content.size() == 0) return;
|
if(content.size() == 0) return 0;
|
||||||
|
|
||||||
// Insert last line inside of this
|
// Insert last line inside of this
|
||||||
file->insert(p, content.get_line(content.size()-1, false));
|
file->insert(p, content.get_line(content.size()-1, false));
|
||||||
if(content.size() == 1) return;
|
if(content.size() == 1) return 1;
|
||||||
|
|
||||||
// Insert first line in front and split
|
// Insert first line in front and split
|
||||||
file->split_line(p);
|
file->split_line(p, false);
|
||||||
file->insert(p, content.get_line(0, false));
|
file->insert(p, content.get_line(0, false));
|
||||||
if(content.size() == 2) return;
|
if(content.size() == 2) return 4;
|
||||||
|
|
||||||
// Insert lines
|
// Insert lines
|
||||||
for(count_type i = content.size()-2; i > 0; --i)
|
for(count_type i = content.size()-2; i > 0; --i)
|
||||||
file->insert(p.r, content.get_line(i, false));
|
file->insert(p.r+1, content.get_line(i, false));
|
||||||
|
|
||||||
|
return content.size()+2;
|
||||||
}
|
}
|
||||||
|
|
306
treap.cpp
306
treap.cpp
|
@ -2,99 +2,258 @@
|
||||||
|
|
||||||
// Get size uf a subtreap
|
// Get size uf a subtreap
|
||||||
count_type Treap::get_size(line *l) {
|
count_type Treap::get_size(line *l) {
|
||||||
if(l == nullptr) return 0;
|
if(l == nullptr)
|
||||||
|
return 0;
|
||||||
return l->size;
|
return l->size;
|
||||||
}
|
}
|
||||||
|
count_type Treap::get_priority(line *l) {
|
||||||
|
if(l == nullptr)
|
||||||
|
return 0;
|
||||||
|
return l->priority;
|
||||||
|
}
|
||||||
|
|
||||||
// Split treap by k-th element
|
// Treap node rotations
|
||||||
two_lines Treap::split(line *l, count_type k) {
|
line *rotate_left(line *l) {
|
||||||
if(l == nullptr) return {nullptr, nullptr};
|
line *r = l->right, *mid = r->left;
|
||||||
|
|
||||||
if(get_size(l->left) >= k) {
|
// Switch
|
||||||
// In the left subtree
|
l->set_right(mid);
|
||||||
auto two = split(l->left, k);
|
r->set_left(l);
|
||||||
l->left = two.second;
|
|
||||||
l->size -= get_size(two.first);
|
return r;
|
||||||
return {two.first, l};
|
}
|
||||||
|
line *rotate_right(line *r) {
|
||||||
|
line *l = r->left, *mid = l->right;
|
||||||
|
|
||||||
|
// Switch
|
||||||
|
r->set_left(mid);
|
||||||
|
l->set_right(r);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meta-operations
|
||||||
|
line* Treap::insert(line *l, count_type k, string s, bool new_version) {
|
||||||
|
if(l == nullptr)
|
||||||
|
return new line(rand(), s);
|
||||||
|
|
||||||
|
// Insert into left subtree
|
||||||
|
if(k <= get_size(l->left)) {
|
||||||
|
line *son = insert(l->left, k, s, new_version);
|
||||||
|
|
||||||
|
if(new_version)
|
||||||
|
l = new line(l->priority, l->text, son, l->right, son);
|
||||||
|
else
|
||||||
|
l->set_left(son);
|
||||||
|
|
||||||
|
if(get_priority(l->left) > get_priority(l))
|
||||||
|
l = rotate_right(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert into right subtree
|
||||||
|
else {
|
||||||
|
line *son = insert(l->right, k - (get_size(l->left)+1), s, new_version);
|
||||||
|
|
||||||
|
if(new_version)
|
||||||
|
l = new line(l->priority, l->text, l->left, son, son);
|
||||||
|
else
|
||||||
|
l->set_right(son);
|
||||||
|
|
||||||
|
if(get_priority(l->right) > get_priority(l))
|
||||||
|
l = rotate_left(l);
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
line* Treap::remove(line *l, count_type k) {
|
||||||
|
line *lson = l->left, *rson = l->right;
|
||||||
|
|
||||||
|
// Remove from left subtree
|
||||||
|
if(k < get_size(lson)) {
|
||||||
|
line *son = remove(lson, k);
|
||||||
|
return new line(l->priority, l->text, son, rson, son);
|
||||||
|
}
|
||||||
|
// Remove this line
|
||||||
|
else if(k == get_size(l->left)) {
|
||||||
|
// Picking the son we can
|
||||||
|
if(lson == nullptr && rson == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
else if(lson == nullptr)
|
||||||
|
return new line(l->priority, rson->text, rson->left, rson->right, nullptr);
|
||||||
|
else if(rson == nullptr)
|
||||||
|
return new line(l->priority, lson->text, lson->left, lson->right, nullptr);
|
||||||
|
|
||||||
|
// Picking the son with higher priority
|
||||||
|
else if(get_priority(lson) >= get_priority(rson)) {
|
||||||
|
line *son = new line(lson);
|
||||||
|
line l_copy = line(l->priority, l->text, son, l->right, nullptr);
|
||||||
|
|
||||||
|
rotate_right(&l_copy);
|
||||||
|
son->right = remove(&l_copy, get_size(l_copy.left));
|
||||||
|
son->next_in_version = son->right;
|
||||||
|
son->update_size();
|
||||||
|
|
||||||
|
return son;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// In the right subtree
|
line *son = new line(rson);
|
||||||
auto two = split(l->right, k - (1+get_size(l->left)));
|
line l_copy = line(l->priority, l->text, l->left, son, nullptr);
|
||||||
l->right = two.first;
|
|
||||||
l->size -= get_size(two.second);
|
rotate_left(&l_copy);
|
||||||
return {l, two.second};
|
son->left = remove(&l_copy, get_size(l_copy.left));
|
||||||
|
son->next_in_version = son->left;
|
||||||
|
son->update_size();
|
||||||
|
|
||||||
|
return son;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove from right subtree
|
||||||
// Join two treaps
|
else {
|
||||||
line* Treap::join(line *a, line *b) {
|
line *son = remove(rson, k - (get_size(lson)+1) );
|
||||||
if(a == nullptr) return b;
|
return new line(l->priority, l->text, lson, son, son);
|
||||||
if(b == nullptr) return a;
|
}
|
||||||
|
}
|
||||||
if(a->priority < b->priority) {
|
line* Treap::update(line *l, count_type k, string s, bool new_version) {
|
||||||
a->size += get_size(b);
|
if(new_version) {
|
||||||
a->right = join(a->right, b);
|
if(k < get_size(l->left)) {
|
||||||
return a;
|
line *son = update(l->left, k, s, new_version);
|
||||||
|
return new line(l->priority, l->text, son, l->right, son);
|
||||||
|
}
|
||||||
|
else if(k == get_size(l->left))
|
||||||
|
return new line(l->priority, s, l->left, l->right, nullptr);
|
||||||
|
else {
|
||||||
|
line *son = update(l->right, k - (1+get_size(l->left)), s, new_version);
|
||||||
|
return new line(l->priority, l->text, l->left, son, son);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b->size += get_size(a);
|
if(k < get_size(l->left))
|
||||||
b->left = join(a, b->left);
|
update(l->left, k, s, new_version);
|
||||||
return b;
|
else if(k == get_size(l->left))
|
||||||
|
l->text = s;
|
||||||
|
else
|
||||||
|
update(l->right, k - (1+get_size(l->left)), s, new_version);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find k-th line of file
|
// Find k-th line of file
|
||||||
line* Treap::find(line *l, count_type k) {
|
line* Treap::find(line *l, count_type k) {
|
||||||
if(l == nullptr) return nullptr;
|
if(l == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
if(k <= get_size(l->left))
|
if(k < get_size(l->left))
|
||||||
return find(l->left, k);
|
return find(l->left, k);
|
||||||
else if(k == get_size(l->left)+1)
|
else if(k == get_size(l->left))
|
||||||
return l;
|
return l;
|
||||||
else
|
else
|
||||||
return find(l->right, k - (1+get_size(l->left)) );
|
return find(l->right, k - (1+get_size(l->left)) );
|
||||||
}
|
}
|
||||||
line* Treap::find(count_type k) {
|
|
||||||
if(k >= root->size)
|
void Treap::construct(vector<string> &line) {
|
||||||
return nullptr;
|
for(string text : line)
|
||||||
// Don't find index k, but k-th line -> +1
|
insert(size(), text, false);
|
||||||
return find(root, k+1);
|
}
|
||||||
|
|
||||||
|
// Undo
|
||||||
|
void Treap::delete_version(line *l) {
|
||||||
|
if(l == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
line *next = l->next_in_version;
|
||||||
|
delete l;
|
||||||
|
delete_version(next);
|
||||||
|
}
|
||||||
|
count_type Treap::undo() {
|
||||||
|
if(changes.size() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get number of changes
|
||||||
|
change last = changes.top();
|
||||||
|
changes.pop();
|
||||||
|
|
||||||
|
// Delete all treap versions within the change
|
||||||
|
for(count_type i = 0; i < last.count; i++) {
|
||||||
|
line *last_root = root.top();
|
||||||
|
root.pop();
|
||||||
|
delete_version(last_root);
|
||||||
|
}
|
||||||
|
return last.row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Treap::compress_versions(count_type count) {
|
||||||
|
for(count_type i = 1; i < count; ++i)
|
||||||
|
changes.pop();
|
||||||
|
if(count > 0)
|
||||||
|
changes.top().count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// File access
|
// File access
|
||||||
void Treap::clear() {
|
void Treap::clear() {
|
||||||
while(size() > 0) {
|
// Clear all versions
|
||||||
auto two = split(root, 1);
|
while(root.size() > 1)
|
||||||
root = two.second;
|
undo();
|
||||||
delete two.first;
|
// Clear original file
|
||||||
}
|
while(size() > 0)
|
||||||
|
remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line insert
|
// Line insert
|
||||||
void Treap::insert(count_type k, string s) {
|
void Treap::insert(count_type k, string s, bool new_version) {
|
||||||
line *l = new line(rand(), s);
|
if(k > size()) {
|
||||||
|
std::cerr << "Inserting out of file range\n";
|
||||||
if(root == nullptr) {
|
|
||||||
root = l;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto two = split(root, k);
|
line* new_root = insert(get_root(), k, s, new_version);
|
||||||
two.first = join(two.first, l);
|
|
||||||
root = join(two);
|
if(new_version) {
|
||||||
|
root.push(new_root);
|
||||||
|
changes.push({k, 1});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
root.top() = new_root;
|
||||||
}
|
}
|
||||||
// Line removal
|
// Line removal
|
||||||
void Treap::remove(count_type k) {
|
void Treap::remove(count_type k) {
|
||||||
auto two = split(root, k+1);
|
if(k >= size()) {
|
||||||
auto first_split = split(two.first, k);
|
std::cerr << "Removing out of file range\n";
|
||||||
delete first_split.second;
|
return;
|
||||||
two.first = first_split.first;
|
}
|
||||||
root = join(two);
|
|
||||||
|
if(size() == 1)
|
||||||
|
update(0, "");
|
||||||
|
else {
|
||||||
|
root.push(remove(get_root(), k));
|
||||||
|
changes.push({k, 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line text update
|
||||||
|
void Treap::update(count_type k, string s, bool new_version) {
|
||||||
|
if(k >= size()) {
|
||||||
|
std::cerr << "Updating out of file range\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s == find(get_root(), k)->text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
line *new_root = update(get_root(), k, s, new_version);
|
||||||
|
|
||||||
|
if(new_version) {
|
||||||
|
root.push(new_root);
|
||||||
|
changes.push({k, 1});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessing the file
|
// Accessing the file
|
||||||
string Treap::get_line(count_type r, bool substitute_tab) {
|
string Treap::get_line(count_type r, bool substitute_tab) {
|
||||||
string line = find(r)->text;
|
line *l = find(get_root(), r);
|
||||||
|
if(l == nullptr) {
|
||||||
|
std::cerr << r << " not found.\n";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
string line = l->text;
|
||||||
if(substitute_tab)
|
if(substitute_tab)
|
||||||
return substitute_tabs(line);
|
return substitute_tabs(line);
|
||||||
else
|
else
|
||||||
|
@ -129,20 +288,43 @@ count_type Treap::bulk_find(vector<string> *vec, line *l, count_type k, count_ty
|
||||||
// Access multiple adjacent vertices
|
// Access multiple adjacent vertices
|
||||||
vector<string> Treap::bulk_get_line(count_type r, count_type count) {
|
vector<string> Treap::bulk_get_line(count_type r, count_type count) {
|
||||||
vector<string> ret(0);
|
vector<string> ret(0);
|
||||||
bulk_find(&ret, root, r+1, count);
|
bulk_find(&ret, get_root(), r+1, count);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Treap::insert(position p, string t) {
|
void Treap::insert(position p, string t) {
|
||||||
find(p.r)->text.insert(p.c-get_tab_offset(p), t);
|
string text = get_line(p.r, false);
|
||||||
|
text.insert(p.c-get_tab_offset(p), t);
|
||||||
|
if(text != get_line(p.r, false))
|
||||||
|
update(p.r, text);
|
||||||
}
|
}
|
||||||
void Treap::remove(position p, count_type len) {
|
void Treap::remove(position p, count_type len) {
|
||||||
find(p.r)->text.erase(p.c-get_tab_offset(p),len);
|
string text = get_line(p.r, false);
|
||||||
|
text.erase(p.c-get_tab_offset(p),len);
|
||||||
|
if(text != get_line(p.r, false))
|
||||||
|
update(p.r, text);
|
||||||
}
|
}
|
||||||
// Split line
|
// Split line
|
||||||
void Treap::split_line(position p) {
|
void Treap::split_line(position p, bool should_compress) {
|
||||||
string line = get_line(p.r);
|
string line = get_line(p.r, false);
|
||||||
string newline = line.substr(p.c, line.size());
|
count_type place = p.c - get_tab_offset(p);
|
||||||
remove(p, line.size()-p.c);
|
string newline = line.substr(place, line.size());
|
||||||
|
|
||||||
|
if(line.size()-place > 0)
|
||||||
|
remove(p, line.size()-place);
|
||||||
insert(p.r+1, newline);
|
insert(p.r+1, newline);
|
||||||
|
|
||||||
|
if(should_compress)
|
||||||
|
compress_versions(2);
|
||||||
|
}
|
||||||
|
void Treap::merge_line(count_type k, bool should_compress) {
|
||||||
|
if(k == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string text = get_line(k, false);
|
||||||
|
remove(k);
|
||||||
|
update(k-1, get_line(k-1, false) + text);
|
||||||
|
|
||||||
|
if(should_compress)
|
||||||
|
compress_versions(2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue