namespace Invercargill { public abstract class Enumerable : Object { public abstract Tracker get_tracker(); // Returns false if iteration was interrupted // Returns true if iteration reached natural end public virtual bool iterate_if(PredicateDelegate handler) { var tracker = get_tracker(); while(tracker.has_next()) { if(!handler(tracker.get_next())) { return false; } } return true; } public virtual void iterate(ItemDelegate handler) { iterate_if(i => { handler(i); return true; }); } public virtual Sequence to_sequence() { var sequence = new Sequence(); iterate(i => sequence.add(i)); return sequence; } public virtual Gee.Collection to_collection() { var collection = new Gee.LinkedList(); iterate(i => collection.add(i)); return collection; } public virtual Tracker iterator() { return get_tracker(); } public virtual T[] to_array() { return to_collection().to_array(); } public virtual int count() { var count = 0; iterate(i => count++); return count; } public virtual bool any(PredicateDelegate predicate = (i) => true) { var result = false; iterate_if(i => { if(predicate(i)) { result = true; return false; } return true; }); return result; } public virtual bool all(PredicateDelegate predicate) { return !any(i => !predicate(i)); } public virtual bool no(PredicateDelegate predicate = (i) => true) { return all(i => !predicate(i)); } public virtual Enumerable where(owned PredicateDelegate predicate) { return new FilterQuery(this, (owned)predicate); } public virtual Enumerable select(owned TransformDelegate transform) { return new TransformQuery(this, (owned)transform); } public virtual Enumerable select_many(owned TransformDelegate> transform) { return new MergeQuery(select((owned)transform)); } public virtual Enumerable sort(owned CompareDelegate compare) { return new SortQuery(this, (owned)compare); } public virtual Enumerable concat(Enumerable other) { return new ConcatEnumerable(this, other); } public virtual Enumerable take(int count) { return new TakeQuery(this, count); } public virtual Enumerable skip(int count) { return new SkipQuery(this, count); } public virtual Enumerable cast() { return select(i => (Tout)i); } public virtual Enumerable parallel_select(owned TransformDelegate transform, uint workers = 0) { var actual_workers = workers; if(actual_workers < 1) { actual_workers = get_num_processors(); } return new ParallelQuery(this, (owned)transform, (int)actual_workers); } public virtual int parallel_iterate(ItemDelegate handler, uint workers = 0) { return parallel_select(i => { handler(i); return i; }, workers) .count(); } public virtual Enumerable> contextualised_select(owned TransformDelegate transform) { return new TransformQuery>(this, (i) => new SelectionContext() { origin = i, result = transform(i) }); } public virtual Tout aggrigate(Tout initial, AggrigateDelegate aggrigate_func) { var aggrigate = initial; iterate(i => { aggrigate = aggrigate_func(aggrigate, i); }); return aggrigate; } public virtual bool contains(T item) { return any(i => i == item); } public virtual Enumerable> pair(Enumerable other) { return new PairEnumerable(this, other); } public virtual Enumerable zip(Enumerable other) { return new ZipperEnumerable(this, other); } public virtual Enumerable fork(owned TransformDelegate fork1, owned TransformDelegate fork2) { var seq = to_sequence(); return seq.select((owned)fork1).zip(seq.select((owned)fork2)); } public virtual Enumerable fork_many(owned TransformDelegate> fork1, owned TransformDelegate> fork2) { return new MergeQuery(fork((owned)fork1, (owned)fork2)); } public virtual bool matches(Enumerable other, EqualityDelegate equals) { return pair(other).all(p => equals(p.value1, p.value2)); } public virtual Enumerable with(T item) { var seq = new Sequence(); seq.add(item); return concat(seq); } public virtual T first(owned PredicateDelegate? predicate = null) throws SequenceError { var tracker = predicate == null ? get_tracker() : where((owned)predicate).get_tracker(); if(tracker.has_next()) { return tracker.get_next(); } throw new SequenceError.NO_ELEMENTS("The sequence contains no elements"); } public virtual T? first_or_default(owned PredicateDelegate? predicate = null) { var tracker = predicate == null ? get_tracker() : where((owned)predicate).get_tracker(); if(tracker.has_next()) { return tracker.get_next(); } return null; } public virtual T single(owned PredicateDelegate? predicate = null) throws SequenceError { var tracker = predicate == null ? get_tracker() : where((owned)predicate).get_tracker(); if(tracker.has_next()) { var item = tracker.get_next(); if(tracker.has_next()) { throw new SequenceError.MULTUPLE_ELEMENTS("The sequence contains more than one element"); } return item; } throw new SequenceError.NO_ELEMENTS("The sequence contains no elements"); } public virtual T single_or_default(owned PredicateDelegate? predicate = null) throws SequenceError { var tracker = predicate == null ? get_tracker() : where((owned)predicate).get_tracker(); if(tracker.has_next()) { var item = tracker.get_next(); if(tracker.has_next()) { throw new SequenceError.MULTUPLE_ELEMENTS("The sequence contains more than one element"); } return item; } return null; } public virtual string to_string(TransformDelegate stringifier, string seperator = "") { bool is_first = true; return aggrigate("", (s, v) => { if(is_first) { is_first = false; return stringifier(v); } return s + seperator + stringifier(v); }); } public virtual Object[] to_object_array() throws SequenceError { if(!typeof(T).is_object()) { throw new SequenceError.INVALID_TYPE("Can only make an object array of an Enumerable where T is derrived from GLib.Object"); } return select(i => (Object)i).to_array(); } } }