[geary/wip/713891-traversable: 1/12] Basic implementation of Traversable->Iterable bridge



commit 3be7756a24b4368581ccb3a1624f17edbff31083
Author: Charles Lindsay <chaz yorba org>
Date:   Fri Dec 6 14:35:49 2013 -0800

    Basic implementation of Traversable->Iterable bridge
    
    This includes a few handy features I already know we'll need, but only a
    handful.  More should be added as necessary.

 src/CMakeLists.txt                    |    1 +
 src/engine/util/util-traversable.vala |  208 +++++++++++++++++++++++++++++++++
 2 files changed, 209 insertions(+), 0 deletions(-)
---
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bfc9c5d..7ee7572 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -286,6 +286,7 @@ engine/util/util-stream.vala
 engine/util/util-string.vala
 engine/util/util-synchronization.vala
 engine/util/util-time.vala
+engine/util/util-traversable.vala
 engine/util/util-trillian.vala
 )
 
diff --git a/src/engine/util/util-traversable.vala b/src/engine/util/util-traversable.vala
new file mode 100644
index 0000000..b4889ff
--- /dev/null
+++ b/src/engine/util/util-traversable.vala
@@ -0,0 +1,208 @@
+/* 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 {
+    public Geary.Traversable.Iterable<G> traverse<G>(Gee.Iterable<G> i) {
+        return new Geary.Traversable.Iterable<G>(i.iterator());
+    }
+}
+
+namespace Geary.Traversable {
+
+/**
+ * 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 should
+ * still work in foreach.
+ */
+public class Iterable<G> : BaseObject {
+    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, seed));
+    }
+    
+    public Iterable<G> filter(owned Gee.Predicate<G> f) {
+        return new Iterable<G>(i.filter(f));
+    }
+    
+    public Iterable<G> chop(int offset, int length = -1) {
+        return new Iterable<G>(i.chop(offset, length));
+    }
+    
+    public Iterable<G> filter_null() {
+        return new Iterable<G>(i.filter(x => x != null));
+    }
+    
+    public Iterable<A> cast<A>() {
+        return new Iterable<G>(
+            // This would be a lot simpler if valac didn't barf on the shorter,
+            // more obvious syntax for each of these delegates here.
+            i.filter(x => ((Object) x).get_type().is_a(typeof(A)))
+            .map<A>(x => { return (A) x; }));
+    }
+    
+    public Collection<G> to_collection(owned Gee.EqualDataFunc<G>? equal_func = null) {
+        return new Collection<G>(i, equal_func);
+    }
+    
+    public Gee.Collection<G> add_all_to(Gee.Collection<G> c) {
+        while (i.next())
+            c.add(i  get());
+        return c;
+    }
+    
+    public Gee.ArrayList<G> to_array_list(owned Gee.EqualDataFunc<G>? equal_func = null) {
+        Gee.ArrayList<G> c = new Gee.ArrayList<G>(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>(hash_func, 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>(compare_func);
+        add_all_to(c);
+        return c;
+    }
+}
+
+/**
+ * A Collection that lazily gets and caches results from an existing Iterator.
+ * Will iterate over the given Iterator at most once.
+ */
+public class Collection<G> : Gee.AbstractCollection<G> {
+    private class Iterator<G> : BaseObject, Gee.Iterator<G>, Gee.Traversable<G> {
+        private Collection<G> collection;
+        private int cache_index = -1;
+        
+        public virtual bool valid { get { return cache_index >= 0; } }
+        public virtual bool read_only { get { return true; } }
+        
+        public Iterator(Collection<G> collection) {
+            this.collection = collection;
+        }
+        
+        private void warn_read_only() {
+            warning("%s is read-only", get_type().name());
+        }
+        
+        public virtual bool next() {
+            bool _has_next = has_next();
+            if (_has_next)
+                ++cache_index;
+            return _has_next;
+        }
+        
+        public virtual bool has_next() {
+            if (cache_index + 1 >= collection.cache.size)
+                return collection.cache_next();
+            return true;
+        }
+        
+        public new virtual G @get() {
+            return collection cache  get(cache_index);
+        }
+        
+        public virtual void remove() {
+            warn_read_only();
+        }
+        
+        // For Gee.Traversable.
+        public virtual bool @foreach(Gee.ForallFunc<G> f) {
+            foreach (G item in collection) {
+                if (!f(item))
+                    return false;
+            }
+            return true;
+        }
+    }
+    
+    private Gee.Iterator<G> source;
+    private Gee.ArrayList<G> cache;
+    
+    public override int size { get { cache_all(); return cache.size; } }
+    public override bool read_only { get { return true; } }
+    
+    public Collection(Gee.Iterator<G> iterator, owned Gee.EqualDataFunc<G>? equal_func = null) {
+        base();
+        
+        source = iterator;
+        cache = new Gee.ArrayList<G>((owned) equal_func);
+    }
+    
+    private bool cache_next(out G element = null) {
+        if (source.next()) {
+            cache.add(element = source  get());
+            return true;
+        }
+        element = null;
+        return false;
+    }
+    
+    private void cache_all() {
+        while (cache_next()) {
+            // Nothing.
+        }
+    }
+    
+    private void warn_read_only() {
+        warning("%s is read-only", get_type().name());
+    }
+    
+    public override bool contains(G item) {
+        if (cache.contains(item))
+            return true;
+        
+        G test;
+        while (cache_next(out test)) {
+            if (cache.equal_func(test, item))
+                return true;
+        }
+        
+        return false;
+    }
+    
+    public override bool add(G item) {
+        warn_read_only();
+        return false;
+    }
+    
+    public override bool remove(G item) {
+        warn_read_only();
+        return false;
+    }
+    
+    public override void clear() {
+        warn_read_only();
+    }
+    
+    public override Gee.Iterator<G> iterator() {
+        return new Iterator<G>(this);
+    }
+}
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]