A buggy_dots/e210.dot => buggy_dots/e210.dot +36 -0
@@ 0,0 1,36 @@
+digraph vine {
+ graph [ordering="out"];
+ ratio = fill;
+ node [style="filled"];
+ "0x7ffff7fbe210" [label="e210:,",color="crimson"];
+ "0x7ffff7fbe210" -> "0x7ffff7fbe240" [label="24"];
+ "0x7ffff7fbe240" [label="0:e240: There is nothing better:0",color="cornflowerblue"];
+ "0x7ffff7fbe240" -> "0x7ffff7fbe210" [style="dotted"];
+ "0x7ffff7fbe210" -> "0x7ffff7fbe270" [label="204"];
+ "0x7ffff7fbe270" [label="0:e270: than a nice new long string.
+Of course some of these strings can be quite complicated.
+",color="cornflowerblue"];
+ "0x7ffff7fbe270" -> "0x7ffff7fbe1b0" [label="116"];
+ "0x7ffff7fbe1b0" [label="e1b0:reak ",color="cornflowerblue"];
+ "0x7ffff7fbe1b0" -> "0x7ffff7fbe180" [label="18"];
+ "0x7ffff7fbe180" [label="0:e180:It's important to ",color="cornflowerblue"];
+ "0x7ffff7fbe180" -> "0x7ffff7fbe150" [label="1"];
+ "0x7ffff7fbe150" [label="0:e150:b:0",color="cornflowerblue"];
+ "0x7ffff7fbe150" -> "0x7ffff7fbe180" [style="dotted"];
+ "0x7ffff7fbe180" -> "0x7ffff7fbe1b0" [style="dotted"];
+ "0x7ffff7fbe1b0" -> "0x7ffff7fbe1e0" [label="93"];
+ "0x7ffff7fbe1e0" [label="0:e1e0:up your sentences into pieces",color="cornflowerblue"];
+ "0x7ffff7fbe1e0" -> "0x7ffff7fbe120" [label="64"];
+ "0x7ffff7fbe120" [label="0:e120:.
+",color="cornflowerblue"];
+ "0x7ffff7fbe120" -> "0x7ffff7fbe0f0" [label="62"];
+ "0x7ffff7fbe0f0" [label="0:e0f0:But of course they aren't all complicated either.",color="cornflowerblue"];
+ "0x7ffff7fbe0f0" -> "0x7ffff7fbe030" [label="13"];
+ "0x7ffff7fbe030" [label="0:e030:hello, world!:0",color="cornflowerblue"];
+ "0x7ffff7fbe030" -> "0x7ffff7fbe0f0" [style="dotted"];
+ "0x7ffff7fbe0f0" -> "0x7ffff7fbe120" [style="dotted"];
+ "0x7ffff7fbe120" -> "0x7ffff7fbe1e0" [style="dotted"];
+ "0x7ffff7fbe1e0" -> "0x7ffff7fbe1b0" [style="dotted"];
+ "0x7ffff7fbe1b0" -> "0x7ffff7fbe270" [style="dotted"];
+ "0x7ffff7fbe270" -> "0x7ffff7fbe210" [style="dotted"];
+}
A buggy_dots/yankputaaa.out => buggy_dots/yankputaaa.out +48 -0
@@ 0,0 1,48 @@
+digraph vine {
+ graph [ordering="out"];
+ ratio = fill;
+ node [style="filled"];
+ "0x7ffff7fbe360" [label="e360:aaaaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe360" -> "0x7ffff7fbe270" [label="13"];
+ "0x7ffff7fbe270" [label="e270:aaaaaaaaaa:0",color="cornflowerblue"];
+ "0x7ffff7fbe270" -> "0x7ffff7fbe090" [label="3"];
+ "0x7ffff7fbe090" [label="0:e090:hel:0",color="cornflowerblue"];
+ "0x7ffff7fbe090" -> "0x7ffff7fbe270" [style="dotted"];
+ "0x7ffff7fbe270" -> "0x7ffff7fbe360" [style="dotted"];
+ "0x7ffff7fbe360" -> "0x7ffff7fbe330" [label="198"];
+ "0x7ffff7fbe330" [label="0:e330:aaaaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe330" -> "0x7ffff7fbe300" [label="178"];
+ "0x7ffff7fbe300" [label="0:e300:aaaaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe300" -> "0x7ffff7fbe2d0" [label="158"];
+ "0x7ffff7fbe2d0" [label="0:e2d0:aaaaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe2d0" -> "0x7ffff7fbe240" [label="138"];
+ "0x7ffff7fbe240" [label="0:e240:aaaaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe240" -> "0x7ffff7fbe2a0" [label="118"];
+ "0x7ffff7fbe2a0" [label="0:e2a0:aaa",color="cornflowerblue"];
+ "0x7ffff7fbe2a0" -> "0x7ffff7fbe210" [label="115"];
+ "0x7ffff7fbe210" [label="0:e210:aaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe210" -> "0x7ffff7fbe1e0" [label="97"];
+ "0x7ffff7fbe1e0" [label="0:e1e0:aaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe1e0" -> "0x7ffff7fbe1b0" [label="79"];
+ "0x7ffff7fbe1b0" [label="0:e1b0:aaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe1b0" -> "0x7ffff7fbe180" [label="61"];
+ "0x7ffff7fbe180" [label="0:e180:aaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe180" -> "0x7ffff7fbe0f0" [label="43"];
+ "0x7ffff7fbe0f0" [label="0:e0f0:aaaaaaaaaaaaaaaaaa",color="crimson"];
+ "0x7ffff7fbe0f0" -> "0x7ffff7fbe150" [label="25"];
+ "0x7ffff7fbe150" [label="0:e150:aaaaaaaaaaaaaaa",color="cornflowerblue"];
+ "0x7ffff7fbe150" -> "0x7ffff7fbe0c0" [label="10"];
+ "0x7ffff7fbe0c0" [label="0:e0c0:lo, world!:0",color="cornflowerblue"];
+ "0x7ffff7fbe0c0" -> "0x7ffff7fbe150" [style="dotted"];
+ "0x7ffff7fbe150" -> "0x7ffff7fbe0f0" [style="dotted"];
+ "0x7ffff7fbe0f0" -> "0x7ffff7fbe180" [style="dotted"];
+ "0x7ffff7fbe180" -> "0x7ffff7fbe1b0" [style="dotted"];
+ "0x7ffff7fbe1b0" -> "0x7ffff7fbe1e0" [style="dotted"];
+ "0x7ffff7fbe1e0" -> "0x7ffff7fbe210" [style="dotted"];
+ "0x7ffff7fbe210" -> "0x7ffff7fbe2a0" [style="dotted"];
+ "0x7ffff7fbe2a0" -> "0x7ffff7fbe240" [style="dotted"];
+ "0x7ffff7fbe240" -> "0x7ffff7fbe2d0" [style="dotted"];
+ "0x7ffff7fbe2d0" -> "0x7ffff7fbe300" [style="dotted"];
+ "0x7ffff7fbe300" -> "0x7ffff7fbe330" [style="dotted"];
+ "0x7ffff7fbe330" -> "0x7ffff7fbe360" [style="dotted"];
+}
M src/text.c => src/text.c +179 -15
@@ 18,6 18,7 @@
#include "memory.h"
#include "text.h"
#include "hash.h"
+#include "heapstring.h"
static void text_tree_init(struct text_tree *);
static void text_tree_finish(struct text_tree *);
@@ 35,6 36,8 @@ static void text_tree_insert_leftchild_after(struct text_tree *tree, struct text
static void text_tree_insert_leftchild_before(struct text_tree *tree, struct text_node *new);
static struct text_node *create_node(struct text *tx, struct text_piece *p);
static struct text_piece *create_piece(struct text *tx);
+static size_t true_size(struct text_node *n);
+static void copy_to_buffer(struct text_node *t, size_t first, size_t last, char *buf, size_t cap, size_t *copied);
#define NODE_SIZE sizeof(struct text_node)
#define NODE_ALIGN __alignof__(struct text_node)
@@ 53,6 56,7 @@ text_node_init(struct text_node *n, struct text_piece *p)
n->txn_right_size = 0;
n->txn_piece = p;
}
+
#define BLUE "cornflowerblue"
#define RED "crimson"
static
@@ 63,8 67,8 @@ log_node(FILE *f, struct text_node *n)
if (n->txn_left == NULL) {
efprintf(f, "%lu:", n->txn_left_size);
}
- efprintf(f, "%x:%.*s",
- (u16)(u64)n, n->txn_piece->txp_len, n->txn_piece->txp_buf);
+ efprintf(f, "%lx:%.*s",
+ (0xffff & (u64)n), n->txn_piece->txp_len, n->txn_piece->txp_buf);
if (n->txn_right == NULL) {
efprintf(f, ":%lu",
n->txn_right_size);
@@ 126,6 130,23 @@ check_parents_are_correct(struct text_node *n)
static
size_t
+true_size(struct text_node *n)
+{
+ size_t result = 0;
+
+ if (n != NULL) {
+ if (n->txn_left != NULL)
+ result += true_size(n->txn_left);
+ if (n->txn_right != NULL)
+ result += true_size(n->txn_left);
+ result += n->txn_piece->txp_len;
+ }
+
+ return result;
+}
+
+static
+size_t
check_sizes_are_correct(struct text_node *n)
{
if (n->txn_left == NULL) {
@@ 141,7 162,7 @@ check_sizes_are_correct(struct text_node *n)
return n->txn_left_size + n->txn_right_size + n->txn_piece->txp_len;
}
-volatile int g_dobreak;
+volatile int g_dobreak = 0;
static
void
@@ 253,15 274,21 @@ finish_root_piece(struct text *tx)
p->txp_state = TXP_CONST;
}
+#define TM_NORMAL 0
+#define TM_INSERT 1
+#define TM_VISUAL 2
+
void
test_text(void)
{
- int insert = 0;
+ int mode = TM_NORMAL;
struct text tx;
char buf[] = "hello, world!";
- size_t cursor = 0;
+ size_t cursor = 0, vis_cursor = 0;
size_t size = sizeof(buf) - 1;
static struct termios oldterm, newterm;
+ struct heapstring *reg = NULL;
+ size_t reg_len = 0;
eprintf("piece %lux%lu=%lu\n", sizeof(struct text_piece), PAGE_SIZE /
sizeof(struct text_piece), PAGE_SIZE / sizeof(struct
@@ 281,25 308,73 @@ test_text(void)
int c;
check_invariants(&tx);
c = getchar();
- if (insert) {
- if ('A' <= c && c <= 'Z') {
+ if (mode == TM_INSERT) {
+ if (c == 0x7f) {
+ finish_root_piece(&tx);
+ mode = TM_NORMAL;
+ } else if (c != 0x1b) {
char ch = (char)c;
insert_at(&tx, cursor, &ch, 1);
cursor++;
size++;
} else {
finish_root_piece(&tx);
- insert = 0;
+ mode = TM_NORMAL;
+ }
+ } else if (mode == TM_VISUAL) {
+ if (c == 'l') {
+ cursor = (cursor + 1) % size;
+ } else if (c == 'h') {
+ cursor = (cursor - 1) % size;
+ } else if (c == 'y') {
+ size_t vis_first, vis_len, vis_last;
+ size_t copied;
+ if (cursor > vis_cursor) {
+ vis_len = cursor - vis_cursor;
+ vis_last = cursor;
+ vis_first = vis_cursor;
+ } else {
+ vis_len = vis_cursor - cursor;
+ vis_first = cursor;
+ vis_last = vis_cursor;
+ }
+
+ if (reg != NULL)
+ heapstring_destroy(reg, &sys_alloc);
+ reg = heapstring_create(vis_len, &sys_alloc);
+ copy_to_buffer(tx.tx_tree.txt_root,
+ vis_first, vis_last,
+ reg->hs_str, reg->hs_cap,
+ &copied);
+ reg_len = copied;
+ eprintf("register(%lu==%lu)=[%.*s\n].",
+ vis_len, reg_len, vis_len, reg->hs_str);
+ mode = TM_NORMAL;
+ } else {
+ mode = TM_NORMAL;
}
} else {
- if (c == EOF || c == 'q')
+ if (c == EOF || c == 'q') {
break;
- else if (c == 'l')
+ } else if (c == 'v') {
+ vis_cursor = cursor;
+ mode = TM_VISUAL;
+ } else if (c == 'l') {
cursor = (cursor + 1) % size;
- else if (c == 'h')
+ } else if (c == 'h') {
cursor = (cursor - 1) % size;
- else if (c == 'i') {
- insert = 1;
+ } else if (c == 'i') {
+ mode = TM_INSERT;
+ } else if (c == 'p') {
+ insert_at(&tx, cursor, reg->hs_str, reg_len);
+ size += reg_len;
+ finish_root_piece(&tx);
+ } else if (c == 'P') {
+ size_t loc = cursor == 0 ? 0 : cursor - 1;
+ insert_at(&tx, loc, reg->hs_str, reg_len);
+ size += reg_len;
+ cursor += reg_len;
+ finish_root_piece(&tx);
}
}
eprintf("%lu %lu", cursor, size);
@@ 988,12 1063,14 @@ do_splay(struct text_tree *tree, size_t cursor)
size_t right_total = t->txn_piece->txp_len + t->txn_right_size;
y = &n;
while (y != r) {
- y->txn_left_size -= left_total;
+ /*y->txn_left_size -= left_total;*/
+ y->txn_left_size = true_size(y->txn_left);
y = y->txn_left;
}
y = &n;
while (y != l) {
- y->txn_right_size -= right_total;
+ /*y->txn_right_size -= right_total;*/
+ y->txn_right_size = true_size(y->txn_right);
y = y->txn_right;
}
}
@@ 1056,3 1133,90 @@ print_text_tree_inorder(struct text_node *t, size_t cursor, size_t parent)
print_text_tree_inorder(t->txn_right, cursor, end);
}
+
+/* parent is the length of everything preceding this node that is above
+ * it in the tree */
+static
+void
+copy_to_buffer(struct text_node *t, size_t first, size_t last, char *buf, size_t cap, size_t *copied)
+{
+ size_t subcopied;
+ int do_before = 0, do_after = 0;
+ size_t start, len, end, offset, amount, front, back;
+ *copied = 0;
+
+ if (t == NULL)
+ return;
+
+ /* the first start and end positions and length of this node's piece */
+ start = t->txn_left_size;
+ len = t->txn_piece->txp_len;
+ end = start + len;
+
+ efprintf(stderr, "first=%lu, last=%lu, start=%lu, end=%lu, cap=%lu\n",
+ first, last, start, end, cap);
+
+ if (end <= first) {
+ efprintf(stderr, "going right");
+ return copy_to_buffer(t->txn_right, first, last, buf, cap, copied);
+ }
+ if (last <= start) {
+ efprintf(stderr, "going left");
+ return copy_to_buffer(t->txn_left, first, last, buf, cap, copied);
+ }
+
+ /*
+ copy_to_buffer(t->txn_left, first, last, buf, cap, &subcopied);
+ cap -= subcopied;
+ buf += subcopied;
+ *copied += subcopied;
+
+ copy_to_buffer(t->txn_right, first, last, buf, cap, &subcopied);
+ cap -= subcopied;
+ buf += subcopied;
+ *copied += subcopied;
+ */
+
+ if (start <= first && first <= end && end <= last) {
+ front = first;
+ back = end;
+ do_after = 1;
+ } else if (start <= first && last <= end) {
+ front = first;
+ back = last;
+ } else if (first <= start && end <= last) {
+ front = start;
+ back = end;
+ do_before = 1;
+ do_after = 1;
+ } else if (first <= start && start <= last && last <= end) {
+ front = start;
+ back = last;
+ do_before = 1;
+ }
+
+ if (do_before) {
+ efprintf(stderr, "do_before!\n");
+ copy_to_buffer(t->txn_left, first, last, buf, cap, &subcopied);
+ cap -= subcopied;
+ buf += subcopied;
+ *copied += subcopied;
+ }
+
+ offset = front - start;
+ amount = back - front;
+ if (amount > cap) amount = cap;
+
+ strncpy(buf, t->txn_piece->txp_buf + offset, amount);
+ cap -= amount;
+ buf += amount;
+ *copied += amount;
+
+ if (do_after) {
+ efprintf(stderr, "do_after!\n");
+ copy_to_buffer(t->txn_right, first, last, buf, cap, &subcopied);
+ cap -= subcopied;
+ buf += subcopied;
+ *copied += subcopied;
+ }
+}
M text.py => text.py +301 -10
@@ 1,3 1,8 @@
+import random
+import time
+
+step_by_step = False
+
class TextPiece:
def __init__(self, buf, size, state, cap):
self.buf = buf
@@ 5,10 10,31 @@ class TextPiece:
self.state = state
self.cap = cap
+ def __str__(self):
+ return self.buf + f'... (0x{self.size})'
+
class TextTree:
def __init__(self, root):
self.root = root
+ def dot(self):
+ with open('out.dot', 'w') as f:
+ print('digraph vine {', file=f)
+ print(' graph [ordering="out"];', file=f)
+ print(' ratio = fill;', file=f)
+ print(' forcelabels = true;', file=f)
+ print(' node [style="filled"];', file=f)
+ self.root.dot(f)
+ print('}', file=f)
+
+ def all_left_edges(self):
+ return sorted(self.root.all_left_edges())
+
+ def assert_is_good(self, ops):
+ ops = ','.join(f'{x:x}' for x in ops)#map(str, ops))
+ assert self.root.parent is None, ops
+ self.root.assert_is_good(ops)
+
class TextNode:
def __init__(self, parent, left, lsize, right, rsize, piece):
self.parent = parent
@@ 18,26 44,127 @@ class TextNode:
self.rsize = rsize
self.piece = piece
+ def assert_is_good(self, ops):
+ if self.parent:
+ assert self is self.parent.left or self is self.parent.right, ops
+ if self.left:
+ assert self.left.parent is self, ops
+ assert self.left.true_size == self.lsize, f'0x{self.left.true_size:x}:0x{self.lsize:x}:{ops}'
+ if self.right:
+ assert self.right.parent is self, ops
+ assert self.right.true_size == self.rsize, f'0x{self.right.true_size:x}:0x{self.rsize:x}:{ops}'
+
+ def parental_left_offset(self):
+ if self.parent is None:
+ return 0
+ if self is self.parent.left:
+ return self.parent.parental_left_offset()
+ elif self is self.parent.right:
+ return self.parent.right_edge()
+ else:
+ raise RuntimeError('Should not be possible!')
+
+ def left_edge(self):
+ return self.parental_left_offset() + self.lsize
+
+ def right_edge(self):
+ return self.parental_left_offset() + self.lsize + self.piece.size
+
+ def do_size(self):
+ if self.left is not None:
+ self.left.do_size()
+ if self.right is not None:
+ self.right.do_size()
+ self.lsize = self.left.size if self.left else 0
+ self.rsize = self.right.size if self.right else 0
+
+ @property
+ def size(self):
+ return self.lsize + self.piece.size + self.rsize
+
+ @property
+ def true_size(self):
+ return (self.left.true_size if self.left else 0) + (self.right.true_size if self.right else 0) + self.piece.size
+
+ def __str__(self):
+ return '\n'.join(self.to_tree(0))
+
+ def to_tree(self, indent):
+ ind = indent * '\t'
+ #tree = [f'{ind}{self.piece}']
+ tree = [f'{ind}{hex(self.lsize + self.piece.size + self.rsize)}']
+ if self.left is not None:
+ tree.extend(self.left.to_tree(indent + 1))
+ if self.right is not None:
+ tree.extend(self.right.to_tree(indent + 1))
+ return tree
+
+ def dot(self, f):
+ colour = 'crimson' if self.piece.state == 1 else 'cornflowerblue'
+ lere = f'{self.left_edge():x}:{self.right_edge():x}'
+ #lere = ''
+ print(f' "{id(self)}" [xlabel=<<font color="green">{lere}</font>>,label=<', file=f, end='')
+ #print(f' "{id(self)}" [label=<', file=f, end='')
+ if self.left is None:
+ print(f'{self.lsize:x}:', file=f, end='')
+ if False:
+ print(f'{self.piece}', file=f, end='')
+ elif False:
+ print(self.piece.size, file=f, end='')
+ elif False:
+ print(self.piece.size.bit_length() - 1, file=f, end='')
+ elif False:
+ print(f'2<sup>{self.piece.size.bit_length()-1}</sup>', file=f, end='')
+ else:
+ print(f'{self.piece.size:x} / 2<sup>{self.piece.size.bit_length()-1}</sup>', file=f, end='')
+ if self.right is None:
+ print(f':{self.rsize:x}', file=f, end='')
+ print(f'>,color="{colour}"];', file=f)
+
+ if self.left is not None:
+ print(f' "{id(self)}" -> "{id(self.left)}" [fontcolor="red",label="{self.lsize:x}"];', file=f)
+ #print(f' "{id(self)}" -> "{id(self.left)}";', file=f)
+ self.left.dot(f)
+ if self.right is not None:
+ print(f' "{id(self)}" -> "{id(self.right)}" [fontcolor="red",label="{self.rsize:x}"];', file=f)
+ #print(f' "{id(self)}" -> "{id(self.right)}";', file=f)
+ self.right.dot(f)
+ if self.parent is not None:
+ print(f' "{id(self)}" -> "{id(self.parent)}" [style="dotted"];', file=f)
+
+ def all_left_edges(self):
+ #ret = [random.randrange(self.left_edge(), self.right_edge())]
+ ret = [self.left_edge()]
+ if self.left is not None:
+ ret.extend(self.left.all_left_edges())
+ if self.right is not None:
+ ret.extend(self.right.all_left_edges())
+ return ret
+
+
def do_splay(t, cursor):
n = TextNode(None, None, 0, None, 0, None)
l = n
r = n
plo = 0
+ l_or_r_first = None
+
if t is None:
return
while True:
+ #if step_by_step: breakpoint()
le = plo + t.lsize
re = plo + t.lsize + t.piece.size
- if cursor <= le:
+ if cursor <= le and not (cursor == 0 and le == 0):
if t.left is None:
break
if cursor <= plo + t.left.lsize:
y = t.left
t.left = y.right
t.lsize = y.rsize
- if t.left:
+ if t.left is not None:
t.left.parent = t
y.right = t
y.rsize += t.rsize + t.piece.size
@@ 45,8 172,10 @@ def do_splay(t, cursor):
t = y
if t.left is None:
break
+ if l_or_r_first is None:
+ l_or_r_first = 'r'
r.left = t
- r.lsize = t.lsize + t.rsize + t.piece.size
+ r.lsize = t.size
if r != n:
t.parent = r
r = t
@@ 66,8 195,10 @@ def do_splay(t, cursor):
t = y
if t.right is None:
break
+ if l_or_r_first is None:
+ l_or_r_first = 'l'
l.right = t
- l.rsize = t.lsize + t.rsize + t.piece.size
+ l.rsize = t.size
if l != n:
t.parent = l
l = t
@@ 76,6 207,11 @@ def do_splay(t, cursor):
else:
break
+ lt = r.lsize - t.rsize
+ rt = l.rsize - t.lsize
+
+ #breakpoint()
+
l.right = t.left
l.rsize = t.lsize
r.left = t.right
@@ 86,22 222,177 @@ def do_splay(t, cursor):
if r.left is not None:
r.left.parent = r
- lt = t.piece.size + t.lsize
- rt = t.piece.size + t.rsize
+ #lt = t.piece.size + t.lsize
+ #rt = t.piece.size + t.rsize
y = n
while y != r:
- y.lsize -= lt
+ #y.lsize -= lt
+ y.lsize = y.left.true_size
y = y.left
y = n
while y != l:
- y.rsize -= rt
+ y.rsize = y.right.true_size
+ #y.rsize -= rt
y = y.right
t.left = n.right
t.right = n.left
- t.lsize = t.left.lsize + t.left.rsize + t.left.piece.size
- t.rsize = t.right.lsize + t.right.rsize + t.right.piece.size
+ if t.left is not None:
+ t.lsize = t.left.size
+ else:
+ t.lsize = 0
+ if t.right is not None:
+ t.rsize = t.right.size
+ else:
+ t.rsize = 0
+
+ if t.left is not None:
+ t.left.parent = t
+ if t.right is not None:
+ t.right.parent = t
t.parent = None
return t
+
+def generate_node(n):
+ k = 2 ** (n - 1)
+ p = TextPiece(chr(ord('A') + n - 1), k, 0, 0)
+ return TextNode(None, None, 0, None, 0, p)
+
+def generate_tree_k(k0, k):
+ root = generate_node(k0)
+ if k == 0:
+ return root
+ l = generate_tree_k(2 * k0, k - 1)
+ r = generate_tree_k(2 * k0 + 1, k - 1)
+ root.left = l
+ root.lsize = l.size
+ root.right = r
+ root.rsize = r.size
+ l.parent = root
+ r.parent = root
+ return root
+
+def generate_tree(k):
+ return TextTree(generate_tree_k(1, k))
+
+def gen_node(n):
+ k = n
+ p = TextPiece(None, k, 0, 0)
+ return TextNode(None, None, 0, None, 0, p)
+
+def gen_tree_k(k0, k):
+ root = gen_node(k0)
+ if k == 0:
+ return root
+ l = gen_tree_k(k0 // (2 ** (2 ** (k - 1))), k - 1)
+ r = gen_tree_k(k0 * (2 ** (2 ** (k - 1))), k - 1)
+ root.left = l
+ root.lsize = l.size
+ root.right = r
+ root.rsize = r.size
+ l.parent = root
+ r.parent = root
+ return root
+
+def gen_tree(k):
+ return TextTree(gen_tree_k(2 ** (2 ** k - 1), k))
+
+
+"""
+1
+ 2
+ 8
+ 128
+ 256
+ 16
+ 512
+ 1024
+ 4
+ 32
+ 2048
+ 4096
+ 64
+ 8192
+ 16384
+"""
+
+def main():
+ tr = generate_tree(3)
+ #a = generate_node(1)
+ #b = generate_node(2)
+ #c = generate_node(3)
+ #d = generate_node(4)
+ #e = generate_node(5)
+ #f = generate_node(6)
+ #g = generate_node(7)
+ #h = generate_node(8)
+ #i = generate_node(9)
+ #b.left = a; a.parent = b
+ #c.left = b; b.parent = c
+ #d.left = c; c.parent = d
+ #e.left = d; d.parent = e
+ #e.right = f; f.parent = e
+ #f.right = g; g.parent = f
+ #g.right = h; h.parent = g
+ #h.right = i; i.parent = h
+ #e.do_size()
+ #tr = TextTree(e)
+ tr.dot()
+ while True:
+ k = int(input('Enter number: '), 16)
+ if k == -1:
+ break
+ print(', '.join('{:x}'.format(x) for x in tr.all_left_edges()))
+ tr.root = do_splay(tr.root, k)
+ tr.dot()
+
+def test_all_trees(k):
+ global step_by_step
+ roots = set()
+ for i in range(2**(k + 1) - 1):
+ ops = []
+ tr = gen_tree(k)
+ tr.assert_is_good(ops)
+ le = tr.all_left_edges()[i] + 1
+ tr.assert_is_good(ops)
+ #tr.dot()
+ #input(str(le))
+ tr.root = do_splay(tr.root, le)
+ ops.append(le)
+ tr.assert_is_good(ops)
+ roots.add(tr.root.piece.size)
+ tr.dot()
+
+ #input()
+ if False:
+ les = tr.all_left_edges()
+ random.shuffle(les)
+ for le in les:
+ tr.root = do_splay(tr.root, le)
+ ops.append(le)
+ tr.assert_is_good(ops)
+ time.sleep(0.02)
+ tr.dot()
+ #input()
+ else:
+ tr.root = do_splay(tr.root, 0x7f)
+ tr.dot()
+ tr.assert_is_good(ops + [0x7f])
+ tr.root = do_splay(tr.root, 0x7ff)
+ tr.dot()
+ #input()
+ tr.assert_is_good(ops + [0x7f, 0x7ff])
+ step_by_step = True
+ tr.root = do_splay(tr.root, 0x1f)
+ step_by_step = False
+ tr.dot()
+ #input()
+ tr.assert_is_good(ops + [0x7f, 0x7ff, 0x1f])
+ if len(roots) != 2**(k + 1) - 1:
+ print('len(roots) wrong: expected {} but got {}'.format(2**(k + 1) - 1, len(roots)))
+
+if __name__ == '__main__':
+ while True:
+ test_all_trees(int(input('k? ')))