[email protected] (mhx) writes:
I was going to mention that a good (or possibly the only) reason to use >iterators (like FOREACH) is when the data is organized in lists. However,
on reflection, it is possible to avoid lists by adding an indexing array
(at the cost of one indirection). Any idea if that would be significantly >faster?
Following a linked list costs 4-5 cycles per element on modern desktop
CPUs even if the elements are in the D-cache, more if they are further
away from the core.
By contrast, dealing with the elements through an array of element
addresses (I guess that's what you mean with "indexing array") does
not introduce such a latency: if each element is processed independent
of the others, you can process them arbitrarily in parallel. If there
is some dependency in the processing of the elements, that dependency
limits the processing.
However, there is probably a reason why you used a linked list instead
of an array. If you could easily do your processing with an array,
you would have chosen the array in the first place.
The disadvantage of a simple array would be that it becomes too small or
is too large (in case of lists the number of items is probably dynamic).
If the array can grow (and thus become too small), my usual approach
is to ALLOCATE the array with a power-of-two number of elements, and
RESIZE it to double size when that becomes too small.
As for "too large", that's something I don't worry about. However,
Bernd Paysan's string library (all the words with "$" in Gforth),
which has grown into covering all kinds of dynamically allocated
memory blocks, actually also uses RESIZE to shrink the memory blocks
it administers. The reason for this is that the library only
remembers the size of the current memory block in bytes, not also the
size of the ALLOCATEd/RESIZEd block. The library computes the size of
the ALLOCATEd block from the current memory block by rounding it up to
the next power-of-two; when the next memory block size for an
allocation results in a different power-of-to, the allocation is
RESIZEd, whether that grows or shrinks.
However, for a buffer where the contents can grow or shrink (or,
typically, start a new content with a smaller size that then grows), I
prefer not to shrink and to keep a separate BUFFER-MAXLENGTH field in
the data structure describing it around. This means that the number
of RESIZEs is determined by the maximum length that the buffer ever
has.
Back to linked lists: Typical applications are when you want to insert
or delete something in the middle or want to have a parent-pointer
tree (as in fig-Forth's vocabularies that all included the Forth
vocabulary), or when you don't want to deal with dynamic memory
allocation (as in wordlists in Forth implementations even without
fig-Forth's common-ancestor property).
- anton
--
M. Anton Ertl
http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs:
http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard:
https://forth-standard.org/
EuroForth 2023:
https://euro.theforth.net/2023
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)