Section 199: Destroying boxes
When we are done with a node list, we are obliged to return it to free storage, including all of its sublists. The recursive procedure flush_node_list does this for us.
Section 200
First, however, we shall consider two non-recursive procedures that do simpler tasks. The first of these, delete_token_ref, is called when a pointer to a token list’s reference count is being removed. This means that the token list should disappear if the reference count was null, otherwise the count should be decreased by one.
#define token_ref_count(X) info((X)) // reference count preceding a token list
// |p| points to the reference count of a token list that is losing one reference
void delete_token_ref(pointer p) {
if (token_ref_count(p) == null) {
flush_list(p);
}
else {
decr(token_ref_count(p));
}
}
Section 201
Similarly, delete_glue_ref is called when a pointer to a glue specification is being withdrawn.
#define fast_delete_glue_ref(X) \
do { \
if (glue_ref_count((X)) == null) { \
free_node((X), GLUE_SPEC_SIZE); \
} \
else { \
decr(glue_ref_count((X))); \
} \
} while (0)
// |p| points to a glue specification
void delete_glue_ref(pointer p) {
fast_delete_glue_ref(p);
}
Section 202
Now we are ready to delete any node list, recursively. In practice, the nodes deleted are usually charnodes (about 2/3 of the time), and they are glue nodes in about half of the remaining cases.
// erase list of nodes starting at |p|
void flush_node_list(pointer p) {
pointer q; // successor to node |p|
while (p != null) {
q = link(p);
if (is_char_node(p)) {
free_avail(p);
}
else {
switch(type(p)) {
case HLIST_NODE:
case VLIST_NODE:
case UNSET_NODE:
flush_node_list(list_ptr(p));
free_node(p, BOX_NODE_SIZE);
goto done;
case RULE_NODE:
free_node(p, RULE_NODE_SIZE);
goto done;
case INS_NODE:
flush_node_list(ins_ptr(p));
delete_glue_ref(split_top_ptr(p));
free_node(p, INS_NODE_SIZE);
goto done;
case WHATSIT_NODE:
// << Wipe out the whatsit node |p| and |goto done|, 1358 >>
case GLUE_NODE:
fast_delete_glue_ref(glue_ptr(p));
if (leader_ptr(p) != null) {
flush_node_list(leader_ptr(p));
}
break;
case KERN_NODE:
case MATH_NODE:
case PENALTY_NODE:
do_nothing;
break;
case LIGATURE_NODE:
flush_node_list(lig_ptr(p));
break;
case MARK_NODE:
delete_token_ref(mark_ptr(p));
break;
case DISC_NODE:
flush_node_list(pre_break(p));
flush_node_list(post_break(p));
break;
case ADJUST_NODE:
flush_node_list(adjust_ptr(p));
break;
// << Cases of |flush_node_list| that arise in mlists only, 698 >>
default:
confusion("flushing");
}
free_node(p, SMALL_NODE_SIZE);
done:
}
p = q;
}
}