| 1 | #include <stdio.h>
|
|---|
| 2 | #include <seq.cvh>
|
|---|
| 3 | #include <assert.h>
|
|---|
| 4 | #include <stdarg.h>
|
|---|
| 5 | #include <stdint.h>
|
|---|
| 6 | #include <stdio.h>
|
|---|
| 7 | #include <stdlib.h>
|
|---|
| 8 | #include "treebuffer.h"
|
|---|
| 9 |
|
|---|
| 10 | #define unused(x) ((void)x)
|
|---|
| 11 | #define M (t->mems += 1)
|
|---|
| 12 | #define MM (t->mems += 2)
|
|---|
| 13 | #define MMM (t->mems += 3)
|
|---|
| 14 | #define MMMM (t->mems += 4)
|
|---|
| 15 |
|
|---|
| 16 | struct Node {
|
|---|
| 17 | Node * parent;
|
|---|
| 18 | int children; // the number of x such that (x->parent == this)
|
|---|
| 19 | Node * ll, * rl; // left link, right link; used for several lists
|
|---|
| 20 | int depth; // distance to root
|
|---|
| 21 | Node * representant; // ancestor with (depth % history == 0)
|
|---|
| 22 | int active_count; // number of x that are active and x->representant == this
|
|---|
| 23 | char seen; // used for garbage collection
|
|---|
| 24 | char active;
|
|---|
| 25 | int data;
|
|---|
| 26 |
|
|---|
| 27 | // NOTE: All lists using |ll| and |rl| are doubly linked, circular, and
|
|---|
| 28 | // using a sentinel.
|
|---|
| 29 |
|
|---|
| 30 | // TODO: pointer to tree so that I can assert that added nodes aren't already in a tree
|
|---|
| 31 | };
|
|---|
| 32 |
|
|---|
| 33 | typedef struct TBTree {
|
|---|
| 34 | int history;
|
|---|
| 35 | enum algo algo;
|
|---|
| 36 | Node * active; // list of active nodes
|
|---|
| 37 | Node * to_delete;
|
|---|
| 38 | // FILE * statistics_file;
|
|---|
| 39 | int node_count; // only maintained by tb_amortized
|
|---|
| 40 | int last_gc_node_count; // only maintained by tb_amortized
|
|---|
| 41 | int mems;
|
|---|
| 42 | int ref_count; // references from "Tree"
|
|---|
| 43 | } TBTree;
|
|---|
| 44 |
|
|---|
| 45 | struct Tree {
|
|---|
| 46 | int history;
|
|---|
| 47 | TBTree * tree;
|
|---|
| 48 | Node * last_add;
|
|---|
| 49 | };
|
|---|
| 50 |
|
|---|
| 51 | Node * tb_make_node(int data) {
|
|---|
| 52 | Node * r = malloc(sizeof(Node));
|
|---|
| 53 | r->parent = 0;
|
|---|
| 54 | r->children = 0;
|
|---|
| 55 | r->ll = r->rl = r;
|
|---|
| 56 | r->depth = -1;
|
|---|
| 57 | r->representant = 0;
|
|---|
| 58 | r->active_count = 0;
|
|---|
| 59 | r->seen = 0;
|
|---|
| 60 | r->active = 1;
|
|---|
| 61 | r->data = data;
|
|---|
| 62 | return r;
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | int tb_get_data(Node * x) {
|
|---|
| 66 | return x->data;
|
|---|
| 67 | }
|
|---|
| 68 |
|
|---|
| 69 | TBTree * tb_initialize(int history, enum algo algo, Node * root) {
|
|---|
| 70 | assert (root);
|
|---|
| 71 | assert (history > 0);
|
|---|
| 72 | TBTree * t = malloc(sizeof(TBTree));
|
|---|
| 73 | t->history = history;
|
|---|
| 74 | t->algo = algo;
|
|---|
| 75 | t->active = malloc(sizeof(Node));
|
|---|
| 76 | t->active->ll = t->active->rl = root;
|
|---|
| 77 | t->active->parent = 0;
|
|---|
| 78 | root->ll = root->rl = t->active;
|
|---|
| 79 | root->depth = 0;
|
|---|
| 80 | root->representant = root;
|
|---|
| 81 | root->active_count = 1;
|
|---|
| 82 | assert (root->active);
|
|---|
| 83 | t->to_delete = malloc(sizeof(Node));
|
|---|
| 84 | t->to_delete->ll = t->to_delete->rl = t->to_delete;
|
|---|
| 85 | //t->statistics_file = 0;
|
|---|
| 86 | t->node_count = 1;
|
|---|
| 87 | t->last_gc_node_count = 1;
|
|---|
| 88 | t->mems = 0;
|
|---|
| 89 | t->ref_count = 0;
|
|---|
| 90 | return t;
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | void cut_parent(TBTree * t, Node * y) {
|
|---|
| 94 | Node * x = (M, y->parent);
|
|---|
| 95 | if (x && (M, --x->children == 0) && !(M, x->active)) {
|
|---|
| 96 | assert (x->ll == x); // not in some other list
|
|---|
| 97 | assert (x->rl == x);
|
|---|
| 98 | x->ll = t->to_delete, MM; x->rl = t->to_delete->rl, MMM;
|
|---|
| 99 | x->ll->rl = x->rl->ll = x, MMMM;
|
|---|
| 100 | }
|
|---|
| 101 | y->parent = 0, M;
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | void delete_one(TBTree * t) {
|
|---|
| 105 | assert (t);
|
|---|
| 106 | Node * x = (MM, t->to_delete->rl);
|
|---|
| 107 | if ((M, x == t->to_delete)) return;
|
|---|
| 108 | assert (t->algo == tb_real_time);
|
|---|
| 109 | x->ll->rl = x->rl, MMM; x->rl->ll = x->ll, MMM;
|
|---|
| 110 | x->ll = x->rl = x, MM;
|
|---|
| 111 | cut_parent(t, x);
|
|---|
| 112 | free(x), M;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | void tb_delete(TBTree * t) {
|
|---|
| 116 | if (!t) return;
|
|---|
| 117 | assert (t->mems == 0);
|
|---|
| 118 |
|
|---|
| 119 | // Move |active| into |to_delete|.
|
|---|
| 120 | { Node * L = (MM, t->active->ll);
|
|---|
| 121 | Node * R = (MM, t->active->rl);
|
|---|
| 122 | R->ll = t->to_delete, MM;
|
|---|
| 123 | L->rl = t->to_delete->rl, MMM;
|
|---|
| 124 | t->active->rl->ll->rl = t->active->rl; t->mems += 6;
|
|---|
| 125 | t->active->ll->rl->ll = t->active->ll; t->mems += 6;
|
|---|
| 126 | t->active->ll = t->active->rl = t->active; t->mems += 5;
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | // Cleanup.
|
|---|
| 130 | t->algo = tb_real_time, M;
|
|---|
| 131 | while ((MMM, t->to_delete->rl != t->to_delete)) delete_one(t);
|
|---|
| 132 | t->mems = 0;
|
|---|
| 133 | free(t->active);
|
|---|
| 134 | free(t->to_delete);
|
|---|
| 135 | free(t);
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | void gc_todo_parent(TBTree * t, Node * y, Node * todo) {
|
|---|
| 139 | assert (y);
|
|---|
| 140 | Node * x = (M, y->parent);
|
|---|
| 141 | if (!x) return;
|
|---|
| 142 | if ((M, x->seen)) return;
|
|---|
| 143 | x->seen = 1, M;
|
|---|
| 144 | x->ll = todo, M; x->rl = todo->rl, MM;
|
|---|
| 145 | x->ll->rl = x->rl->ll = x, MMMM;
|
|---|
| 146 | }
|
|---|
| 147 |
|
|---|
| 148 | void gc_parent(TBTree *, Node *);
|
|---|
| 149 |
|
|---|
| 150 | void gc_node(TBTree * t, Node * x) {
|
|---|
| 151 | assert (t);
|
|---|
| 152 | assert (x);
|
|---|
| 153 | assert (!x->seen);
|
|---|
| 154 | assert (!x->active);
|
|---|
| 155 | assert (x->children == 0);
|
|---|
| 156 | gc_parent(t, x);
|
|---|
| 157 | free(x);
|
|---|
| 158 | if (t->algo == tb_amortized) --t->node_count, M;
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | void gc_parent(TBTree * t, Node * y) {
|
|---|
| 162 | assert (t);
|
|---|
| 163 | assert (y);
|
|---|
| 164 | Node * x = (M, y->parent);
|
|---|
| 165 | y->parent = 0, M;
|
|---|
| 166 | if (x && (M, --x->children == 0) && (M, !x->seen)) {
|
|---|
| 167 | gc_node(t, x);
|
|---|
| 168 | }
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | void gc(TBTree * t) {
|
|---|
| 172 | assert (t);
|
|---|
| 173 | assert (t->algo == tb_gc || t->algo == tb_amortized);
|
|---|
| 174 |
|
|---|
| 175 | for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl)) {
|
|---|
| 176 | n->seen = 1, M;
|
|---|
| 177 | }
|
|---|
| 178 | Node sentinel_a, sentinel_b, sentinel_c;
|
|---|
| 179 | Node * now; // being processed now
|
|---|
| 180 | Node * todo; // to process after now
|
|---|
| 181 | Node * middle; // was processed, but doesn't include active nodes
|
|---|
| 182 | now = &sentinel_a; todo = &sentinel_b; middle = &sentinel_c;
|
|---|
| 183 | middle->ll = middle->rl = middle, MM;
|
|---|
| 184 | now->ll = now->rl = now, MM;
|
|---|
| 185 | todo->ll = todo->rl = todo, MM;
|
|---|
| 186 | for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl)) {
|
|---|
| 187 | gc_todo_parent(t, n, todo);
|
|---|
| 188 | }
|
|---|
| 189 | for (int layer = 2; (MM, layer < t->history && todo != todo->rl); ++layer) {
|
|---|
| 190 | { Node * tmp = now; now = todo; todo = tmp; }
|
|---|
| 191 | for (Node * n = (M, now->rl); n != now; (M, n = n->rl)) {
|
|---|
| 192 | gc_todo_parent(t, n, todo);
|
|---|
| 193 | }
|
|---|
| 194 |
|
|---|
| 195 | // Move |now| content into |middle|.
|
|---|
| 196 | { Node * nl = (M, now->ll);
|
|---|
| 197 | Node * nr = (M, now->rl);
|
|---|
| 198 | nr->ll = middle, M;
|
|---|
| 199 | nl->rl = middle->rl, MM;
|
|---|
| 200 | now->rl->ll->rl = now->rl, MMMM;
|
|---|
| 201 | now->ll->rl->ll = now->ll, MMMM;
|
|---|
| 202 | now->ll = now->rl = now, MM;
|
|---|
| 203 | }
|
|---|
| 204 | }
|
|---|
| 205 | for (Node * n = (M, todo->rl); n != todo; (M, n = n->rl)) {
|
|---|
| 206 | gc_parent(t, n);
|
|---|
| 207 | }
|
|---|
| 208 | { Node * p, * q;
|
|---|
| 209 | for (p = (MM, t->to_delete->rl); p != (M, t->to_delete); p = q) {
|
|---|
| 210 | q = p->rl, M;
|
|---|
| 211 | gc_node(t, p);
|
|---|
| 212 | }
|
|---|
| 213 | t->to_delete->rl = t->to_delete->ll = t->to_delete, t->mems += 5;
|
|---|
| 214 | }
|
|---|
| 215 | assert (now->ll == now);
|
|---|
| 216 | assert (now->rl == now);
|
|---|
| 217 | for (Node * n = (M, todo->rl); n != todo; (M, n = n->rl)) n->seen = 0, M;
|
|---|
| 218 | for (Node * n = (M, middle->rl); n != middle; (M, n = n->rl)) n->seen = 0, M;
|
|---|
| 219 | for (Node * n = (MM, t->active->rl); (M, n != t->active); (M, n = n->rl))
|
|---|
| 220 | n->seen = 0, M;
|
|---|
| 221 | { Node * p, * q;
|
|---|
| 222 | for (p = (M, todo->rl); p != todo; p = q) {
|
|---|
| 223 | q = p->rl, M;
|
|---|
| 224 | p->ll = p->rl = p, MM;
|
|---|
| 225 | }
|
|---|
| 226 | for (p = (M, middle->rl); p != middle; p = q) {
|
|---|
| 227 | q = p->rl, M;
|
|---|
| 228 | p->ll = p->rl = p, MM;
|
|---|
| 229 | }
|
|---|
| 230 | }
|
|---|
| 231 |
|
|---|
| 232 | if (t->algo == tb_amortized) {
|
|---|
| 233 | t->last_gc_node_count = t->node_count, MM;
|
|---|
| 234 | }
|
|---|
| 235 | }
|
|---|
| 236 |
|
|---|
| 237 | void tb_add_child(TBTree * t, Node * parent, Node * child) {
|
|---|
| 238 | assert (t);
|
|---|
| 239 | assert (t->mems == 0);
|
|---|
| 240 | assert (parent);
|
|---|
| 241 | assert (child);
|
|---|
| 242 | child->parent = parent, M;
|
|---|
| 243 | ++parent->children, M;
|
|---|
| 244 | child->ll = t->active, MM; child->rl = t->active->rl, MMM;
|
|---|
| 245 | child->ll->rl = child->rl->ll = child, MMMM;
|
|---|
| 246 | if (t->algo == tb_amortized) {
|
|---|
| 247 | if ((MM, ++t->node_count >= 2 * t->last_gc_node_count)) gc(t);
|
|---|
| 248 | } else if (t->algo == tb_real_time) {
|
|---|
| 249 | delete_one(t);
|
|---|
| 250 | child->depth = parent->depth + 1, MM;
|
|---|
| 251 | child->representant =
|
|---|
| 252 | (MM, child->depth % t->history == 0)? child : (M, parent->representant); M;
|
|---|
| 253 | ++child->representant->active_count, MM;
|
|---|
| 254 | }
|
|---|
| 255 | t->mems = 0;
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | void tb_deactivate(TBTree * t, Node * n) {
|
|---|
| 259 | assert (t);
|
|---|
| 260 | assert (t->mems == 0);
|
|---|
| 261 | assert (n);
|
|---|
| 262 | assert (n->active);
|
|---|
| 263 | n->active = 0;
|
|---|
| 264 | n->ll->rl = n->rl, MMM; n->rl->ll = n->ll, MMM;
|
|---|
| 265 | n->ll = n->rl = n, MM;
|
|---|
| 266 | if ((M, n->children == 0)) {
|
|---|
| 267 | n->ll = t->to_delete, MM; n->rl = t->to_delete->rl, MMM;
|
|---|
| 268 | n->ll->rl = n->rl->ll = n, MMMM;
|
|---|
| 269 | }
|
|---|
| 270 | if (t->algo == tb_gc) {
|
|---|
| 271 | gc(t);
|
|---|
| 272 | }
|
|---|
| 273 | if (t->algo == tb_real_time) {
|
|---|
| 274 | assert (n->representant);
|
|---|
| 275 | if ((MM, --n->representant->active_count) == 0) {
|
|---|
| 276 | cut_parent(t, n->representant);
|
|---|
| 277 | }
|
|---|
| 278 | }
|
|---|
| 279 | t->mems = 0;
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | void tb_expand(TBTree * t, Node * parent, Node * children[]) {
|
|---|
| 283 | for (Node ** n = children; *n; ++n) tb_add_child(t, parent, *n);
|
|---|
| 284 | tb_deactivate(t, parent);
|
|---|
| 285 | }
|
|---|
| 286 |
|
|---|
| 287 | void tb_history(TBTree * t, Node * node, Node * ancestors[]) {
|
|---|
| 288 | assert (t->mems == 0);
|
|---|
| 289 | assert (node->active);
|
|---|
| 290 | int h = (M, t->history);
|
|---|
| 291 | while (node && h--) {
|
|---|
| 292 | *ancestors++ = node, M;
|
|---|
| 293 | node = node->parent, M;
|
|---|
| 294 | }
|
|---|
| 295 | *ancestors = 0, M;
|
|---|
| 296 | t->mems = 0;
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | Node * tb_active(const TBTree * t) {
|
|---|
| 300 | assert (t);
|
|---|
| 301 | if (t->active->rl == t->active) return 0;
|
|---|
| 302 | return t->active->rl;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | // PRE: |n| is in |t| (*not* checked by assertions), and active
|
|---|
| 306 | Node * tb_next_active(const TBTree * t, const Node * n) {
|
|---|
| 307 | assert (t);
|
|---|
| 308 | assert (n);
|
|---|
| 309 | // assert (n->active);
|
|---|
| 310 | if (n->rl == t->active) return 0;
|
|---|
| 311 | return n->rl;
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | /* ********* VerifyThis 2017 interface extension ********* */
|
|---|
| 315 |
|
|---|
| 316 | int get_data(Node * node) {
|
|---|
| 317 | return tb_get_data(node);
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | Tree * empty(int history) {
|
|---|
| 321 | Tree * tree = (Tree*)malloc(sizeof(Tree));
|
|---|
| 322 |
|
|---|
| 323 | tree->history = history;
|
|---|
| 324 | tree->tree = NULL;
|
|---|
| 325 | tree->last_add = NULL;
|
|---|
| 326 | return tree;
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | Tree * add(Tree * tree, int data) {
|
|---|
| 330 | Node * child = tb_make_node(data);
|
|---|
| 331 | Tree * new_tree = (Tree*)malloc(sizeof(Tree));
|
|---|
| 332 |
|
|---|
| 333 | if (tree->tree == NULL) {
|
|---|
| 334 | new_tree->tree = tb_initialize(tree->history, tb_real_time, child);
|
|---|
| 335 | new_tree->history = tree->history;
|
|---|
| 336 | new_tree->last_add = child;
|
|---|
| 337 | } else {
|
|---|
| 338 | tb_add_child(tree->tree, tree->last_add, child);
|
|---|
| 339 | new_tree->tree = tree->tree;
|
|---|
| 340 | new_tree->history = tree->history;
|
|---|
| 341 | new_tree->last_add = child;
|
|---|
| 342 | }
|
|---|
| 343 | new_tree->tree->ref_count++;
|
|---|
| 344 | return new_tree;
|
|---|
| 345 | }
|
|---|
| 346 |
|
|---|
| 347 | void take(Tree * tree, Node * ancestors[]) {
|
|---|
| 348 | if (tree->tree != NULL)
|
|---|
| 349 | tb_history(tree->tree, tree->last_add, ancestors);
|
|---|
| 350 | else
|
|---|
| 351 | ancestors[0] = 0;
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | void delete(Tree *tree) {
|
|---|
| 355 | TBTree * tb_tree = tree->tree;
|
|---|
| 356 |
|
|---|
| 357 | if (tb_tree!=NULL && --tb_tree->ref_count == 0)
|
|---|
| 358 | tb_delete(tree->tree);
|
|---|
| 359 | free(tree);
|
|---|
| 360 | }
|
|---|
| 361 |
|
|---|
| 362 | int hasSeen(Node * node, Node * seens[], int n) {
|
|---|
| 363 | for (int i = 0; i < n; i++) {
|
|---|
| 364 | if (node == seens[i]) return 1;
|
|---|
| 365 | }
|
|---|
| 366 | return 0;
|
|---|
| 367 | }
|
|---|
| 368 |
|
|---|
| 369 | /* Computing the H_<h, which is descried as the bound of the heap
|
|---|
| 370 | size */
|
|---|
| 371 | int computing_bounds(Tree * tree) {
|
|---|
| 372 | $atomic{
|
|---|
| 373 | TBTree * t = tree->tree;
|
|---|
| 374 | Node *active = t->active;
|
|---|
| 375 | Node * level[];
|
|---|
| 376 | Node * seen[];
|
|---|
| 377 |
|
|---|
| 378 | $seq_init(&level, 0, NULL);
|
|---|
| 379 | $seq_init(&seen, 0, NULL);
|
|---|
| 380 | while (active != NULL) {
|
|---|
| 381 | $seq_append(&level, &active, 1);
|
|---|
| 382 | $seq_append(&seen, &active, 1);
|
|---|
| 383 | active = tb_next_active(t, active);
|
|---|
| 384 | }
|
|---|
| 385 |
|
|---|
| 386 | int i = 1;
|
|---|
| 387 |
|
|---|
| 388 | while (i < tree->history) {
|
|---|
| 389 | int level_size = $seq_length(&level);
|
|---|
| 390 | int seen_size;
|
|---|
| 391 | Node * nxt_level[];
|
|---|
| 392 |
|
|---|
| 393 | $seq_init(&nxt_level, 0, NULL);
|
|---|
| 394 | for (int j = 0; j < level_size; j++) {
|
|---|
| 395 | active = level[j]->parent;
|
|---|
| 396 | seen_size = $seq_length(&seen);
|
|---|
| 397 | if (active != NULL)
|
|---|
| 398 | if (!hasSeen(active, seen, seen_size)) {
|
|---|
| 399 | $seq_append(&nxt_level, &active, 1);
|
|---|
| 400 | $seq_append(&seen, &active, 1);
|
|---|
| 401 | }
|
|---|
| 402 | }
|
|---|
| 403 | // level := nxt_levl ...
|
|---|
| 404 | $seq_remove(&level, 0, NULL, level_size);
|
|---|
| 405 | $seq_append(&level, &nxt_level, $seq_length(&nxt_level));
|
|---|
| 406 | i++;
|
|---|
| 407 | }
|
|---|
| 408 | return $seq_length(&seen);
|
|---|
| 409 | }
|
|---|
| 410 | }
|
|---|
| 411 |
|
|---|
| 412 | void check_heap_inbound(size_t heapsize, int history, Tree * tree, size_t *max) {
|
|---|
| 413 | int H = computing_bounds(tree);
|
|---|
| 414 | size_t boundsize = sizeof(Tree) + sizeof(TBTree) + sizeof(Node) * H
|
|---|
| 415 | // root, active and to_delete ...
|
|---|
| 416 | + sizeof(Node) * 3;
|
|---|
| 417 |
|
|---|
| 418 | if (boundsize < *max)
|
|---|
| 419 | boundsize = *max;
|
|---|
| 420 | else
|
|---|
| 421 | *max = boundsize;
|
|---|
| 422 | printf("max=%d\n", *max);
|
|---|
| 423 | printf("H<i=%d\n", H);
|
|---|
| 424 | printf("heap_size=%d\n", heapsize);
|
|---|
| 425 | printf("bound_size=%d\n", boundsize);
|
|---|
| 426 | assert(boundsize >= heapsize);
|
|---|
| 427 | }
|
|---|
| 428 |
|
|---|