-
Notifications
You must be signed in to change notification settings - Fork 18
Iterators
Iterators are objects similar to variants which contain a reference to a container and a position therein. All iterators share the same set of basic operations which don't depend on the source object, i.e. list iterators and map iterators use the same functions for manipulation.
An iterator points to a single item in a collection, and can be used to access its value, optionally also its key (map iterators). Some iterators also support erasing the item they point to, and list iterators can also be used to insert an item in a place where the original item was.
new List:l = list_new();
list_add(l, 1);
list_add(l, 2);
list_add(l, 3);
new Iter:i = list_iter(l); // points to the first element
assert iter_get(i) == 1;
iter_move_next(i);
assert iter_get(i) == 2;
iter_erase(i);
assert iter_get(i) == 3 && list_size(l) == 2;
iter_insert(i, 4);
assert list_get(l, 1) == 4 && list_size(l) == 3;
Iterators support both relative and absolute movement (iter_move_next
, iter_move_previous
, iter_to_first
, iter_to_last
). In contrast with C++, pointing to the "end" of a collection is usually represented by an iterator being "inside" or "outside" it (iter_inside
). Inserting an item via an "outside" iterator adds it to the end of the collection. iter_reset
moves the iterator "outside" the collection.
Iterators also support the equality operation and cloning. Two iterators are equal if they point to the same position in the same collection.
Every iterator has access to its collection, and is notified when the collection is deleted. In this case, the iterator object still exists, but cannot be used to access the collection anymore.
new List:l = list_new();
new Iter:i = list_iter(l);
assert iter_valid(i) && iter_linked(i);
list_delete(l);
assert iter_valid(i) && !iter_linked(i);
Since modifying a collection in any way may break existing iterators, all iterators are automatically invalidated when a collection is altered (like iter_reset
, so absolute movement is still possible).
new List:l = list_new();
list_add(l, 1);
new Iter:i = list_iter(l);
assert iter_inside(i);
list_add(l, 2);
assert !iter_inside(i);
The lifetime of iterators is handled similarly to strings and variants, since usually they are only used temporarily. In case an iterator should remain existing for a longer time, iter_acquire
and iter_release
should be used. See this for more information about garbage collection.
If the collection where an iterator points to is deleted, the iterator's lifetime stays unaffected.
Generic lists and maps produce generic iterators which employ compile-time safety measures preventing assigning or retrieving incorrectly tagged values:
new List<Float>:l = list_new<Float>();
list_add<Float>(l, 1.0);
list_add<Float>(l, 2.0);
list_add<Float>(l, 3.0);
for_list_of<Float>(i : l)
{
printf("%f", iter_get<Float>(i));
}