summaryrefslogtreecommitdiff
path: root/src/server/point.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/point.cpp')
-rw-r--r--src/server/point.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/server/point.cpp b/src/server/point.cpp
new file mode 100644
index 0000000..ab9f70f
--- /dev/null
+++ b/src/server/point.cpp
@@ -0,0 +1,139 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+struct Point {
+ Page *page;
+ uint16_t index;
+
+ uint16_t index_to_offset() {
+ if (index < page->gap_start) {
+ return index;
+ } else {
+ return index + (page->gap_end - page->gap_start);
+ }
+ }
+
+ uint8_t prev_byte() {
+ if (index == 0) {
+ if (page->prev) {
+ return page->prev->elements[Point(page->prev, page->prev->element_count - 1).index_to_offset()];
+ } else {
+ return 0;
+ }
+ } else {
+ return page->elements[Point(page, index - 1).index_to_offset()];
+ }
+ }
+
+ uint8_t next_byte() {
+ if (index == page->element_count) {
+ if (page->next) {
+ return page->next->elements[Point(page->next, 0).index_to_offset()];
+ } else {
+ return 0;
+ }
+ } else {
+ return page->elements[index_to_offset()];
+ }
+ }
+
+ void move_forward() {
+ if (index < page->element_count) {
+ index++;
+ } else if (page->next) {
+ page = page->next;
+ index = 0;
+ }
+ }
+
+ void move_backward() {
+ if (index > 0) {
+ index--;
+ } else if (page->prev) {
+ page = page->prev;
+ index = page->element_count;
+ }
+ }
+
+
+ public:
+
+ Point() : page(0), index(0) {}
+ Point(Page* page, uint16_t index) : page(page), index(index) {}
+ Point(const Buffer &b) : page(b.storage), index(0) {}
+ Point(const Point &p) : page(p.page), index(p.index) {}
+
+ bool operator==(Point p) {
+ return page == p.page && index == p.index;
+ }
+
+ bool operator!=(Point p) {
+ return page != p.page || index != p.index;
+ }
+
+ bool at_start() {
+ return index == 0 && !page->prev;
+ }
+
+ bool at_end() {
+ return index == page->element_count && !page->next;
+ }
+
+ void operator++(int) {
+ if (index == page->element_count) move_forward();
+ move_forward();
+ }
+
+ void operator--(int) {
+ move_backward();
+ if (index == 0) move_backward();
+ }
+
+ char element() {
+ return next_byte();
+ }
+
+ void align_gap() {
+ while (page->gap_end < index_to_offset()) {
+ page->move_gap_forward();
+ }
+ while (page->gap_end > index_to_offset()) {
+ page->move_gap_backward();
+ }
+ }
+
+ void push(uint8_t c) {
+ if (page->is_full()) {
+ page->split();
+ if (index >= PAGE_SIZE / 2) {
+ page = page->next;
+ index -= PAGE_SIZE / 2;
+ }
+ }
+ align_gap();
+ page->push(c);
+ move_forward();
+ }
+
+ void pop() {
+ if (!at_start()) {
+ align_gap();
+ page->pop();
+ move_backward();
+ if (index == 0) {
+ move_backward();
+ }
+ }
+ if (page->is_empty()) {
+ if (page->prev) {
+ move_backward();
+ delete page->next;
+ } else if (page->next) {
+ page->next->copy_to(page);
+ delete page->next;
+ index = 0;
+ }
+ }
+ }
+
+};