Skip to content

Instantly share code, notes, and snippets.

@chazomaticus
Last active December 31, 2015 17:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chazomaticus/8018276 to your computer and use it in GitHub Desktop.
Save chazomaticus/8018276 to your computer and use it in GitHub Desktop.
Iterable class from Geary, touched up a bit to stand alone
/* Copyright 2013 Yorba Foundation
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
namespace Geary {
/**
* Take a Gee object and return a Geary.Iterable for convenience.
*/
public Geary.Iterable<G> traverse<G>(Gee.Iterable<G> i) {
return new Geary.Iterable<G>(i.iterator());
}
/**
* Take some non-null items (all must be of type G) and return a
* Geary.Iterable for convenience.
*/
public Geary.Iterable<G> iterate<G>(G g, ...) {
va_list args = va_list();
G arg = g;
Gee.ArrayList<G> list = new Gee.ArrayList<G>();
do {
list.add(arg);
} while ((arg = args.arg()) != null);
return Geary.traverse<G>(list);
}
/**
* Take an array of items and return a Geary.Iterable for convenience.
*/
public Geary.Iterable<G> iterate_array<G>(G[] a) {
return Geary.traverse<G>(new Gee.ArrayList<G>.wrap(a));
}
}
/**
* An Iterable that simply wraps an existing Iterator. You get one iteration,
* and only one iteration. Basically every method triggers one iteration and
* returns a new object.
*
* Note that this can't inherit from Gee.Iterable because its interface
* requires that map/filter/etc. return Iterators, not Iterables. It still
* works in foreach.
*/
public class Geary.Iterable<G> : Object {
/**
* A private class that lets us take a Geary.Iterable and convert it back
* into a Gee.Iterable.
*/
private class GeeIterable<G>
: Gee.Traversable<G>, Gee.Iterable<G>, Object {
private Gee.Iterator<G> i;
public GeeIterable(Gee.Iterator<G> iterator) {
i = iterator;
}
public Gee.Iterator<G> iterator() {
return i;
}
// Unfortunately necessary for Gee.Traversable.
public virtual bool @foreach(Gee.ForallFunc<G> f) {
foreach (G g in this) {
if (!f(g))
return false;
}
return true;
}
}
private Gee.Iterator<G> i;
public Iterable(Gee.Iterator<G> iterator) {
i = iterator;
}
public virtual Gee.Iterator<G> iterator() {
return i;
}
public Iterable<A> map<A>(Gee.MapFunc<A, G> f) {
return new Iterable<A>(i.map<A>(f));
}
public Iterable<A> scan<A>(Gee.FoldFunc<A, G> f, owned A seed) {
return new Iterable<A>(i.scan<A>(f, (owned) seed));
}
public Iterable<G> filter(owned Gee.Predicate<G> f) {
return new Iterable<G>(i.filter((owned) f));
}
public Iterable<G> chop(int offset, int length = -1) {
return new Iterable<G>(i.chop(offset, length));
}
public Iterable<A> map_nonnull<A>(Gee.MapFunc<A, G> f) {
return new Iterable<A>(i.map<A>(f).filter(g => g != null));
}
/**
* Return only objects of the destination type, as the destination type.
* Only works on types derived from Object.
*/
public Iterable<A> cast_object<A>() {
return new Iterable<A>(
// This would be a lot simpler if valac didn't barf on the
// shorter, more obvious syntax for each of these delegates.
i.filter(g => ((Object) g).get_type().is_a(typeof(A)))
.map<A>(g => { return (A) g; }));
}
public G? first() {
foreach (G g in this)
return g;
return null;
}
public G? first_matching(Gee.Predicate<G> f) {
foreach (G g in this) {
if (f(g))
return g;
}
return null;
}
public bool any(Gee.Predicate<G> f) {
foreach (G g in this) {
if (f(g))
return true;
}
return false;
}
public bool all(Gee.Predicate<G> f) {
foreach (G g in this) {
if (!f(g))
return false;
}
return true;
}
public int count_matching(Gee.Predicate<G> f) {
int count = 0;
foreach (G g in this) {
if (f(g))
count++;
}
return count;
}
/**
* The resulting Gee.Iterable comes with the same caveat that you may only
* iterate over it once.
*/
public Gee.Iterable<G> to_gee_iterable() {
return new GeeIterable<G>(i);
}
public Gee.Collection<G> add_all_to(Gee.Collection<G> c) {
foreach (G g in this)
c.add(g);
return c;
}
public Gee.ArrayList<G> to_array_list(
owned Gee.EqualDataFunc<G>? equal_func = null) {
Gee.ArrayList<G> c = new Gee.ArrayList<G>((owned) equal_func);
add_all_to(c);
return c;
}
public Gee.LinkedList<G> to_linked_list(
owned Gee.EqualDataFunc<G>? equal_func = null) {
Gee.LinkedList<G> c = new Gee.LinkedList<G>((owned) equal_func);
add_all_to(c);
return c;
}
public Gee.HashSet<G> to_hash_set(
owned Gee.HashDataFunc<G>? hash_func = null,
owned Gee.EqualDataFunc<G>? equal_func = null) {
Gee.HashSet<G> c = new Gee.HashSet<G>(
(owned) hash_func, (owned) equal_func);
add_all_to(c);
return c;
}
public Gee.TreeSet<G> to_tree_set(
owned CompareDataFunc<G>? compare_func = null) {
Gee.TreeSet<G> c = new Gee.TreeSet<G>((owned) compare_func);
add_all_to(c);
return c;
}
public Gee.Map<K, G> add_all_to_map<K>(
Gee.Map<K, G> m,
Gee.MapFunc<K, G> key_func) {
foreach (G g in this)
m.@set(key_func(g), g);
return m;
}
public Gee.HashMap<K, G> to_hash_map<K>(
Gee.MapFunc<K, G> key_func,
owned Gee.HashDataFunc<K>? key_hash_func = null,
owned Gee.EqualDataFunc<K>? key_equal_func = null,
owned Gee.EqualDataFunc<G>? value_equal_func = null) {
Gee.HashMap<K, G> c = new Gee.HashMap<K, G>(
(owned) key_hash_func,
(owned) key_equal_func,
(owned) value_equal_func);
add_all_to_map<K>(c, key_func);
return c;
}
}
@chazomaticus
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment