Anonymous structs and unions have been introduced in C11. The code of
make is supposed to be compatible with C90 though.
The additional members were intended to be used during an interactive
debugging session only and were thus not relevant to running the actual
code.
There is no use case for accessing or even modifying the capacity of a
vector, therefore there is no need to hide it using the prefix "priv_".
This way, the member names are aligned between Buffer and Vector.
This means no more unnecessary void pointers in function signatures and
no more abstraction level at checking a single element of a list. In
most cases it is more appropriate to define a function that operates on
the list as a whole, thereby hiding implementation details like the
ListNode from the caller.
Previously, Lst_ForEachUntil allowed the list to be modified while
iterating. Almost none of the code needs this, and it's also confusing
for human readers.
None of the current unit tests makes use of this concurrent modification
right now, but that's not evidence enough. Only 72% of the code are
covered by unit tests right now, and there are lots of edge cases
(whether intended or not) that are not covered by unit tests.
Therefore, all calls to Lst_ForEachUntil were changed to
Lst_ForEachUntilConcurrent and those that were obvious were changed
back. The remaining calls probably don't need the concurrent
modification code, but that's not obvious from looking at the code.
These functions had made the Lst data type more complicated and hard to
understand than necessary. This additional complexity was not needed in
the vast majority of the cases.
The function call variant takes more screen space than the direct field
access. Having an abstract API is usually a good idea, in this case of
simple read-only member access it makes the code more difficult to read.
LstNode_Set has been kept as a function since it is not a read-only
accessor function.
All of its uses have been inlined since iterating through a linked list
is trivial. This avoids the cumbersome callback functions with void
pointer parameters, allowing the compiler to perform better type checks.
These functions made the code larger than necessary. The prev and next
fields are published intentionally since navigating in a doubly-linked
list is simple to do and there is no need to wrap this in a layer of
function calls, not even syntactically. (On the execution level, the
function calls had been inlined anyway.)
The tags prevent the structs from accidentally becoming compatible
types.
While here, remove a few typedefs for structs that are single-purpose,
since there is no point in abstracting from the actual representation of
these types.
Accessing the fields List.first, List.last, ListNode.prev, ListNode.next
and ListNode.datum in read-only mode should be more efficient than a
whole function call.
All modifications to the lists or their nodes must still happen via
function calls.
This change reduces the code size, makes the code faster to execute and
allows Lst_ForEach to be written inline without the visual overhead of
function calls.
Since the callback function returns a terminating condition, this is not
really a foreach loop.
Many of the calls to Lst_ForEachUntil don't make use of the terminating
condition, and several don't modify the list structurally, which means
they don't need this complicated implementation.
In a follow-up commit, Lst_ForEach will be added back with a much
simpler implementation that iterates over the list naively, without a
terminating condition and without taking the iteration state from
Lst_Open/Lst_Next/Lst_Close into account. The migration to this simpler
implementation will be done step by step since each callback function
needs to be examined closely.
It was the last remaining use of that function outside of lst.c.
While here, clean up the code of add_wait_dep by removing unreachable
code (the GNode lists never contain NULL, only the GNode.commands lists
do that).
By using a Stack instead of a Lst, the available API is reduced to the
very few functions that are really needed for a stack. This prevents
accidental misuse (such as confusing Lst_Append with Lst_Prepend) and
clearly communicates what the expected behavior is.
A stack also needs fewer calls to bmake_malloc than an equally-sized
list, and the memory is contiguous. For the nested include path, all
this doesn't matter, but the type is so generic that it may be used in
other places as well.
Lst_IsEmpty does not belong in the "create and destroy" group, but in
"query information without modifying anything".
The functions named LstNode_* all belong together. They do not provide
much abstraction, but still they restrict the API and hide a few struct
fields that are only used internally by Lst_Open/Lst_Close and
Lst_ForEach.
Use consistent wording in the documentation of the functions (list,
node, datum).