Verifies that the 'dag' is in canonical order, meaning that nodes under the left branches have lower indices than nodes under * right branches, with the exception that nodes under right branches may (cross-)reference identical nodes that already occur under * left branches. * * Returns 'SIMPLICITY_NO_ERROR' if the 'dag' is in canonical order, and returns 'SIMPLICITY_ERR_DATA_OUT_OF_ORDER' if i
| 378 | * Precondition: dag_node dag[len] and 'dag' is well-formed. |
| 379 | */ |
| 380 | simplicity_err simplicity_verifyCanonicalOrder(dag_node* dag, const uint_fast32_t len) { |
| 381 | uint_fast32_t bottom = 0; |
| 382 | uint_fast32_t top = len-1; /* Underflow is checked below. */ |
| 383 | |
| 384 | if (!len) { |
| 385 | simplicity_assert(false); /* A well-formed dag has non-zero length */ |
| 386 | return SIMPLICITY_NO_ERROR; /* However, an empty dag is technically in canonical order */ |
| 387 | } |
| 388 | |
| 389 | /* We use dag[i].aux as a "stack" to manage the traversal of the DAG. */ |
| 390 | dag[top].aux = len; /* We will set top to 'len' to indicate we are finished. */ |
| 391 | |
| 392 | /* Each time any particular 'top' value is revisited in this loop, bottom has increased to be strictly larger than the last 'child' |
| 393 | value examined. Therefore we will make further progress in the loop the next time around. |
| 394 | By this reasoning any given 'top' value will be visited no more than numChildren(dag[top].tag) + 1 <= 3 times. |
| 395 | Thus this loop iterates at most O('len') times. |
| 396 | */ |
| 397 | while (top < len) { |
| 398 | /* We determine canonical order by iterating through the dag in canonical (pre-)order, |
| 399 | incrementing 'bottom' each time we encounter a node that is (correctly) placed at the 'bottom' index. |
| 400 | We take advantage of the precondition that the dag is well-formed to know in advance that any children |
| 401 | of a node have index strictly less than the node itself. |
| 402 | */ |
| 403 | |
| 404 | /* Check first child. */ |
| 405 | uint_fast32_t child = dag[top].child[0]; |
| 406 | switch (dag[top].tag) { |
| 407 | case ASSERTL: |
| 408 | case ASSERTR: |
| 409 | case CASE: |
| 410 | case DISCONNECT: |
| 411 | case COMP: |
| 412 | case PAIR: |
| 413 | case INJL: |
| 414 | case INJR: |
| 415 | case TAKE: |
| 416 | case DROP: |
| 417 | if (bottom < child) { |
| 418 | dag[child].aux = top; |
| 419 | top = child; |
| 420 | continue; |
| 421 | } |
| 422 | if (bottom == child) bottom++; |
| 423 | case IDEN: |
| 424 | case UNIT: |
| 425 | case WITNESS: |
| 426 | case HIDDEN: |
| 427 | case JET: |
| 428 | case WORD: |
| 429 | break; |
| 430 | } |
| 431 | |
| 432 | /* Check second child. */ |
| 433 | child = dag[top].child[1]; |
| 434 | switch (dag[top].tag) { |
| 435 | case ASSERTL: |
| 436 | case ASSERTR: |
| 437 | case CASE: |
no outgoing calls
no test coverage detected