#include #include #include #include #include #include #include #include "treebuffer.h" #define unused(x) ((void)x) #define M (t->mems += 1) #define MM (t->mems += 2) #define MMM (t->mems += 3) #define MMMM (t->mems += 4) struct Node { Node * parent; int children; // the number of x such that (x->parent == this) Node * ll, * rl; // left link, right link; used for several lists int depth; // distance to root Node * representant; // ancestor with (depth % history == 0) int active_count; // number of x that are active and x->representant == this char seen; // used for garbage collection char active; int data; // NOTE: All lists using |ll| and |rl| are doubly linked, circular, and // using a sentinel. // TODO: pointer to tree so that I can assert that added nodes aren't already in a tree }; typedef struct TBTree { int history; enum algo algo; Node * active; // list of active nodes Node * to_delete; // FILE * statistics_file; int node_count; // only maintained by tb_amortized int last_gc_node_count; // only maintained by tb_amortized int mems; int ref_count; // references from "Tree" } TBTree; struct Tree { int history; TBTree * tree; Node * last_add; }; Node * tb_make_node(int data) { Node * r = malloc(sizeof(Node)); r->parent = 0; r->children = 0; r->ll = r->rl = r; r->depth = -1; r->representant = 0; r->active_count = 0; r->seen = 0; r->active = 1; r->data = data; return r; } int tb_get_data(Node * x) { return x->data; } TBTree * tb_initialize(int history, enum algo algo, Node * root) { assert (root); assert (history > 0); TBTree * t = malloc(sizeof(TBTree)); t->history = history; t->algo = algo; t->active = malloc(sizeof(Node)); t->active->ll = t->active->rl = root; t->active->parent = 0; root->ll = root->rl = t->active; root->depth = 0; root->representant = root; root->active_count = 1; assert (root->active); t->to_delete = malloc(sizeof(Node)); t->to_delete->ll = t->to_delete->rl = t->to_delete; //t->statistics_file = 0; t->node_count = 1; t->last_gc_node_count = 1; t->mems = 0; t->ref_count = 0; return t; } void cut_parent(TBTree * t, Node * y) { Node * x = (M, y->parent); if (x && (M, --x->children == 0) && !(M, x->active)) { assert (x->ll == x); // not in some other list assert (x->rl == x); x->ll = t->to_delete, MM; x->rl = t->to_delete->rl, MMM; x->ll->rl = x->rl->ll = x, MMMM; } y->parent = 0, M; } void delete_one(TBTree * t) { assert (t); Node * x = (MM, t->to_delete->rl); if ((M, x == t->to_delete)) return; assert (t->algo == tb_real_time); x->ll->rl = x->rl, MMM; x->rl->ll = x->ll, MMM; x->ll = x->rl = x, MM; cut_parent(t, x); free(x), M; } void tb_delete(TBTree * t) { if (!t) return; assert (t->mems == 0); // Move |active| into |to_delete|. { Node * L = (MM, t->active->ll); Node * R = (MM, t->active->rl); R->ll = t->to_delete, MM; L->rl = t->to_delete->rl, MMM; t->active->rl->ll->rl = t->active->rl; t->mems += 6; t->active->ll->rl->ll = t->active->ll; t->mems += 6; t->active->ll = t->active->rl = t->active; t->mems += 5; } // Cleanup. t->algo = tb_real_time, M; while ((MMM, t->to_delete->rl != t->to_delete)) delete_one(t); t->mems = 0; free(t->active); free(t->to_delete); free(t); } void gc_todo_parent(TBTree * t, Node * y, Node * todo) { assert (y); Node * x = (M, y->parent); if (!x) return; if ((M, x->seen)) return; x->seen = 1, M; x->ll = todo, M; x->rl = todo->rl, MM; x->ll->rl = x->rl->ll = x, MMMM; } void gc_parent(TBTree *, Node *); void gc_node(TBTree * t, Node * x) { assert (t); assert (x); assert (!x->seen); assert (!x->active); assert (x->children == 0); gc_parent(t, x); free(x); if (t->algo == tb_amortized) --t->node_count, M; } void gc_parent(TBTree * t, Node * y) { assert (t); assert (y); Node * x = (M, y->parent); y->parent = 0, M; if (x && (M, --x->children == 0) && (M, !x->seen)) { gc_node(t, x); } } void gc(TBTree * t) { assert (t); assert (t->algo == tb_gc || t->algo == tb_amortized); for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl)) { n->seen = 1, M; } Node sentinel_a, sentinel_b, sentinel_c; Node * now; // being processed now Node * todo; // to process after now Node * middle; // was processed, but doesn't include active nodes now = &sentinel_a; todo = &sentinel_b; middle = &sentinel_c; middle->ll = middle->rl = middle, MM; now->ll = now->rl = now, MM; todo->ll = todo->rl = todo, MM; for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl)) { gc_todo_parent(t, n, todo); } for (int layer = 2; (MM, layer < t->history && todo != todo->rl); ++layer) { { Node * tmp = now; now = todo; todo = tmp; } for (Node * n = (M, now->rl); n != now; (M, n = n->rl)) { gc_todo_parent(t, n, todo); } // Move |now| content into |middle|. { Node * nl = (M, now->ll); Node * nr = (M, now->rl); nr->ll = middle, M; nl->rl = middle->rl, MM; now->rl->ll->rl = now->rl, MMMM; now->ll->rl->ll = now->ll, MMMM; now->ll = now->rl = now, MM; } } for (Node * n = (M, todo->rl); n != todo; (M, n = n->rl)) { gc_parent(t, n); } { Node * p, * q; for (p = (MM, t->to_delete->rl); p != (M, t->to_delete); p = q) { q = p->rl, M; gc_node(t, p); } t->to_delete->rl = t->to_delete->ll = t->to_delete, t->mems += 5; } assert (now->ll == now); assert (now->rl == now); for (Node * n = (M, todo->rl); n != todo; (M, n = n->rl)) n->seen = 0, M; for (Node * n = (M, middle->rl); n != middle; (M, n = n->rl)) n->seen = 0, M; for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl)) n->seen = 0, M; { Node * p, * q; for (p = (M, todo->rl); p != todo; p = q) { q = p->rl, M; p->ll = p->rl = p, MM; } for (p = (M, middle->rl); p != middle; p = q) { q = p->rl, M; p->ll = p->rl = p, MM; } } if (t->algo == tb_amortized) { t->last_gc_node_count = t->node_count, MM; } } void tb_add_child(TBTree * t, Node * parent, Node * child) { assert (t); assert (t->mems == 0); assert (parent); assert (child); child->parent = parent, M; ++parent->children, M; child->ll = t->active, MM; child->rl = t->active->rl, MMM; child->ll->rl = child->rl->ll = child, MMMM; if (t->algo == tb_amortized) { if ((MM, ++t->node_count >= 2 * t->last_gc_node_count)) gc(t); } else if (t->algo == tb_real_time) { delete_one(t); child->depth = parent->depth + 1, MM; child->representant = (MM, child->depth % t->history == 0)? child : (M, parent->representant); M; ++child->representant->active_count, MM; } t->mems = 0; } void tb_deactivate(TBTree * t, Node * n) { assert (t); assert (t->mems == 0); assert (n); assert (n->active); n->active = 0; n->ll->rl = n->rl, MMM; n->rl->ll = n->ll, MMM; n->ll = n->rl = n, MM; if ((M, n->children == 0)) { n->ll = t->to_delete, MM; n->rl = t->to_delete->rl, MMM; n->ll->rl = n->rl->ll = n, MMMM; } if (t->algo == tb_gc) { gc(t); } if (t->algo == tb_real_time) { assert (n->representant); if ((MM, --n->representant->active_count) == 0) { cut_parent(t, n->representant); } } t->mems = 0; } void tb_expand(TBTree * t, Node * parent, Node * children[]) { for (Node ** n = children; *n; ++n) tb_add_child(t, parent, *n); tb_deactivate(t, parent); } void tb_history(TBTree * t, Node * node, Node * ancestors[]) { assert (t->mems == 0); assert (node->active); int h = (M, t->history); while (node && h--) { *ancestors++ = node, M; node = node->parent, M; } *ancestors = 0, M; t->mems = 0; } Node * tb_active(const TBTree * t) { assert (t); if (t->active->rl == t->active) return 0; return t->active->rl; } // PRE: |n| is in |t| (*not* checked by assertions), and active Node * tb_next_active(const TBTree * t, const Node * n) { assert (t); assert (n); // assert (n->active); if (n->rl == t->active) return 0; return n->rl; } /* ********* VerifyThis 2017 interface extension ********* */ int get_data(Node * node) { return tb_get_data(node); } Tree * empty(int history) { Tree * tree = (Tree*)malloc(sizeof(Tree)); tree->history = history; tree->tree = NULL; tree->last_add = NULL; return tree; } Tree * add(Tree * tree, int data) { Node * child = tb_make_node(data); Tree * new_tree = (Tree*)malloc(sizeof(Tree)); if (tree->tree == NULL) { new_tree->tree = tb_initialize(tree->history, tb_real_time, child); new_tree->history = tree->history; new_tree->last_add = child; } else { tb_add_child(tree->tree, tree->last_add, child); new_tree->tree = tree->tree; new_tree->history = tree->history; new_tree->last_add = child; } new_tree->tree->ref_count++; return new_tree; } void take(Tree * tree, Node * ancestors[]) { if (tree->tree != NULL) tb_history(tree->tree, tree->last_add, ancestors); else ancestors[0] = 0; } void delete(Tree *tree) { TBTree * tb_tree = tree->tree; if (tb_tree!=NULL && --tb_tree->ref_count == 0) tb_delete(tree->tree); free(tree); } int hasSeen(Node * node, Node * seens[], int n) { for (int i = 0; i < n; i++) { if (node == seens[i]) return 1; } return 0; } /* Computing the H_tree; Node *active = t->active; Node * level[]; Node * seen[]; $seq_init(&level, 0, NULL); $seq_init(&seen, 0, NULL); while (active != NULL) { $seq_append(&level, &active, 1); $seq_append(&seen, &active, 1); active = tb_next_active(t, active); } int i = 1; while (i < tree->history) { int level_size = $seq_length(&level); int seen_size; Node * nxt_level[]; $seq_init(&nxt_level, 0, NULL); for (int j = 0; j < level_size; j++) { active = level[j]->parent; seen_size = $seq_length(&seen); if (active != NULL) if (!hasSeen(active, seen, seen_size)) { $seq_append(&nxt_level, &active, 1); $seq_append(&seen, &active, 1); } } // level := nxt_levl ... $seq_remove(&level, 0, NULL, level_size); $seq_append(&level, &nxt_level, $seq_length(&nxt_level)); i++; } return $seq_length(&seen); } } void check_heap_inbound(size_t heapsize, int history, Tree * tree, size_t *max) { int H = computing_bounds(tree); size_t boundsize = sizeof(Tree) + sizeof(TBTree) + sizeof(Node) * H // root, active and to_delete ... + sizeof(Node) * 3; if (boundsize < *max) boundsize = *max; else *max = boundsize; printf("max=%d\n", *max); printf("H= heapsize); }