Myrddin: libbio

Summary

Iteration over sequence is something that turns up regularly. The iteration utilities provided here simplify a number of common instances of iteration over collections. They allow for iterating over a zipped sequence, enumerating a collection of elements, or going over a collection of elements in reverse.

All of these iterators hold a reference to the original data, and require that it not be freed until they are finished consuming it. They do not copy the slices that they iterate over, and all consume O(1) storage.

pkg iter =
    type zipiter(@a, @b)
    type refiter(@a)#
    type reverseiter(@a)
    type enumiter(@a)

    impl iterable zipiter(@a, @b) -> (@a, @b)
    impl iterable enumiter(@a) -> (size, @a)
    impl iterable refiter(@a) -> @a#
    impl iterable reverseiter(@a) -> @a

    generic bychunk : (a : @a[:], chunk : std.size -> chunkiter(@a))
    generic byenum  : (a : @a[:] -> enumiter(@a))
    generic byperm  : (a : @a[:], cmp : (a : @a, b : @a -> std.order) -> permiter(@a))
    generic byref   : (sl : @a[:] -> refiter(@a))
    generic byreverse   : (sl : @a[:] -> reverseiter(@a))
    generic byzip   : (a : @a[:], b : @b[:]  -> zipiter(@a, @b))
;;

Zip Iterators

impl iterable zipiter(@a, @b) -> (@a, @b)
generic byzip   : (a : @a[:], b : @b[:]  -> zipiter(@a, @b))

The zipiter takes two slices, and returns an iterator that will walk over them pair by pair. So, for example, if you were to call std.byzip([1,2,3][:], [4,5,6][:]), you would iterate through the elements (1,4), (2,5), (3, 6).

Enum Iterators

impl iterable enumiter(@a) -> (size, @a)
generic byenum  : (a : @a[:] -> enumiter(@a))

The enumiter takes a single sequence, and returns the pair of (index, element) tuples. If you were to call std.byenum(["hello", "there", "friend"][:]), you iterate through the elements (1, "hello"), (2, "there"), (3, "friend").

Ref Iterators

impl iterable refiter(@a) -> @a#
generic byreverse   : (sl : @a[:] -> refiter(@a))

The reference iterator takes a single slice, and returns pointers to the elements back. This prevents spurious copies of large values, and may also be used to mutate the values being iterated over.

Reverse Iterators

impl iterable reverseiter(@a) -> @a
generic byreverse   : (sl : @a[:] -> reverseiter(@a))

The reverse takes a single slice, and returns the same elements back, but in the reverse order. Calling std.byenum(["hello", "there", "friend"][:]) would iterate in the sequence `"friend", "there", "hello".

Ref Iterators

impl iterable refiter(@a) -> @a#
generic byref   : (sl : @a[:] -> reverseiter(@a))

The reference iterator takes a slice, and iterates over it, returning a pointer to each element. This iterator can be used either to avoid excessive copying, or to mutate the original element in the sequence.

Permutation Iterator

Examples

This is a simple zip iterator:

This is a simple enum iterator: