Introduce the ListIterator interface and make lists implement it
authorDidier 'Ptitjes <ptitjes@free.fr>
Tue, 15 Sep 2009 11:33:29 +0000 (13:33 +0200)
committerDidier 'Ptitjes <ptitjes@free.fr>
Tue, 15 Sep 2009 18:15:43 +0000 (20:15 +0200)
gee/Makefile.am
gee/abstractlist.vala
gee/arraylist.vala
gee/linkedlist.vala
gee/list.vala
gee/listiterator.vala [new file with mode: 0644]
gee/readonlylist.vala
tests/testlist.vala

index 4a899b0..f9d7266 100644 (file)
@@ -32,6 +32,7 @@ libgee_la_VALASOURCES = \
        iterator.vala \
        linkedlist.vala \
        list.vala \
+       listiterator.vala \
        map.vala \
        multimap.vala \
        multiset.vala \
index ec1bb39..23d491e 100644 (file)
@@ -34,6 +34,11 @@ public abstract class Gee.AbstractList<G> : Gee.AbstractCollection<G>, List<G> {
        /**
         * @inheritDoc
         */
+       public abstract ListIterator<G> list_iterator ();
+
+       /**
+        * @inheritDoc
+        */
        public abstract new G? get (int index);
 
        /**
index e4810e0..0e0e29e 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2004-2005  Novell, Inc
  * Copyright (C) 2005  David Waite
  * Copyright (C) 2007-2008  Jürg Billeter
+ * Copyright (C) 2009  Didier Villevalois
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,7 @@
  *
  * Author:
  *     Jürg Billeter <j@bitron.ch>
+ *     Didier 'Ptitjes Villevalois <ptitjes@free.fr>
  */
 
 using GLib;
@@ -76,6 +78,13 @@ public class Gee.ArrayList<G> : AbstractList<G> {
        /**
         * @inheritDoc
         */
+       public override ListIterator<G> list_iterator () {
+               return new Iterator<G> (this);
+       }
+
+       /**
+        * @inheritDoc
+        */
        public override bool contains (G item) {
                return (index_of (item) != -1);
        }
@@ -237,7 +246,7 @@ public class Gee.ArrayList<G> : AbstractList<G> {
                _items.resize (value);
        }
 
-       private class Iterator<G> : Object, Gee.Iterator<G> {
+       private class Iterator<G> : Object, Gee.Iterator<G>, BidirIterator<G>, ListIterator<G> {
                public ArrayList<G> list {
                        construct {
                                _list = value;
@@ -258,11 +267,12 @@ public class Gee.ArrayList<G> : AbstractList<G> {
 
                public bool next () {
                        assert (_stamp == _list._stamp);
-                       if (_index < _list._size) {
+                       if (_index + 1 < _list._size) {
                                _index++;
+                               _removed = false;
+                               return true;
                        }
-                       _removed = false;
-                       return (_index < _list._size);
+                       return false;
                }
 
                public bool has_next () {
@@ -285,7 +295,7 @@ public class Gee.ArrayList<G> : AbstractList<G> {
                        assert (_index >= 0);
                        assert (_index < _list._size);
                        assert (! _removed);
-                       return _list.get (_index);
+                       return _list._items[_index];
                }
 
                public void remove () {
@@ -298,6 +308,62 @@ public class Gee.ArrayList<G> : AbstractList<G> {
                        _removed = true;
                        _stamp = _list._stamp;
                }
+
+               public bool previous () {
+                       assert (_stamp == _list._stamp);
+                       if (_index > 0) {
+                               _index--;
+                               return true;
+                       }
+                       return false;
+               }
+
+               public bool has_previous () {
+                       assert (_stamp == _list._stamp);
+                       return (_index - 1 >= 0);
+               }
+
+               public bool last () {
+                       assert (_stamp == _list._stamp);
+                       if (_list.size == 0) {
+                               return false;
+                       }
+                       _index = _list._size - 1;
+                       return true;
+               }
+
+               public new void set (G item) {
+                       assert (_stamp == _list._stamp);
+                       assert (_index >= 0);
+                       assert (_index < _list._size);
+                       _list._items[_index] = item;
+                       _stamp = ++_list._stamp;
+               }
+
+               public void insert (G item) {
+                       assert (_stamp == _list._stamp);
+                       assert (_index >= 0);
+                       assert (_index < _list._size);
+                       _list.insert (_index, item);
+                       _index++;
+                       _stamp = _list._stamp;
+               }
+
+               public void add (G item) {
+                       assert (_stamp == _list._stamp);
+                       assert (_index >= 0);
+                       assert (_index < _list._size);
+                       _list.insert (_index + 1, item);
+                       _index++;
+                       _stamp = _list._stamp;
+               }
+
+               public int index () {
+                       assert (_stamp == _list._stamp);
+                       assert (_index >= 0);
+                       assert (_index < _list._size);
+                       return _index;
+               }
        }
 }
 
index 1918033..e021ee8 100644 (file)
@@ -3,8 +3,7 @@
  * Copyright (C) 2004-2005  Novell, Inc
  * Copyright (C) 2005  David Waite
  * Copyright (C) 2007-2008  Jürg Billeter
- * Copyright (C) 2009  Mark Lee
- * Copyright (C) 2009  Julien Fontanet
+ * Copyright (C) 2009  Mark Lee, Didier Villevalois
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,6 +21,7 @@
  *
  * Author:
  *     Mark Lee <marklee@src.gnome.org>
+ *     Didier 'Ptitjes Villevalois <ptitjes@free.fr>
  */
 
 /**
@@ -65,6 +65,13 @@ public class Gee.LinkedList<G> : AbstractList<G>, Queue<G>, Deque<G> {
        /**
         * @inheritDoc
         */
+       public override ListIterator<G> list_iterator () {
+               return new Iterator<G> (this);
+       }
+
+       /**
+        * @inheritDoc
+        */
        public override int size {
                get { return this._size; }
        }
@@ -385,31 +392,38 @@ public class Gee.LinkedList<G> : AbstractList<G>, Queue<G>, Deque<G> {
                }
        }
 
-       private class Iterator<G> : Object, Gee.Iterator<G> {
+       private class Iterator<G> : Object, Gee.Iterator<G>, BidirIterator<G>, ListIterator<G> {
                private bool started = false;
                private bool removed = false;
                private unowned Node<G>? position;
                private int _stamp;
                private LinkedList<G> _list;
+               private int _index;
 
                public Iterator (LinkedList<G> list) {
                        this._list = list;
                        this.position = null;
+                       this._index = -1;
                        this._stamp = list._stamp;
                }
 
                public bool next () {
                        assert (this._stamp == this._list._stamp);
 
-                       if (this.removed) {
+                       if (this.removed && this.position != null) {
                                this.removed = false;
-                       } else if (!this.started) {
+                               return true;
+                       } else if (!this.started && this._list._head != null) {
                                this.started = true;
                                this.position = this._list._head;
-                       } else if (this.position != null) {
+                               this._index++;
+                               return true;
+                       } else if (this.position != null && this.position.next != null) {
                                this.position = this.position.next;
+                               this._index++;
+                               return true;
                        }
-                       return this.position != null;
+                       return false;
                }
 
                public bool has_next () {
@@ -427,9 +441,14 @@ public class Gee.LinkedList<G> : AbstractList<G>, Queue<G>, Deque<G> {
 
                public bool first () {
                        assert (this._stamp == this._list._stamp);
-                       this.position = null;
-                       this.started = false;
-                       return next ();
+                       if (this._list.size == 0) {
+                               return false;
+                       }
+                       this.position = this._list._head;
+                       this.started = true;
+                       this._index = 0;
+                       this.removed = false;
+                       return this.position != null;
                }
 
                public new G get () {
@@ -452,6 +471,94 @@ public class Gee.LinkedList<G> : AbstractList<G>, Queue<G>, Deque<G> {
                        this.removed = true;
                        this._stamp = this._list._stamp;
                }
+
+               public bool previous () {
+                       assert (this._stamp == this._list._stamp);
+
+                       if (!this.started) {
+                               this.position = null;
+                               return false;
+                       } else if (this.position != null && this.position.prev != null) {
+                               this.position = this.position.prev;
+                               this._index--;
+                               return true;
+                       }
+                       return false;
+               }
+
+               public bool has_previous () {
+                       assert (this._stamp == this._list._stamp);
+
+                       if (!this.started) {
+                               return false;
+                       } else if (this.position != null) {
+                               return this.position.prev != null;
+                       }
+                       return false;
+               }
+
+               public bool last () {
+                       assert (this._stamp == this._list._stamp);
+
+                       if (this._list.size == 0) {
+                               return false;
+                       }
+                       this.position = this._list._tail;
+                       this.started = true;
+                       this._index = this._list._size - 1;
+                       return this.position != null;
+               }
+
+               public new void set (G item) {
+                       assert (this._stamp == this._list._stamp);
+                       assert (this.position != null);
+
+                       this.position.data = item;
+               }
+
+               public void insert (G item) {
+                       assert (this._stamp == this._list._stamp);
+                       assert (this.position != null);
+
+                       Node<G> n = new Node<G> (item);
+                       if (this.position.prev != null) {
+                               this.position.prev.next = n;
+                               n.prev = this.position.prev;
+                       } else {
+                               this._list._head = n;
+                       }
+                       this.position.prev = n;
+                       n.next = this.position;
+                       this._list._size++;
+                       this._index++;
+                       _stamp = _list._stamp;
+               }
+
+               public void add (G item) {
+                       assert (this._stamp == this._list._stamp);
+                       assert (this.position != null);
+
+                       Node<G> n = new Node<G> (item);
+                       if (this.position.next != null) {
+                               this.position.next.prev = n;
+                               n.next = this.position.next;
+                       } else {
+                               this._list._tail = n;
+                       }
+                       this.position.next = n;
+                       n.prev = this.position;
+                       this.position = n;
+                       this._list._size++;
+                       this._index++;
+                       _stamp = _list._stamp;
+               }
+
+               public int index () {
+                       assert (this._stamp == this._list._stamp);
+                       assert (this.position != null);
+
+                       return this._index;
+               }
        }
 
        private unowned Node<G>? _get_node_at (int index) {
index d3221bb..eae18b1 100644 (file)
  */
 public interface Gee.List<G> : Collection<G> {
        /**
+        * Returns a ListIterator that can be used for iteration over this list.
+        *
+        * @return a ListIterator that can be used for iteration over this list
+        */
+       public abstract new ListIterator<G> list_iterator ();
+
+       /**
         * Returns the item at the specified index in this list.
         *
         * @param index zero-based index of the item to be returned
diff --git a/gee/listiterator.vala b/gee/listiterator.vala
new file mode 100644 (file)
index 0000000..34eb3e0
--- /dev/null
@@ -0,0 +1,50 @@
+/* listiterator.vala
+ *
+ * Copyright (C) 2009  Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+/**
+ * A list iterator. This supports bi-directionnal and index-based iteration.
+ */
+public interface Gee.ListIterator<G> : Gee.BidirIterator<G> {
+       /**
+        * Sets the current item in the iteration to the specified new item.
+        */
+       public abstract void set (G item);
+
+       /**
+        * Inserts the specified item before the current item in the iteration. The
+        * cursor is let to point to the current item.
+        */
+       public abstract void insert (G item);
+
+       /**
+        * Adds the specified item after the current item in the iteration. The
+        * cursor is moved to point to the new added item.
+        */
+       public abstract void add (G item);
+
+       /**
+        * Returns the current index in the iteration.
+        *
+        * @return the current index
+        */
+       public abstract int index ();
+}
index f29a790..ad85f59 100644 (file)
@@ -46,6 +46,13 @@ internal class Gee.ReadOnlyList<G> : Gee.ReadOnlyCollection<G>, List<G> {
        /**
         * @inheritDoc
         */
+       public ListIterator<G> list_iterator () {
+               return new Iterator<G> (((Gee.List<G>) _collection).list_iterator ());
+       }
+
+       /**
+        * @inheritDoc
+        */
        public int index_of (G item) {
                return ((Gee.List<G>) _collection).index_of (item);
        }
@@ -119,5 +126,40 @@ internal class Gee.ReadOnlyList<G> : Gee.ReadOnlyCollection<G>, List<G> {
        public virtual new List<G> read_only_view {
                owned get { return this; }
        }
+
+       
+       private class Iterator<G> : ReadOnlyCollection.Iterator<G>, BidirIterator<G>, ListIterator<G> {
+               public Iterator (ListIterator<G> iterator) {
+                       base (iterator);
+               }
+
+               public bool previous () {
+                       return ((ListIterator<G>) _iter).previous ();
+               }
+
+               public bool has_previous () {
+                       return ((ListIterator<G>) _iter).has_previous ();
+               }
+
+               public bool last () {
+                       return ((ListIterator<G>) _iter).last ();
+               }
+
+               public new void set (G item) {
+                       assert_not_reached ();
+               }
+
+               public void insert (G item) {
+                       assert_not_reached ();
+               }
+
+               public void add (G item) {
+                       assert_not_reached ();
+               }
+
+               public int index () {
+                       return ((ListIterator<G>) _iter).index ();
+               }
+       }
 }
 
index cd4b0ad..2d8d7a9 100644 (file)
@@ -31,6 +31,7 @@ public abstract class ListTests : CollectionTests {
        public ListTests (string name) {
                base (name);
                add_test ("[List] iterator is ordered", test_iterator_is_ordered);
+               add_test ("[List] list iterator", test_list_iterator);
                add_test ("[List] duplicates are retained",
                          test_duplicates_are_retained);
                add_test ("[List] get", test_get);
@@ -52,7 +53,7 @@ public abstract class ListTests : CollectionTests {
 
                // Check iterate empty list
                var iterator = test_list.iterator ();
-               assert (! iterator.next());
+               assert (! iterator.next ());
 
                // Check iterate list
                assert (test_list.add ("one"));
@@ -69,7 +70,81 @@ public abstract class ListTests : CollectionTests {
                assert (iterator.get () == "three");
                assert (iterator.next());
                assert (iterator.get () == "one");
-               assert (! iterator.next());
+               assert (! iterator.next ());
+       }
+
+       public void test_list_iterator () {
+               var test_list = test_collection as Gee.List<string>;
+
+               // Check the test list is not null
+               assert (test_list != null);
+
+               // Check iterate empty list
+               var iterator = test_list.list_iterator ();
+               assert (! iterator.has_next ());
+               assert (! iterator.next ());
+               assert (! iterator.has_previous ());
+               assert (! iterator.previous ());
+               assert (! iterator.first ());
+               assert (! iterator.last ());
+
+               // Check iterate list
+               assert (test_list.add ("one"));
+               assert (test_list.add ("two"));
+               assert (test_list.add ("three"));
+
+               iterator = test_list.list_iterator ();
+               assert (iterator.next());
+               assert (iterator.get () == "one");
+               assert (iterator.index () == 0);
+               iterator.set ("new one");
+               assert (iterator.next());
+               assert (iterator.get () == "two");
+               assert (iterator.index () == 1);
+               iterator.set ("new two");
+               assert (test_list.size == 3);
+               assert (iterator.index () == 1);
+               iterator.insert ("before two");
+               assert (test_list.size == 4);
+               assert (iterator.index () == 2);
+               iterator.add ("after two");
+               assert (test_list.size == 5);
+               assert (iterator.index () == 3);
+               assert (iterator.next());
+               assert (iterator.get () == "three");
+               assert (iterator.index () == 4);
+               iterator.set ("new three");
+               assert (! iterator.has_next ());
+               assert (! iterator.next ());
+
+               assert (iterator.first ());
+               assert (iterator.get () == "new one");
+               assert (iterator.index () == 0);
+               assert (! iterator.has_previous ());
+               assert (! iterator.previous ());
+
+               assert (iterator.last ());
+               assert (iterator.get () == "new three");
+               assert (iterator.index () == 4);
+               assert (! iterator.has_next ());
+               assert (! iterator.next ());
+
+               assert (iterator.has_previous ());
+               assert (iterator.previous ());
+               assert (iterator.get () == "after two");
+               assert (iterator.index () == 3);
+               assert (iterator.has_previous ());
+               assert (iterator.previous ());
+               assert (iterator.get () == "new two");
+               assert (iterator.index () == 2);
+               assert (iterator.has_previous ());
+               assert (iterator.previous ());
+               assert (iterator.get () == "before two");
+               assert (iterator.index () == 1);
+               assert (iterator.has_previous ());
+               assert (iterator.previous ());
+               assert (iterator.get () == "new one");
+               assert (iterator.index () == 0);
        }
 
        public virtual void test_duplicates_are_retained () {