~milesrout/vine

c7e21ce6fad79f8c647a8388250dacf2d59455f1 — Miles Rout 2 years ago 7112354 text
WIP5
4 files changed, 564 insertions(+), 25 deletions(-)

A buggy_dots/e210.dot
A buggy_dots/yankputaaa.out
M src/text.c
M text.py
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? ')))