Iterable Sample ​
You implement two pieces: Iterable<G> with iterator () and an element_type property (from Traversable), and a class that implements Iterator<G> for that iterable.
This follows the "Implementing your own Iterable" example from the archived Gee Samples wiki page, updated for current libgee. Notable changes from the wiki version:
Iteratornow requiresvalidandread_onlyproperties.- The old
first ()helper onIteratoris no longer part of the interface, so it is dropped here. - Both interfaces inherit from
Gee.Traversable, which has an abstractforeach ()method that you must implement. You also need to listTraversable<G>explicitly in the interface list of each class (the[GenericAccessors]prerequisite is not pulled in automatically byIterable/Iteratorin user-written code). intis used with a nullable type argument (int?) because libgee's interfaces use[GenericAccessors]. Passing a non-boxed primitive like plainintmakesvalacemit invalid C for the generated type/destroy/dup accessors.
Range walks integers in the half-open interval [from, to) (from inclusive, to exclusive).
Both listings below are complete programs. The first is the minimal sample; the second adds an optional Ruby- or Groovy-style each () on Range (highlighted lines).
using Gee;
public class Range : Object, Traversable<int?>, Iterable<int?> {
public int from { get; private set; }
public int to { get; private set; }
public Range (int from, int to) {
assert (from < to);
this.from = from;
this.to = to;
}
public Type element_type {
get { return typeof (int); }
}
public Iterator<int?> iterator () {
return new RangeIterator (this);
}
public bool @foreach (Gee.ForallFunc<int?> f) {
var it = iterator ();
while (it.next ()) {
if (!f (it.get ())) {
return false;
}
}
return true;
}
}
public class RangeIterator : Object, Traversable<int?>, Iterator<int?> {
private Range range;
private int current;
private bool _valid;
public RangeIterator (Range range) {
this.range = range;
this.current = range.from - 1;
this._valid = false;
}
public bool read_only {
get { return true; }
}
public bool valid {
get { return _valid; }
}
public bool has_next () {
return this.current + 1 < this.range.to;
}
public bool next () {
if (!has_next ()) {
return false;
}
this.current++;
this._valid = true;
return true;
}
/* The `new` keyword hides `Object.get ()` so this becomes the Iterator element accessor. */
public new int? get () {
return this.current;
}
public void remove () {
assert_not_reached ();
}
public bool @foreach (Gee.ForallFunc<int?> f) {
if (_valid) {
if (!f (get ())) {
return false;
}
}
while (next ()) {
if (!f (get ())) {
return false;
}
}
return true;
}
}
void main () {
foreach (int? i in new Range (10, 20)) {
stdout.printf ("%d\n", (!) i);
}
}Optional: each () helper ​
Same program with a delegate and each () on Range, and main using that API. Highlighted lines are everything added relative to the listing above (the helper and a sample call).
using Gee;
public class Range : Object, Traversable<int?>, Iterable<int?> {
public int from { get; private set; }
public int to { get; private set; }
public Range (int from, int to) {
assert (from < to);
this.from = from;
this.to = to;
}
public Type element_type {
get { return typeof (int); }
}
public Iterator<int?> iterator () {
return new RangeIterator (this);
}
public bool @foreach (Gee.ForallFunc<int?> f) {
var it = iterator ();
while (it.next ()) {
if (!f (it.get ())) {
return false;
}
}
return true;
}
public delegate void RangeEachFunc (int i);
public void each (RangeEachFunc each_func) {
foreach (int? i in this) {
each_func ((!) i);
}
}
}
public class RangeIterator : Object, Traversable<int?>, Iterator<int?> {
private Range range;
private int current;
private bool _valid;
public RangeIterator (Range range) {
this.range = range;
this.current = range.from - 1;
this._valid = false;
}
public bool read_only {
get { return true; }
}
public bool valid {
get { return _valid; }
}
public bool has_next () {
return this.current + 1 < this.range.to;
}
public bool next () {
if (!has_next ()) {
return false;
}
this.current++;
this._valid = true;
return true;
}
/* The `new` keyword hides `Object.get ()` so this becomes the Iterator element accessor. */
public new int? get () {
return this.current;
}
public void remove () {
assert_not_reached ();
}
public bool @foreach (Gee.ForallFunc<int?> f) {
if (_valid) {
if (!f (get ())) {
return false;
}
}
while (next ()) {
if (!f (get ())) {
return false;
}
}
return true;
}
}
void main () {
new Range (10, 20).each ((i) => {
stdout.printf ("%d\n", i);
});
}Compile and Run ​
valac --pkg gee-0.8 gee-iterable.vala
./gee-iterableEither listing prints the integers 10 through 19 once.
See the Collections chapter for how foreach uses iterators.
