2.23. Iterator

Iterators are objects which can traverse over a sequence without knowing the details of the sequence’s implementation.

The Iterator type is defined as follows:

iterator_type ::= iterator < type >

iterator<int>           // iterates over integer
iterator<const Foo&>    // iterates over Foo by reference

Iterators can be moved, but not copied or cloned.

Iterators can be created via the each function from a range, static array, or dynamic array. each functions are unsafe because the iterator does not capture its arguments:

unsafe
    var it <- each ( [[int 1;2;3;4]] )

The most straightforward way to traverse an iterator is with a for loop:

for x in it             // iterates over contents of 'it'
    print("x = {x}\n")

For the reference iterator, the for loop will provide a reference variable:

var t = [[int 1;2;3;4]]
for x in t      // x is int&
    x ++        // increases values inside t

Iterators can be created from lambdas (see Lambda) or generators (see Generator).

Calling delete on an iterator will make it sequence out and free its memory:

var it <- each_enum(Numbers one)
delete it                           // safe to delete

var it <- each_enum(Numbers one)
for x in it
    print("x = {x}\n")
delete it                           // its always safe to delete sequenced out iterator

Loops and iteration functions do it automatically.

2.23.1. builtin iterators

Table keys and values iterators can be obtained via the keys and values functions:

var tab <- {{ "one"=>1; "two"=>2 }}
for k,v in keys(tab),values(tab)        // keys(tab) is iterator<string>
    print("{k} => {v}\n")               // values(tab) is iterator<int&>

It is possible to iterate over each character of the string via the each function:

unsafe
    for ch in each("hello,world!")      // string iterator is iterator<int>
        print("ch = {ch}\n")

It is possible to iterate over each element of an enumeration via the each_enum function:

enum Numbers
    one
    two
    ten = 10

for x in each_enum(Numbers one)         // argument is any value from said enumeration
    print("x = {x}\n")

2.23.2. builtin iteration functions

The empty function checks if an iterator is null or already sequenced out:

unsafe
    var it <- each ( [[int 1;2;3;4]] )
    for x in it
        print("x = {x}\n")
    verify(empty(it))           // iterator is sequenced out

More complicated iteration patterns may require the next function:

var x : int
while next(it,x)        // this is semantically equivalent to the `for x in it`
    print("x = {x}\n")

Next can only operate on copyable types.

2.23.3. low level builtin iteration functions

_builtin_iterator_first, _builtin_iterator_next, and _builtin_iterator_close address the regular lifecycle of the iterator. A semantic equivalent of the for loop can be explicitly written using these operations:

var it <- each(range(0,10))
var i : int
var pi : void?
unsafe
    pi = reinterpret<void?> ( addr(i) )
if _builtin_iterator_first(it,pi)
    print("i = {i}\n")
    while _builtin_iterator_next(it,pi)
        print("i = {i}\n")
    _builtin_iterator_close(it,pi)

_builtin_iterator_iterate is one function to rule them all. It acts like all 3 functions above. On a non-empty iterator it starts with ‘first’, then proceeds to call next until the sequence is exhausted. Once the iterator is sequenced out, it calls close:

var it <- each(range(0,10))
var i : int
var pi : void?
unsafe
    pi = reinterpret<void?> ( addr(i) )
while _builtin_iterator_iterate(it,pi)      // this is equivalent to the example above
    print("i = {i}\n")

2.23.4. next implementation details

The function next is implemented as follows:

def next ( it:iterator<auto(TT)>; var value : TT& ) : bool
    static_if !typeinfo(can_copy type<TT>)
        concept_assert(false, "requires type which can be copied")
    static_elif typeinfo(is_ref_value type<TT>)
        var pValue : TT - & ?
        unsafe
            if _builtin_iterator_iterate(it, addr(pValue))
                value = *pValue
                return true
            else
                return false
    else
        unsafe
            return _builtin_iterator_iterate(it, addr(value))

It is important to notice that builtin iteration functions accept pointers instead of references.