Add SortedMap interface
authorMaciej Piechotka <uzytkownik2@gmail.com>
Mon, 28 Sep 2009 21:32:09 +0000 (23:32 +0200)
committerMaciej Piechotka <uzytkownik2@gmail.com>
Mon, 2 May 2011 10:45:25 +0000 (11:45 +0100)
gee/Makefile.am
gee/abstractsortedmap.vala [new file with mode: 0644]
gee/bidirmapiterator.vala [new file with mode: 0644]
gee/sortedmap.vala [new file with mode: 0644]
gee/treemap.vala
tests/Makefile.am
tests/testmap.vala
tests/testsortedmap.vala [new file with mode: 0644]
tests/testtreemap.vala

index dd69136..30f6c99 100644 (file)
@@ -14,6 +14,7 @@ libgee_la_SOURCES = \
        abstractset.vala \
        arraylist.vala \
        bidiriterator.vala \
+       bidirmapiterator.vala \
        collection.vala \
        comparable.vala \
        deque.vala \
@@ -39,6 +40,7 @@ libgee_la_SOURCES = \
        readonlymap.vala \
        readonlyset.vala \
        set.vala \
+       sortedmap.vala \
        sortedset.vala \
        timsort.vala \
        treemap.vala \
diff --git a/gee/abstractsortedmap.vala b/gee/abstractsortedmap.vala
new file mode 100644 (file)
index 0000000..20201f0
--- /dev/null
@@ -0,0 +1,68 @@
+/* readonlysortedmap.vala
+ *
+ * Copyright (C) 2009-2011  Maciej Piechotka
+ *
+ * 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:
+ *     Maciej Piechotka <uzytkownik2@gmail.com>
+ */
+
+public abstract class Gee.AbstractSortedMap<K, V> : AbstractMap<K,V>, SortedMap<K,V> {
+       /**
+        * {@inheritDoc}
+        */
+       public abstract SortedMap<K,V> head_map (K before);
+
+       /**
+        * {@inheritDoc}
+        */
+       public abstract SortedMap<K,V> tail_map (K after);
+
+       /**
+        * {@inheritDoc}
+        */
+       public abstract SortedMap<K,V> sub_map (K before, K after);
+
+       /**
+        * {@inheritDoc}
+        */
+       public abstract SortedSet<K> ascending_keys { owned get; }
+       /**
+        * {@inheritDoc}
+        */
+       public abstract SortedSet<Map.Entry<K,V>> ascending_entries { owned get; }
+       /**
+        * {@inheritDoc}
+        */
+       public abstract BidirMapIterator<K,V> bidir_map_iterator ();
+
+       private weak SortedMap<K,V> _read_only_view;
+       /**
+        * The read-only view this map.
+        */
+       public new SortedMap<K,V> read_only_view {
+               owned get {
+                       SortedMap<K,V> instance = _read_only_view;
+                       if (_read_only_view == null) {
+                               instance = new ReadOnlySortedMap<K,V> (this);
+                               _read_only_view = instance;
+                               instance.add_weak_pointer ((void**) (&_read_only_view));
+                       }
+                       return instance;
+               }
+       }
+}
+
diff --git a/gee/bidirmapiterator.vala b/gee/bidirmapiterator.vala
new file mode 100644 (file)
index 0000000..a0c1c1d
--- /dev/null
@@ -0,0 +1,55 @@
+/* bidiriterator.vala
+ *
+ * Copyright (C) 2009  Didier Villevalois, Maciej Piechotka
+ * Copyright (C) 2011  Maciej Piechotka
+ *
+ * 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:
+ *     Maciej Piechotka <uzytkownik2@gmail.com>
+ */
+
+/**
+ * A bi-directional Map iterator.
+ */
+public interface Gee.BidirMapIterator<K,V> : Gee.MapIterator<K,V> {
+       /**
+        * Rewinds to the previous element in the iteration.
+        *
+        * @return `true` if the iterator has a previous element
+        */
+       public abstract bool previous ();
+
+       /**
+        * Checks whether there is a previous element in the iteration.
+        *
+        * @return `true` if the iterator has a previous element
+        */
+       public abstract bool has_previous ();
+
+       /**
+        * Goes back to the first element.
+        *
+        * @return `true` if the iterator has a first element
+        */
+       public abstract bool first ();
+
+       /**
+        * Advances to the last element in the iteration.
+        *
+        * @return `true` if the iterator has a last element
+        */
+       public abstract bool last ();
+}
diff --git a/gee/sortedmap.vala b/gee/sortedmap.vala
new file mode 100644 (file)
index 0000000..c95bde0
--- /dev/null
@@ -0,0 +1,54 @@
+/* sortedset.vala
+ *
+ * Copyright (C) 2009-2011  Maciej Piechotka
+ *
+ * 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:
+ *     Maciej Piechotka <uzytkownik2@gmail.com>
+ */
+
+public interface Gee.SortedMap<K,V> : Gee.Map<K,V> {
+       /**
+        * Returns map containing pairs with key strictly lower the the argument.
+        */
+       public abstract SortedMap<K,V> head_map (K before);
+       /**
+        * Returns map containing pairs with key equal or larger then the argument.
+        */
+       public abstract SortedMap<K,V> tail_map (K after);
+       /**
+        * Returns right-open map (i.e. containing all pair which key is strictly
+        * lower then the second argument and equal or bigger then the first one).
+        *
+        * Null as one parameter means that it should include all from this side.
+        */
+       public abstract SortedMap<K,V> sub_map (K before, K after);
+       /**
+        * Returns the keys in ascending order.
+        */
+       public abstract SortedSet<K> ascending_keys { owned get; }
+       /**
+        * Returns the entries in ascending order.
+        */
+       public abstract SortedSet<Map.Entry<K,V>> ascending_entries { owned get; }
+       /**
+        * Returns a bi-directional iterator for this map.
+        *
+        * @return a bi-directional map iterator
+        */
+       public abstract BidirMapIterator<K,V> bidir_map_iterator ();
+}
+
index 563b450..d708202 100644 (file)
@@ -1,6 +1,6 @@
 /* treemap.vala
  *
- * Copyright (C) 2009  Maciej Piechotka
+ * Copyright (C) 2009-2011  Maciej Piechotka
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,7 +31,7 @@ using GLib;
  *
  * @see HashMap
  */
-public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
+public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V>, SortedMap<K,V> {
        /**
         * {@inheritDoc}
         */
@@ -48,7 +48,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
         */
        public override Set<K> keys {
                owned get {
-                       Set<K> keys = _keys;
+                       var keys = _keys;
                        if (_keys == null) {
                                keys = new KeySet<K,V> (this);
                                _keys = keys;
@@ -63,7 +63,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
         */
        public override Collection<V> values {
                owned get {
-                       Collection<K> values = _values;
+                       var values = _values;
                        if (_values == null) {
                                values = new ValueCollection<K,V> (this);
                                _values = values;
@@ -78,7 +78,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
         */
        public override Set<Map.Entry<K,V>> entries {
                owned get {
-                       Set<Map.Entry<K,V>> entries = _entries;
+                       var entries = _entries;
                        if (_entries == null) {
                                entries = new EntrySet<K,V> (this);
                                _entries = entries;
@@ -100,9 +100,9 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
 
        private int _size = 0;
 
-       private weak Set<K> _keys;
+       private weak SortedSet<K> _keys;
        private weak Collection<V> _values;
-       private weak Set<Map.Entry<K,V>> _entries;
+       private weak SortedSet<Map.Entry<K,V>> _entries;
 
        /**
         * Constructs a new, empty tree map sorted according to the specified
@@ -395,9 +395,66 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
        /**
         * {@inheritDoc}
         */
+       public SortedMap<K,V> head_map (K before) {
+               return new SubMap<K,V> (this, new Range<K,V>.head (this, before));
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public SortedMap<K,V> tail_map (K after) {
+               return new SubMap<K,V> (this, new Range<K,V>.tail (this, after));
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public SortedMap<K,V> sub_map (K after, K before) {
+               return new SubMap<K,V> (this, new Range<K,V> (this, after, before));
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public SortedSet<K> ascending_keys {
+               owned get {
+                       var keys = _keys;
+                       if (_keys == null) {
+                               keys = new KeySet<K,V> (this);
+                               _keys = keys;
+                               keys.add_weak_pointer (&_keys);
+                       }
+                       return keys;
+               }
+       }
+       /**
+        * @inheritDoc
+        */
+       public SortedSet<Map.Entry<K,V>> ascending_entries {
+               owned get {
+                       var entries = _entries;
+                       if (_entries == null) {
+                               entries = new EntrySet<K,V> (this);
+                               _entries = entries;
+                               entries.add_weak_pointer (&_entries);
+                       }
+                       return entries;
+               }
+       }
+       
+       /**
+        * @inheritDoc
+        */
        public override Gee.MapIterator<K,V> map_iterator () {
                return new MapIterator<K,V> (this);
        }
+       
+       /**
+        * @inheritDoc
+        */
+       public Gee.BidirMapIterator<K,V> bidir_map_iterator () {
+               return new MapIterator<K,V> (this);
+       }
 
        [Compact]
        private class Node<K, V> {
@@ -453,12 +510,54 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
        private weak Node<K, V>? last = null;
        private int stamp = 0;
 
+       private inline K min (K a, K b) {
+               return key_compare_func (a, b) <= 0 ? a : b;
+       }
+
+       private inline K max (K a, K b) {
+               return key_compare_func (a, b) > 0 ? a : b;
+       }
+
+       private inline unowned Node<K,V>? find_node (K key) {
+               unowned Node<K,V>? cur = root;
+               while (cur != null) {
+                       int res = key_compare_func (key, cur.key);
+                       if (res == 0) {
+                               return cur;
+                       } else if (res < 0) {
+                               cur = cur.left;
+                       } else {
+                               cur = cur.right;
+                       }
+               }
+               return null;
+       }
+
+       private inline unowned Node<K,V>? find_nearest (K key) {
+               unowned Node<K,V>? cur = root;
+               while (cur != null) {
+                       int res = key_compare_func (key, cur.key);
+                       if (res == 0) {
+                               return cur;
+                       } else if (res < 0) {
+                               if (cur.left == null)
+                                       return cur;
+                               cur = cur.left;
+                       } else {
+                               if (cur.right == null)
+                                       return cur;
+                               cur = cur.right;
+                       }
+               }
+               return null;
+       }
+
        private class Entry<K,V> : Map.Entry<K,V> {
                private unowned Node<K,V> _node;
 
                public static Map.Entry<K,V> entry_for<K,V> (Node<K,V> node) {
                        Map.Entry<K,V> result = node.entry;
-                       if (node.entry == null) {
+                       if (result == null) {
                                result = new Entry<K,V> (node);
                                node.entry = result;
                                result.add_weak_pointer ((void**) (&node.entry));
@@ -478,7 +577,308 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                }
        }
 
-       private class KeySet<K,V> : AbstractSet<K> {
+       private inline unowned Node<K,V>? find_lower (K key) {
+               unowned Node<K,V>? node = find_nearest (key);
+               if (node == null)
+                       return null;
+               return key_compare_func (key, node.key) <= 0 ? node.prev : node;
+       }
+
+       private inline unowned Node<K,V>? find_higher (K key) {
+               unowned Node<K,V>? node = find_nearest (key);
+               if (node == null)
+                       return null;
+               return key_compare_func (key, node.key) >= 0 ? node.next : node;
+       }
+
+       private inline unowned Node<K,V>? find_floor (K key) {
+               unowned Node<K,V>? node = find_nearest (key);
+               if (node == null)
+                       return null;
+               return key_compare_func (key, node.key) < 0 ? node.prev : node;
+       }
+
+       private inline unowned Node<K,V>? find_ceil (K key) {
+               unowned Node<K,V>? node = find_nearest (key);
+               if (node == null)
+                       return null;
+               return key_compare_func (key, node.key) > 0 ? node.next : node;
+       }
+
+       private inline K? lift_null_key (Node<K,V>? node) {
+               return node != null ? node.key : null;
+       }
+
+       private class Range<K,V> {
+               public Range (TreeMap<K,V> map, K after, K before) {
+                       this.map = map;
+                       if (map.key_compare_func (after, before) < 0) {
+                               this.after = after;
+                               this.before = before;
+                               type = RangeType.BOUNDED;
+                       } else {
+                               type = RangeType.EMPTY;
+                       }
+               }
+
+               public Range.head (TreeMap<K,V> map, K before) {
+                       this.map = map;
+                       this.before = before;
+                       type = RangeType.HEAD;
+               }
+
+               public Range.tail (TreeMap<K,V> map, K after) {
+                       this.map = map;
+                       this.after = after;
+                       type = RangeType.TAIL;
+               }
+
+               public Range.empty (TreeMap<K,V> map) {
+                       this.map = map;
+                       type = RangeType.EMPTY;
+               }
+
+               public Range<K,V> cut_head (K after) {
+                       switch (type) {
+                       case RangeType.HEAD:
+                               return new Range<K,V> (map, after, before);
+                       case RangeType.TAIL:
+                               return new Range<K,V>.tail (map, map.max (after, this.after));
+                       case RangeType.EMPTY:
+                               return this;
+                       case RangeType.BOUNDED:
+                               var _after = map.max (after, this.after);
+                               return new Range<K,V> (map, _after, before);
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public Range<K,V> cut_tail (K before) {
+                       switch (type) {
+                       case RangeType.HEAD:
+                               return new Range<K,V>.head (map, map.min (before, this.before));
+                       case RangeType.TAIL:
+                               return new Range<K,V> (map, after, before);
+                       case RangeType.EMPTY:
+                               return this;
+                       case RangeType.BOUNDED:
+                               var _before = map.min (before, this.before);
+                               return new Range<K,V> (map, after, _before);
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public Range<K,V> cut (K after, K before) {
+                       if (type == RangeType.EMPTY)
+                               return this;
+                       var _before = (type == RangeType.HEAD || type == RangeType.BOUNDED) ?
+                               map.min (before, this.before) : before;
+                       var _after = (type == RangeType.TAIL || type == RangeType.BOUNDED) ?
+                               map.max (after, this.after) : after;
+                       return new Range<K,V> (map, _after, _before);
+               }
+
+               public bool in_range (K key) {
+                       return type == RangeType.EMPTY ? false : compare_range(key) == 0;
+               }
+
+               public int compare_range (K key) {
+                       switch (type) {
+                       case RangeType.HEAD:
+                               return map.key_compare_func (key, before) < 0 ? 0 : 1;
+                       case RangeType.TAIL:
+                               return map.key_compare_func (key, after) >= 0 ? 0 : -1;
+                       case RangeType.EMPTY:
+                               return 0; // For simplicity - please make sure it does not break anything
+                       case RangeType.BOUNDED:
+                               return map.key_compare_func (key, after) >= 0 ?
+                                       (map.key_compare_func (key, before) < 0 ? 0 : 1) : -1;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public bool empty_submap () {
+                       switch (type) {
+                       case RangeType.HEAD:
+                               return map.first == null || !in_range (map.first.key);
+                       case RangeType.TAIL:
+                               return map.last == null || !in_range (map.last.key);
+                       case RangeType.EMPTY:
+                               return true;
+                       case RangeType.BOUNDED:
+                               return first () == null;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public unowned Node<K,V>? first () {
+                       switch (type) {
+                       case RangeType.EMPTY:
+                               return null;
+                       case RangeType.HEAD:
+                               return map.first;
+                       default:
+                               return map.find_floor (after);
+                       }
+               }
+
+               public unowned Node<K,V>? last () {
+                       switch (type) {
+                       case RangeType.EMPTY:
+                               return null;
+                       case RangeType.TAIL:
+                               return map.last;
+                       default:
+                               return map.find_lower (before);
+                       }
+               }
+
+               private new TreeMap<K,V> map;
+               private K after;
+               private K before;
+               private RangeType type;
+       }
+
+       private enum RangeType {
+               HEAD,
+               TAIL,
+               EMPTY,
+               BOUNDED
+       }
+
+       private class SubMap<K,V> : AbstractMap<K,V>, SortedMap<K,V> {
+               public override int size { get { return keys.size; } }
+               public override bool is_empty { get { return keys.is_empty; } }
+
+               public SubMap (TreeMap<K,V> map, Range<K,V> range) {
+                       this.map = map;
+                       this.range = range;
+               }
+
+               private weak SortedSet<K>? _keys;
+               public override Set<K> keys {
+                       owned get {
+                               var keys = _keys;
+                               if (_keys == null) {
+                                       keys = new SubKeySet<K,V> (map, range);
+                                       _keys = keys;
+                                       keys.add_weak_pointer(&_keys);
+                               }
+                               return keys;
+                       }
+               }
+
+               private weak Collection<K>? _values;
+               public override Collection<V> values {
+                       owned get {
+                               var values = _values;
+                               if (_values == null) {
+                                       values = new SubValueCollection<K,V> (map, range);
+                                       _values = values;
+                                       values.add_weak_pointer(&_values);
+                               }
+                               return values;
+                       }
+               }
+
+               private weak SortedSet<Entry<K,V>>? _entries;
+               public override Set<Entry<K,V>> entries {
+                       owned get {
+                               var entries = _entries;
+                               if (_entries == null) {
+                                       entries = new SubEntrySet<K,V> (map, range);
+                                       _entries = entries;
+                                       entries.add_weak_pointer(&_entries);
+                               }
+                               return entries;
+                       }
+               }
+
+               public override bool read_only {
+                       get {
+                               return true;
+                       }
+               }
+
+               public override bool has_key (K key) {
+                       return range.in_range (key) && map.has_key (key);
+               }
+
+               public override bool has (K key, V value) {
+                       return range.in_range (key) && map.has (key, value);
+               }
+
+               public override new V? get (K key) {
+                       return range.in_range (key) ? map.get (key) : null;
+               }
+
+               public override void set (K key, V value) {
+                       if (range.in_range (key))
+                               map.set (key, value);
+               }
+
+               public override bool unset (K key, out V? value = null) {
+                       return range.in_range (key) && map.unset (key, out value);
+               }
+
+               public override void clear () {
+                       for (var iterator = map_iterator (); iterator.next ();)
+                               iterator.unset ();
+               }
+               
+               public override Gee.MapIterator<K,V> map_iterator () {
+                       return new SubMapIterator<K,V> (map, range);
+               }
+               
+               public BidirMapIterator<K,V> bidir_map_iterator () {
+                       return new SubMapIterator<K,V> (map, range);
+               }
+
+               public SortedMap<K,V> head_map (K before) {
+                       return new SubMap<K,V> (map, range.cut_tail (before));
+               }
+
+               public SortedMap<K,V> tail_map (K after) {
+                       return new SubMap<K,V> (map, range.cut_head (after));
+               }
+
+               public SortedMap<K,V> sub_map (K after, K before) {
+                       return new SubMap<K,V> (map, range.cut (after, before));
+               }
+
+               public SortedSet<K> ascending_keys {
+                       owned get {
+                               var keys = _keys;
+                               if (_keys == null) {
+                                       keys = new SubKeySet<K,V> (map, range);
+                                       _keys = keys;
+                                       keys.add_weak_pointer(&_keys);
+                               }
+                               return keys;
+                       }
+               }
+
+               public SortedSet<K> ascending_entries {
+                       owned get {
+                               var entries = _entries;
+                               if (_entries == null) {
+                                       entries = new SubEntrySet<K,V> (map, range);
+                                       _entries = entries;
+                                       entries.add_weak_pointer(&_entries);
+                               }
+                               return _entries;
+                       }
+               }
+
+               private TreeMap<K,V> map;
+               private Range<K,V> range;
+       }
+
+       private class KeySet<K,V> : AbstractSet<K>, SortedSet<K> {
                private TreeMap<K,V> _map;
 
                public KeySet (TreeMap<K,V> map) {
@@ -513,17 +913,171 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                        return _map.has_key (key);
                }
 
-               public override bool add_all (Collection<K> collection) {
+               public K first () {
+                       assert (_map.first != null);
+                       return _map.first.key;
+               }
+
+               public K last () {
+                       assert (_map.last != null);
+                       return _map.last.key;
+               }
+
+               public BidirIterator<K> bidir_iterator () {
+                       return new KeyIterator<K,V> (_map);
+               }
+
+               public SortedSet<K> head_set (K before) {
+                       return new SubKeySet<K,V> (_map, new Range<K,V>.head (_map, before));
+               }
+
+               public SortedSet<K> tail_set (K after) {
+                       return new SubKeySet<K,V> (_map, new Range<K,V>.tail (_map, after));
+               }
+
+               public SortedSet<K> sub_set (K after, K before) {
+                       return new SubKeySet<K,V> (_map, new Range<K,V> (_map, after, before));
+               }
+
+               public BidirIterator<K>? iterator_at (K item) {
+                       weak Node<K,V>? node = _map.find_node (item);
+                       if (node == null)
+                               return null;
+                       return new KeyIterator<K,V>.pointing (_map, node);
+               }
+
+               public K? lower (K item) {
+                       return _map.lift_null_key (_map.find_lower (item));
+               }
+
+               public K? higher (K item) {
+                       return _map.lift_null_key (_map.find_higher (item));
+               }
+
+               public K? floor (K item) {
+                       return _map.lift_null_key (_map.find_floor (item));
+               }
+
+               public K? ceil (K item) {
+                       return _map.lift_null_key (_map.find_ceil (item));
+               }
+       }
+
+       private class SubKeySet<K,V> : AbstractSet<K>, SortedSet<K> {
+               public TreeMap<K,V> map { private set; get; }
+               public Range<K,V> range { private set; get; }
+
+               public SubKeySet (TreeMap<K,V> map, Range<K,V> range) {
+                       this.map = map;
+                       this.range = range;
+               }
+
+               public override Iterator<K> iterator () {
+                       return new SubKeyIterator<K,V> (map, range);
+               }
+
+               public override int size {
+                       get {
+                               var i = 0;
+                               Gee.Iterator<K> iterator = iterator ();
+                               while (iterator.next ())
+                                       i++;
+                               return i;
+                       }
+               }
+
+               public override bool read_only {
+                       get {
+                               return true;
+                       }
+               }
+
+               public override bool is_empty { get { return range.empty_submap (); } }
+
+               public override bool add (K key) {
                        assert_not_reached ();
                }
 
-               public override bool remove_all (Collection<K> collection) {
+               public override void clear () {
                        assert_not_reached ();
                }
 
-               public override bool retain_all (Collection<K> collection) {
+               public override bool remove (K key) {
                        assert_not_reached ();
                }
+
+               public override bool contains (K key) {
+                       return range.in_range(key) && map.has_key (key);
+               }
+
+               public BidirIterator<K> bidir_iterator () {
+                       return new SubKeyIterator<K,V> (map, range);
+               }
+
+               public K first () {
+                       weak Node<K,V>? _first = range.first ();
+                       assert (_first != null);
+                       return _first.key;
+               }
+
+               public K last () {
+                       weak Node<K,V>? _last = range.last ();
+                       assert (_last != null);
+                       return _last.key;
+               }
+
+               public SortedSet<K> head_set (K before) {
+                       return new SubKeySet<K,V> (map, range.cut_tail (before));
+               }
+
+               public SortedSet<K> tail_set (K after) {
+                       return new SubKeySet<K,V> (map, range.cut_head (after));
+               }
+
+               public SortedSet<K> sub_set (K after, K before) {
+                       return new SubKeySet<K,V> (map, range.cut (after, before));
+               }
+
+               public BidirIterator<K>? iterator_at (K key) {
+                       if (!range.in_range (key))
+                               return null;
+                       weak Node<K,V>? n = map.find_node (key);
+                       if (n == null)
+                               return null;
+                       return new SubKeyIterator<K,V>.pointing (map, range, n);
+               }
+
+               public K? lower (K key) {
+                       var res = range.compare_range (key);
+                       if (res > 0)
+                               return last ();
+                       var l = map.lift_null_key (map.find_lower (key));
+                       return l != null && range.in_range (l) ? l : null;
+               }
+
+               public K? higher (K key) {
+                       var res = range.compare_range (key);
+                       if (res < 0)
+                               return first ();
+                       var h = map.lift_null_key (map.find_higher (key));
+                       return h != null && range.in_range (h) ? h : null;
+               }
+
+               public K? floor (K key) {
+                       var res = range.compare_range (key);
+                       if (res > 0)
+                               return last ();
+                       var l = map.lift_null_key (map.find_floor (key));
+                       return l != null && range.in_range (l) ? l : null;
+               }
+
+               public K? ceil (K key) {
+                       var res = range.compare_range (key);
+                       if (res < 0)
+                               return first ();
+                       var h = map.lift_null_key (map.find_ceil (key));
+                       return h != null && range.in_range (h) ? h : null;
+               }
        }
 
        private class ValueCollection<K,V> : AbstractCollection<V> {
@@ -566,21 +1120,63 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                        }
                        return false;
                }
+       }
+
+       private class SubValueCollection<K,V> : AbstractCollection<V> {
+               public TreeMap<K,V> map { private set; get; }
+               public Range<K,V> range { private set; get; }
+
+               public SubValueCollection (TreeMap<K,V> map, Range<K,V> range) {
+                       this.map = map;
+                       this.range = range;
+               }
+
+               public override Iterator<V> iterator () {
+                       return new SubValueIterator<K,V> (map, range);
+               }
+
+               public override bool read_only {
+                       get {
+                               return true;
+                       }
+               }
+
+               public override int size {
+                       get {
+                               var i = 0;
+                               Gee.Iterator<V> iterator = iterator ();
+                               while (iterator.next ())
+                                       i++;
+                               return i;
+                       }
+               }
+
+               public override bool is_empty { get { return range.empty_submap (); } }
 
-               public override bool add_all (Collection<V> collection) {
+               public override bool add (V key) {
                        assert_not_reached ();
                }
 
-               public override bool remove_all (Collection<V> collection) {
+               public override void clear () {
                        assert_not_reached ();
                }
 
-               public override bool retain_all (Collection<V> collection) {
+               public override bool remove (V key) {
                        assert_not_reached ();
                }
+
+               public override bool contains (V key) {
+                       Iterator<V> it = iterator ();
+                       while (it.next ()) {
+                               if (map.value_equal_func (key, it.get ())) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
        }
 
-       private class EntrySet<K,V> : AbstractSet<Map.Entry<K, V>> {
+       private class EntrySet<K,V> : AbstractSet<Map.Entry<K, V>>, SortedSet<Map.Entry<K, V>> {
                private TreeMap<K,V> _map;
 
                public EntrySet (TreeMap<K,V> map) {
@@ -615,32 +1211,198 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                        return _map.has (entry.key, entry.value);
                }
 
-               public override bool add_all (Collection<Map.Entry<K, V>> entries) {
+               public Map.Entry<K, V>/*?*/ first () {
+                       assert (_map.first != null);
+                       return Entry.entry_for<K,V> (_map.first);
+               }
+
+               public Map.Entry<K, V>/*?*/ last () {
+                       assert (_map.last != null);
+                       return Entry.entry_for<K,V> (_map.last);
+               }
+
+               public BidirIterator<Map.Entry<K, V>> bidir_iterator () {
+                       return new EntryIterator<K,V> (_map);
+               }
+
+               public SortedSet<Map.Entry<K, V>> head_set (Map.Entry<K, V> before) {
+                       return new SubEntrySet<K,V> (_map, new Range<K,V>.head (_map, before.key));
+               }
+
+               public SortedSet<Map.Entry<K, V>> tail_set (Map.Entry<K, V> after) {
+                       return new SubEntrySet<K,V> (_map, new Range<K,V>.tail (_map, after.key));
+               }
+
+               public SortedSet<K> sub_set (Map.Entry<K, V> after, Map.Entry<K, V> before) {
+                       return new SubEntrySet<K,V> (_map, new Range<K,V> (_map, after.key, before.key));
+               }
+
+               public BidirIterator<Map.Entry<K, V>>? iterator_at (Map.Entry<K, V> item) {
+                       weak Node<K,V>? node = _map.find_node (item.key);
+                       if (node == null || !_map.value_equal_func (node.value, item.value))
+                               return null;
+                       return new EntryIterator<K,V>.pointing (_map, node);
+               }
+
+               public Map.Entry<K, V>/*?*/ lower (Map.Entry<K, V> item) {
+                       weak Node<K,V>? l = _map.find_lower (item.key);
+                       return l != null ? Entry.entry_for<K,V> (l) : null;
+               }
+
+               public Map.Entry<K, V>/*?*/ higher (Map.Entry<K, V> item) {
+                       weak Node<K,V>? l = _map.find_higher (item.key);
+                       return l != null ? Entry.entry_for<K,V> (l) : null;
+               }
+
+               public Map.Entry<K, V>/*?*/ floor (Map.Entry<K, V> item) {
+                       weak Node<K,V>? l = _map.find_floor (item.key);
+                       return l != null ? Entry.entry_for<K,V> (l) : null;
+               }
+
+               public Map.Entry<K, V>/*?*/ ceil (Map.Entry<K, V> item) {
+                       weak Node<K,V>? l = _map.find_ceil (item.key);
+                       return l != null ? Entry.entry_for<K,V> (l) : null;
+               }
+       }
+
+       private class SubEntrySet<K,V> : AbstractSet<Map.Entry<K,V>>, SortedSet<Map.Entry<K,V>> {
+               public TreeMap<K,V> map { private set; get; }
+               public Range<K,V> range { private set; get; }
+
+               public SubEntrySet (TreeMap<K,V> map, Range<K,V> range) {
+                       this.map = map;
+                       this.range = range;
+               }
+
+               public override Iterator<Map.Entry<K,V>> iterator () {
+                       return new SubEntryIterator<K,V> (map, range);
+               }
+
+               public override int size {
+                       get {
+                               var i = 0;
+                               Gee.Iterator<Map.Entry<K,V>> iterator = iterator ();
+                               while (iterator.next ())
+                                       i++;
+                               return i;
+                       }
+               }
+
+               public override bool read_only {
+                       get {
+                               return true;
+                       }
+               }
+
+               public override bool is_empty { get { return range.empty_submap (); } }
+
+               public override bool add (Map.Entry<K,V> entry) {
                        assert_not_reached ();
                }
 
-               public override bool remove_all (Collection<Map.Entry<K, V>> entries) {
+               public override void clear () {
                        assert_not_reached ();
                }
 
-               public override bool retain_all (Collection<Map.Entry<K, V>> entries) {
+               public override bool remove (Map.Entry<K,V> entry) {
                        assert_not_reached ();
                }
+
+               public override bool contains (Map.Entry<K,V> entry) {
+                       return range.in_range(entry.key) && map.has (entry.key, entry.value);
+               }
+
+               public BidirIterator<K> bidir_iterator () {
+                       return new SubEntryIterator<K,V> (map, range);
+               }
+
+               public Map.Entry<K,V> first () {
+                       weak Node<K,V>? _first = range.first ();
+                       assert (_first != null);
+                       return Entry.entry_for<K,V> (_first);
+               }
+
+               public Map.Entry<K,V> last () {
+                       weak Node<K,V>? _last = range.last ();
+                       assert (_last != null);
+                       return Entry.entry_for<K,V> (_last);
+               }
+
+               public SortedSet<K> head_set (Map.Entry<K,V> before) {
+                       return new SubEntrySet<K,V> (map, range.cut_tail (before.key));
+               }
+
+               public SortedSet<K> tail_set (Map.Entry<K,V> after) {
+                       return new SubEntrySet<K,V> (map, range.cut_head (after.key));
+               }
+
+               public SortedSet<K> sub_set (Map.Entry<K,V> after, Map.Entry<K,V> before) {
+                       return new SubEntrySet<K,V> (map, range.cut (after.key, before.key));
+               }
+
+               public BidirIterator<Map.Entry<K,V>>? iterator_at (Map.Entry<K,V> entry) {
+                       if (!range.in_range (entry.key))
+                               return null;
+                       weak Node<K,V>? n = map.find_node (entry.key);
+                       if (n == null || !map.value_equal_func (n.value, entry.value))
+                               return null;
+                       return new SubEntryIterator<K,V>.pointing (map, range, n);
+               }
+
+               public Map.Entry<K,V>/*?*/ lower (Map.Entry<K,V> entry) {
+                       var res = range.compare_range (entry.key);
+                       if (res > 0)
+                               return last ();
+                       weak Node<K,V>? l = map.find_lower (entry.key);
+                       return l != null && range.in_range (l.key) ? Entry.entry_for<K,V> (l) : null;
+               }
+
+               public Map.Entry<K,V>/*?*/ higher (Map.Entry<K,V> entry) {
+                       var res = range.compare_range (entry.key);
+                       if (res < 0)
+                               return first ();
+                       weak Node<K,V>? h = map.find_higher (entry.key);
+                       return h != null && range.in_range (h.key) ? Entry.entry_for<K,V> (h) : null;
+               }
+
+               public Map.Entry<K,V>/*?*/ floor (Map.Entry<K,V> entry) {
+                       var res = range.compare_range (entry.key);
+                       if (res > 0)
+                               return last ();
+                       weak Node<K,V>? l = map.find_floor (entry.key);
+                       return l != null && range.in_range (l.key) ? Entry.entry_for<K,V> (l) : null;
+               }
+
+               public Map.Entry<K,V>/*?*/ ceil (Map.Entry<K,V> entry) {
+                       var res = range.compare_range (entry.key);
+                       if (res < 0)
+                               return first ();
+                       weak Node<K,V>? h = map.find_ceil (entry.key);
+                       return h != null && range.in_range (h.key) ? Entry.entry_for<K,V> (h) : null;
+               }
        }
 
-       private class NodeIterator<K,V> : Object {
+       private class NodeIterator<K, V> : Object {
                protected TreeMap<K,V> _map;
-
+               
                // concurrent modification protection
                protected int stamp;
-
-               protected weak Node<K, V>? current;
+               
+               protected bool started = false;
+               
+               internal weak Node<K, V>? current;
                protected weak Node<K, V>? _next;
                protected weak Node<K, V>? _prev;
 
                public NodeIterator (TreeMap<K,V> map) {
                        _map = map;
+                       this.stamp = _map.stamp;
+               }
+
+               public NodeIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+                       _map = map;
                        stamp = _map.stamp;
+                       this.current = current;
                }
 
                public bool next () {
@@ -654,6 +1416,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                                }
                        } else if (_next == null && _prev == null) {
                                current = _map.first;
+                               started = true;
                                return current != null;
                        } else {
                                current = _next;
@@ -670,7 +1433,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                        return (current == null && _next == null && _prev == null && _map.first != null) ||
                               (current == null && _next != null) ||
                               (current != null && current.next != null);
-               }
+               }
 
                public bool first () {
                        assert (stamp == _map.stamp);
@@ -718,7 +1481,7 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                public void remove () {
                        assert_not_reached ();
                }
-               
+
                public void unset () {
                        assert (stamp == _map.stamp);
                        assert (current != null);
@@ -744,13 +1507,126 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                                return current != null;
                        }
                }
+
+               internal unowned Node<K,V>? safe_next_get () {
+                       return (current != null) ? current.next : _next;
+               }
+
+               internal unowned Node<K,V>? safe_previous_get () {
+                       return (current != null) ? current.prev : _prev;
+               }
+       }
+
+       private class SubNodeIterator<K,V> : Object {
+               public SubNodeIterator (TreeMap<K,V> map, Range<K,V> range) {
+                       _map = map;
+                       this.range = range;
+               }
+
+               public SubNodeIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+                       _map = map;
+                       this.range = range;
+                       this.iterator = new NodeIterator<K,V>.pointing (_map, node);
+               }
+
+               public bool next () {
+                       if (iterator != null) {
+                               weak Node<K,V>? node= iterator.safe_next_get ();
+                               if (node != null && range.in_range (node.key)) {
+                                       assert (iterator.next ());
+                                       return true;
+                               } else {
+                                       return false;
+                               }
+                       } else {
+                               return first ();
+                       }
+               }
+
+               public bool has_next () {
+                       if (iterator != null) {
+                               weak Node<K,V>? node = iterator.safe_next_get ();
+                               return node != null && range.in_range (node.key);
+                       } else {
+                               return range.first () != null;
+                       }
+               }
+
+               public virtual bool first () {
+                       weak Node<K,V>? node = range.first ();
+                       if (node == null)
+                               return false;
+                       iterator = iterator_pointing_at (node);
+                       return true;
+               }
+
+               public bool previous () {
+                       if (iterator == null)
+                               return false;
+                       weak Node<K,V>? node;
+                       if ((node = iterator.safe_previous_get ()) != null && range.in_range (node.key)) {
+                               assert (iterator.previous ());
+                               return true;
+                       } else {
+                               return false;
+                       }
+               }
+
+               public bool has_previous () {
+                       if (iterator == null)
+                               return false;
+                       weak Node<K,V>? node;
+                       return (node = iterator.safe_previous_get ()) != null && range.in_range (node.key);
+               }
+
+               public virtual bool last () {
+                       weak Node<K,V>? node = range.last ();
+                       if (node == null)
+                               return false;
+                       iterator = iterator_pointing_at (node);
+                       return true;
+               }
+
+               public void remove () {
+                       assert (valid);
+                       iterator.remove ();
+               }
+
+               public void unset () {
+                       assert (valid);
+                       iterator.unset ();
+               }
+               
+               public virtual bool read_only {
+                       get {
+                               return true;
+                       }
+               }
+
+               public bool valid {
+                       get {
+                               return iterator != null && iterator.valid;
+                       }
+               }
+               
+               protected virtual NodeIterator<K,V> iterator_pointing_at (Node<K,V> node) {
+                       return new NodeIterator<K,V>.pointing (_map, node);
+               }
+
+               protected new TreeMap<K,V> _map;
+               protected Range<K,V> range;
+               protected NodeIterator<K,V>? iterator = null;
        }
 
-       private class KeyIterator<K,V> : NodeIterator<K,V>, Gee.Iterator<K>, BidirIterator<K> {
+       private class KeyIterator<K,V> : NodeIterator<K, V>, Gee.Iterator<K>, BidirIterator<K> {
                public KeyIterator (TreeMap<K,V> map) {
                        base (map);
                }
 
+               public KeyIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+                       base.pointing (map, current);
+               }
+
                public new K get () {
                        assert (stamp == _map.stamp);
                        assert (current != null);
@@ -758,50 +1634,111 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                }
        }
 
+       private class SubKeyIterator<K,V> : SubNodeIterator<K,V>, Gee.Iterator<K>, BidirIterator<K> {
+               public SubKeyIterator (TreeMap<K,V> map, Range<K,V> range) {
+                       base (map, range);
+               }
+
+               public SubKeyIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+                       base.pointing (map, range, node);
+               }
+
+               public new K get () {
+                       assert (valid);
+                       return iterator.current.key;
+               }
+       }
+
        private class ValueIterator<K,V> : NodeIterator<K,V>, Gee.Iterator<V>, Gee.BidirIterator<V> {
                public ValueIterator (TreeMap<K,V> map) {
                        base (map);
                }
 
+               public ValueIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+                       base.pointing (map, current);
+               }
+
                public new V get () {
                        assert (stamp == _map.stamp);
-                       assert (current != null);
+                       assert (valid);
                        return current.value;
                }
        }
 
+       private class SubValueIterator<K,V> : SubNodeIterator<K,V>, Gee.Iterator<K>, BidirIterator<K> {
+               public SubValueIterator (TreeMap<K,V> map, Range<K,V> range) {
+                       base (map, range);
+               }
+
+               public SubValueIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+                       base.pointing (map, range, node);
+               }
+
+               public new V get () {
+                       assert (valid);
+                       return iterator.current.value;
+               }
+       }
+
        private class EntryIterator<K,V> : NodeIterator<K,V>, Gee.Iterator<Map.Entry<K,V>>, Gee.BidirIterator<Map.Entry<K,V>> {
                public EntryIterator (TreeMap<K,V> map) {
                        base (map);
                }
 
+               public EntryIterator.pointing (TreeMap<K,V> map, Node<K,V> node) {
+                       base.pointing (map, node);
+               }
+
                public new Map.Entry<K,V> get () {
                        assert (stamp == _map.stamp);
-                       assert (current != null);
-                       return Entry<K,V>.entry_for<K,V> (current);
+                       assert (valid);
+                       return Entry.entry_for<K,V> (current);
+               }
+
+               public new void remove () {
+                       unset ();
                }
        }
 
-       private class MapIterator<K,V> : NodeIterator<K,V>, Gee.MapIterator<K,V> {
+       private class SubEntryIterator<K,V> : SubNodeIterator<K,V>, Gee.Iterator<Map.Entry<K,V>>, Gee.BidirIterator<Map.Entry<K,V>> {
+               public SubEntryIterator (TreeMap<K,V> map, Range<K,V> range) {
+                       base (map, range);
+               }
+
+               public SubEntryIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+                       base.pointing (map, range, node);
+               }
+
+               public new Map.Entry<K,V> get () {
+                       assert (iterator != null);
+                       return Entry.entry_for<K,V> (iterator.current);
+               }
+
+               public new void remove () {
+                       unset ();
+               }
+       }
+       
+       private class MapIterator<K,V> : NodeIterator<K,V>, Gee.MapIterator<K,V>, BidirMapIterator<K,V> {
                public MapIterator (TreeMap<K,V> map) {
                        base (map);
                }
 
                public K get_key () {
                        assert (stamp == _map.stamp);
-                       assert (current != null);
+                       assert (valid);
                        return current.key;
                }
 
                public V get_value () {
                        assert (stamp == _map.stamp);
-                       assert (current != null);
+                       assert (valid);
                        return current.value;
                }
 
                public void set_value (V value) {
                        assert (stamp == _map.stamp);
-                       assert (current != null);
+                       assert (valid);
                        current.value = value;
                }
                
@@ -817,4 +1754,37 @@ public class Gee.TreeMap<K,V> : Gee.AbstractMap<K,V> {
                        }
                }
        }
+       
+       private class SubMapIterator<K,V> : SubNodeIterator<K,V>, Gee.MapIterator<K,V>, BidirMapIterator<K,V> {
+               public SubMapIterator (TreeMap<K,V> map, Range<K,V> range) {
+                       base (map, range);
+               }
+
+               public K get_key () {
+                       assert (valid);
+                       return iterator.current.key;
+               }
+
+               public V get_value () {
+                       assert (valid);
+                       return iterator.current.value;
+               }
+
+               public void set_value (V value) {
+                       assert (valid);
+                       iterator.current.value = value;
+               }
+               
+               public override bool read_only {
+                       get {
+                               return false;
+                       }
+               }
+               
+               public bool mutable {
+                       get {
+                               return true;
+                       }
+               }
+       }
 }
index d6c1bcb..5142745 100644 (file)
@@ -29,6 +29,7 @@ tests_SOURCES = \
        testreadonlyset.vala \
        testset.vala \
        testsortedset.vala \
+       testsortedmap.vala \
        testtreemap.vala \
        testtreemultimap.vala \
        testtreemultiset.vala \
index 81dd4a3..009f091 100644 (file)
@@ -529,7 +529,7 @@ public abstract class MapTests : Gee.TestCase {
                assert (value.get_int () == test_map.size);
                value.unset ();
        }
-       
+
        public void test_fold () {
                test_map.set ("one", "one");
                test_map.set ("two", "two");
@@ -562,16 +562,28 @@ public abstract class MapTests : Gee.TestCase {
                assert (count == 6);
        }
 
-
-
-       public class TestEntry<K,V> : Map.Entry<K,V> {
+       public static Map.Entry<string,string> entry_for (string key, string value) {
+               return new TestEntry<string,string> (key, value);
+       }
+       
+       public static bool check_entry (owned Map.Entry<string,string> e, string key, string value) {
+               return e.key == key && e.value == value;
+       }
+       
+       public static void assert_entry (Map.Entry<string,string> e, string key, string value) {
+               assert (e.key == key);
+               assert (e.value == value);
+       }
+       
+       private class TestEntry<K,V> : Map.Entry<K,V> {
                public TestEntry (K key, V value) {
                        this._key = key;
                        this.value = value;
                }
-
+               
                public override K key { get {return _key; } }
                private K _key;
                public override V value { get; set; }
        }
 }
+
diff --git a/tests/testsortedmap.vala b/tests/testsortedmap.vala
new file mode 100644 (file)
index 0000000..8fcbc40
--- /dev/null
@@ -0,0 +1,1424 @@
+/* sortedset.vala
+ *
+ * Copyright (C) 2009-2011  Maciej Piechotka
+ *
+ * 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:
+ *     Maciej Piechotka <uzytkownik2@gmail.com>
+ */
+
+public abstract class Gee.SortedMapTests : MapTests {
+       public SortedMapTests (string name) {
+               base (name);
+               add_test ("[SortedMap] key ordering", test_key_ordering);
+               add_test ("[SortedMap] first", test_first);
+               add_test ("[SortedMap] last", test_last);
+               add_test ("[SortedMap] iterator_at", test_iterator_at);
+               add_test ("[SortedMap] lower", test_lower);
+               add_test ("[SortedMap] higher", test_higher);
+               add_test ("[SortedMap] floor", test_floor);
+               add_test ("[SortedMap] ceil", test_ceil);
+               add_test ("[SortedMap] bi-directional iterators can go backward",
+                         test_bidir_iterator_can_go_backward);
+               add_test ("[SortedSet] bi-directional iterators can to end",
+                         test_bidir_iterator_last);
+               get_suite ().add_suite (new SubMap (this, SubMap.Type.HEAD).get_suite ());
+               get_suite ().add_suite (new SubMap (this, SubMap.Type.TAIL).get_suite ());
+               get_suite ().add_suite (new SubMap (this, SubMap.Type.SUB).get_suite ());
+               get_suite ().add_suite (new SubMap (this, SubMap.Type.EMPTY).get_suite ());
+       }
+
+       public void test_key_ordering () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+
+               // Check the map exists
+               assert (test_sorted_map != null);
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+               test_sorted_map.set ("seven", "seven");
+               test_sorted_map.set ("eight", "eight");
+               test_sorted_map.set ("nine", "nine");
+               test_sorted_map.set ("ten", "ten");
+               test_sorted_map.set ("eleven", "eleven");
+               test_sorted_map.set ("twelve", "twelve");
+
+               Iterator<string> iterator = test_sorted_map.keys.iterator ();
+               assert (iterator.next ());
+               assert (iterator.get () == "eight");
+               assert (iterator.next ());
+               assert (iterator.get () == "eleven");
+               assert (iterator.next ());
+               assert (iterator.get () == "five");
+               assert (iterator.next ());
+               assert (iterator.get () == "four");
+               assert (iterator.next ());
+               assert (iterator.get () == "nine");
+               assert (iterator.next ());
+               assert (iterator.get () == "one");
+               assert (iterator.next ());
+               assert (iterator.get () == "seven");
+               assert (iterator.next ());
+               assert (iterator.get () == "six");
+               assert (iterator.next ());
+               assert (iterator.get () == "ten");
+               assert (iterator.next ());
+               assert (iterator.get () == "three");
+               assert (iterator.next ());
+               assert (iterator.get () == "twelve");
+               assert (iterator.next ());
+               assert (iterator.get () == "two");
+               assert (iterator.next () == false);
+       }
+       
+       public void test_first () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               // Check the map exists
+               assert (test_sorted_map != null);
+               
+               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                      TestTrapFlags.SILENCE_STDERR)) {
+                       keys.first ();
+                       Posix.exit (0);
+               }
+               Test.trap_assert_failed ();
+
+               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                      TestTrapFlags.SILENCE_STDERR)) {
+                       entries.first ();
+                       Posix.exit (0);
+               }
+               Test.trap_assert_failed ();
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+               test_sorted_map.set ("seven", "seven");
+               test_sorted_map.set ("eight", "eight");
+               test_sorted_map.set ("nine", "nine");
+               test_sorted_map.set ("ten", "ten");
+               test_sorted_map.set ("eleven", "eleven");
+               test_sorted_map.set ("twelve", "twelve");
+               
+               assert (keys.first () == "eight");
+               /*assert_entry (entries.first (), "eight", "eight");*/
+       }
+       
+       public void test_last () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+               // Check the map exists
+               assert (test_sorted_map != null);
+               
+               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                      TestTrapFlags.SILENCE_STDERR)) {
+                       keys.last ();
+                       Posix.exit (0);
+               }
+               Test.trap_assert_failed ();
+
+               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                      TestTrapFlags.SILENCE_STDERR)) {
+                       entries.last ();
+                       Posix.exit (0);
+               }
+               Test.trap_assert_failed ();
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+               test_sorted_map.set ("seven", "seven");
+               test_sorted_map.set ("eight", "eight");
+               test_sorted_map.set ("nine", "nine");
+               test_sorted_map.set ("ten", "ten");
+               test_sorted_map.set ("eleven", "eleven");
+               test_sorted_map.set ("twelve", "twelve");
+               
+               assert (keys.last () == "two");
+               assert_entry (entries.last (), "two", "two");
+       }
+
+       public void test_iterator_at () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               test_map.set ("one", "one");
+               test_map.set ("two", "two");
+               test_map.set ("three", "three");
+
+               var keys_iter = keys.iterator_at ("one");
+               assert (keys_iter != null);
+               assert (keys_iter.get () == "one");
+
+               var entries_iter = entries.iterator_at (entry_for ("one", "one"));
+               assert (entries_iter != null);
+               assert_entry (entries_iter.get (), "one", "one");
+
+               keys_iter = keys.iterator_at ("two");
+               assert (keys_iter != null);
+               assert (keys_iter.get () == "two");
+
+               entries_iter = entries.iterator_at (entry_for ("two", "two"));
+               assert (entries_iter != null);
+               assert_entry (entries_iter.get (), "two", "two");
+
+               keys_iter = keys.iterator_at ("three");
+               assert (keys_iter != null);
+               assert (keys_iter.get () == "three");
+
+               entries_iter = entries.iterator_at (entry_for ("three", "three"));
+               assert (entries_iter != null);
+               assert_entry (entries_iter.get (), "three", "three");
+
+               keys_iter = keys.iterator_at ("zero");
+               assert (keys_iter == null);
+
+               entries_iter = entries.iterator_at (entry_for ("zero", "zero"));
+               assert (entries_iter == null);
+       }
+       
+       public void test_lower () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               assert (keys.lower ("one") == null);
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               assert (keys.lower ("one") == "four");
+               assert_entry (entries.lower (entry_for ("one", "one")), "four", "four");
+
+               assert (keys.lower ("o") == "four");
+               assert_entry (entries.lower (entry_for ("o", "one")), "four", "four");
+
+               assert (keys.lower ("two") == "three");
+               assert_entry (entries.lower (entry_for ("two", "two")), "three", "three");
+
+               assert (keys.lower ("t") == "six");
+               assert_entry (entries.lower (entry_for ("t", "two")), "six", "six");
+
+               assert (keys.lower ("three") == "six");
+               assert_entry (entries.lower (entry_for ("three", "three")), "six", "six");
+
+               assert (keys.lower ("four") == "five");
+               assert_entry (entries.lower (entry_for ("four", "four")), "five", "five");
+
+               assert (keys.lower ("f") == null);
+               assert (entries.lower (entry_for ("f", "four")) == null);
+
+               assert (keys.lower ("five") == null);
+               assert (entries.lower (entry_for ("five", "five")) == null);
+
+               assert (keys.lower ("six") == "one");
+               assert_entry (entries.lower (entry_for ("six", "six")), "one", "one");
+
+               assert (keys.lower ("s") == "one");
+               assert_entry (entries.lower (entry_for ("s", "six")), "one", "one");
+
+       }
+       
+       public void test_higher () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               assert (keys.higher ("one") == null);
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               assert (keys.higher ("one") == "six");
+               assert_entry (entries.higher (entry_for ("one", "one")), "six", "six");
+
+               assert (keys.higher ("o") == "one");
+               assert_entry (entries.higher (entry_for ("o", "one")), "one", "one");
+
+               assert (keys.higher ("two") == null);
+               assert (entries.higher (entry_for ("two", "two")) == null);
+
+               assert (keys.higher ("t") == "three");
+               assert_entry (entries.higher (entry_for ("t", "two")), "three", "three");
+
+               assert (keys.higher ("three") == "two");
+               assert_entry (entries.higher (entry_for ("three", "three")), "two", "two");
+
+               assert (keys.higher ("four") == "one");
+               assert_entry (entries.higher (entry_for ("four", "four")), "one", "one");
+
+               assert (keys.higher ("f") == "five");
+               assert_entry (entries.higher (entry_for ("f", "four")), "five", "five");
+
+               assert (keys.higher ("five") == "four");
+               assert_entry (entries.higher (entry_for ("five", "five")), "four", "four");
+
+               assert (keys.higher ("six") == "three");
+               assert_entry (entries.higher (entry_for ("six", "six")), "three", "three");
+
+               assert (keys.higher ("s") == "six");
+               assert_entry (entries.higher (entry_for ("s", "six")), "six", "six");
+       }
+       
+       public void test_floor () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               assert (keys.floor ("one") == null);
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               assert (keys.floor ("one") == "one");
+               assert_entry (entries.floor (entry_for ("one", "one")), "one", "one");
+
+               assert (keys.floor ("o") == "four");
+               assert_entry (entries.floor (entry_for ("o", "one")), "four", "four");
+
+               assert (keys.floor ("two") == "two");
+               assert_entry (entries.floor (entry_for ("two", "two")), "two", "two");
+
+               assert (keys.floor ("t") == "six");
+               assert_entry (entries.floor (entry_for ("t", "two")), "six", "six");
+
+               assert (keys.floor ("three") == "three");
+               assert_entry (entries.floor (entry_for ("three", "three")), "three", "three");
+
+               assert (keys.floor ("four") == "four");
+               assert_entry (entries.floor (entry_for ("four", "four")), "four", "four");
+
+               assert (keys.floor ("f") == null);
+               assert (entries.floor (entry_for ("f", "four")) == null);
+
+               assert (keys.floor ("five") == "five");
+               assert_entry (entries.floor (entry_for ("five", "five")), "five", "five");
+
+               assert (keys.floor ("six") == "six");
+               assert_entry (entries.floor (entry_for ("six", "six")), "six", "six");
+
+               assert (keys.floor ("s") == "one");
+               assert_entry (entries.floor (entry_for ("s", "six")), "one", "one");
+       }
+       
+       public void test_ceil () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               assert (keys.ceil ("one") == null);
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               assert (keys.ceil ("one") == "one");
+               assert_entry (entries.ceil (entry_for ("one", "one")), "one", "one");
+
+               assert (keys.ceil ("o") == "one");
+               assert_entry (entries.ceil (entry_for ("o", "one")), "one", "one");
+
+               assert (keys.ceil ("two") == "two");
+               assert_entry (entries.ceil (entry_for ("two", "two")), "two", "two");
+
+               assert (keys.ceil ("t") == "three");
+               assert_entry (entries.ceil (entry_for ("t", "two")), "three", "three");
+
+               assert (keys.ceil ("three") == "three");
+               assert_entry (entries.ceil (entry_for ("three", "three")), "three", "three");
+
+               assert (keys.ceil ("four") == "four");
+               assert_entry (entries.ceil (entry_for ("four", "four")), "four", "four");
+
+               assert (keys.ceil ("f") == "five");
+               assert_entry (entries.ceil (entry_for ("f", "four")), "five", "five");
+
+               assert (keys.ceil ("five") == "five");
+               assert_entry (entries.ceil (entry_for ("five", "five")), "five", "five");
+
+               assert (keys.ceil ("six") == "six");
+               assert_entry (entries.ceil (entry_for ("six", "six")), "six", "six");
+
+               assert (keys.ceil ("s") == "six");
+               assert_entry (entries.ceil (entry_for ("s", "six")), "six", "six");
+       }
+
+       public void test_bidir_iterator_can_go_backward () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               var keys_iterator = keys.bidir_iterator ();
+               var entries_iterator = entries.bidir_iterator ();
+               var map_iterator = test_sorted_map.bidir_map_iterator ();
+
+               assert (!keys_iterator.has_previous ());
+               assert (!entries_iterator.has_previous ());
+
+               assert (!map_iterator.has_previous ());
+               assert (!keys_iterator.previous ());
+               assert (!entries_iterator.has_previous ());
+
+               assert (!map_iterator.previous ());
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               keys_iterator = keys.bidir_iterator ();
+               entries_iterator = entries.bidir_iterator ();
+               map_iterator = test_sorted_map.bidir_map_iterator ();
+
+               assert (keys_iterator.next ());
+               assert (entries_iterator.next ());
+
+               assert (map_iterator.next ());
+               assert (keys_iterator.get () == "five");
+               assert_entry (entries_iterator.get (), "five", "five");
+
+               assert (map_iterator.get_key () == "five");
+               assert (map_iterator.get_value () == "five");
+
+               assert (!keys_iterator.has_previous ());
+               assert (!entries_iterator.has_previous ());
+
+               assert (!map_iterator.has_previous ());
+               assert (keys_iterator.next ());
+               assert (entries_iterator.next ());
+
+               assert (map_iterator.next ());
+               assert (keys_iterator.get () == "four");
+               assert_entry (entries_iterator.get (), "four", "four");
+
+               assert (map_iterator.get_key () == "four");
+               assert (map_iterator.get_value () == "four");
+
+               assert (keys_iterator.has_previous ());
+               assert (entries_iterator.has_previous ());
+
+               assert (map_iterator.has_previous ());
+               assert (keys_iterator.next ());
+               assert (entries_iterator.next ());
+
+               assert (map_iterator.next ());
+               assert (keys_iterator.get () == "one");
+               assert_entry (entries_iterator.get (), "one", "one");
+
+               assert (map_iterator.get_key () == "one");
+               assert (map_iterator.get_value () == "one");
+
+               assert (keys_iterator.has_previous ());
+               assert (entries_iterator.has_previous ());
+
+               assert (map_iterator.has_previous ());
+               assert (keys_iterator.next ());
+               assert (entries_iterator.next ());
+
+               assert (map_iterator.next ());
+               assert (keys_iterator.get () == "six");
+               assert_entry (entries_iterator.get (), "six", "six");
+
+               assert (map_iterator.get_key () == "six");
+               assert (map_iterator.get_value () == "six");
+               assert (keys_iterator.has_previous ());
+
+               assert (entries_iterator.has_previous ());
+               assert (map_iterator.has_previous ());
+               assert (keys_iterator.next ());
+
+               assert (entries_iterator.next ());
+               assert (map_iterator.next ());
+               assert (keys_iterator.get () == "three");
+
+               assert_entry (entries_iterator.get (), "three", "three");
+               assert (map_iterator.get_key () == "three");
+               assert (map_iterator.get_value () == "three");
+
+               assert (keys_iterator.has_previous ());
+               assert (entries_iterator.has_previous ());
+               assert (map_iterator.has_previous ());
+
+               assert (keys_iterator.next ());
+               assert (entries_iterator.next ());
+               assert (map_iterator.next ());
+
+               assert (keys_iterator.get () == "two");
+               assert_entry (entries_iterator.get (), "two", "two");
+               assert (map_iterator.get_key () == "two");
+               assert (map_iterator.get_value () == "two");
+
+               assert (keys_iterator.has_previous ());
+               assert (entries_iterator.has_previous ());
+               assert (map_iterator.has_previous ());
+
+               assert (!keys_iterator.next ());
+               assert (!entries_iterator.next ());
+               assert (!map_iterator.next ());
+
+               assert (keys_iterator.previous ());
+               assert (entries_iterator.previous ());
+               assert (map_iterator.previous ());
+
+               assert (keys_iterator.get () == "three");
+               assert_entry (entries_iterator.get (), "three", "three");
+               assert (map_iterator.get_key () == "three");
+               assert (map_iterator.get_value () == "three");
+
+               assert (keys_iterator.previous ());
+               assert (entries_iterator.previous ());
+               assert (map_iterator.previous ());
+
+               assert (keys_iterator.get () == "six");
+               assert_entry (entries_iterator.get (), "six", "six");
+               assert (map_iterator.get_key () == "six");
+               assert (map_iterator.get_value () == "six");
+
+               assert (keys_iterator.previous ());
+               assert (entries_iterator.previous ());
+               assert (map_iterator.previous ());
+
+               assert (keys_iterator.get () == "one");
+               assert_entry (entries_iterator.get (), "one", "one");
+               assert (map_iterator.get_key () == "one");
+               assert (map_iterator.get_value () == "one");
+
+               assert (keys_iterator.previous ());
+               assert (entries_iterator.previous ());
+               assert (map_iterator.previous ());
+
+               assert (keys_iterator.get () == "four");
+               assert_entry (entries_iterator.get (), "four", "four");
+               assert (map_iterator.get_key () == "four");
+               assert (map_iterator.get_value () == "four");
+
+               assert (keys_iterator.previous ());
+               assert (entries_iterator.previous ());
+               assert (map_iterator.previous ());
+
+               assert (keys_iterator.get () == "five");
+               assert_entry (entries_iterator.get (), "five", "five");
+               assert (map_iterator.get_key () == "five");
+               assert (map_iterator.get_value () == "five");
+
+               assert (!keys_iterator.previous ());
+               assert (!entries_iterator.previous ());
+               assert (!map_iterator.previous ());
+
+               assert (keys_iterator.get () == "five");
+               assert_entry (entries_iterator.get (), "five", "five");
+               assert (map_iterator.get_key () == "five");
+               assert (map_iterator.get_value () == "five");
+       }
+
+       public void test_bidir_iterator_last () {
+               var test_sorted_map = test_map as SortedMap<string,string>;
+               var keys = test_sorted_map.ascending_keys;
+               var entries = test_sorted_map.ascending_entries;
+
+               var keys_iterator = keys.bidir_iterator ();
+               var entries_iterator = entries.bidir_iterator ();
+
+               assert (!keys_iterator.last ());
+               assert (!entries_iterator.last ());
+
+               test_sorted_map.set ("one", "one");
+               test_sorted_map.set ("two", "two");
+               test_sorted_map.set ("three", "three");
+               test_sorted_map.set ("four", "four");
+               test_sorted_map.set ("five", "five");
+               test_sorted_map.set ("six", "six");
+
+               keys_iterator = keys.bidir_iterator ();
+               entries_iterator = entries.bidir_iterator ();
+
+               assert (keys_iterator.last ());
+               assert (entries_iterator.last ());
+
+               assert (keys_iterator.get () == "two");
+               assert_entry (entries_iterator.get (), "two", "two");
+       }
+
+       public class SubMap : Gee.TestCase {
+               private SortedMap<string,string> master;
+               private SortedMap<string,string> submap;
+               private SortedMapTests test;
+               public enum Type {
+                       HEAD,
+                       TAIL,
+                       SUB,
+                       EMPTY;
+                       public unowned string to_string () {
+                               switch (this) {
+                               case Type.HEAD: return "Head";
+                               case Type.TAIL: return "Tail";
+                               case Type.SUB: return "Range";
+                               case Type.EMPTY: return "Empty";
+                               default: assert_not_reached ();
+                               }
+                       }
+               }
+               private Type type;
+               
+               public SubMap (SortedMapTests test, Type type) {
+                       base ("%s Submap".printf (type.to_string ()));
+                       this.test = test;
+                       this.type = type;
+                       add_test ("[Map] has_key, size and is_empty",
+                                 test_has_key_size_is_empty);
+                       add_test ("[Map] keys", test_keys);
+                       add_test ("[Map] values", test_values);
+                       add_test ("[Map] entries", test_entries);
+                       add_test ("[Map] get", test_get);
+                       add_test ("[Map] set", test_set);
+                       add_test ("[Map] unset", test_unset);
+                       add_test ("[Map] clear", test_clear);
+                       add_test ("[Map] iterators", test_iterators);
+                       add_test ("[SortedMap] boundaries", test_boundaries);
+                       add_test ("[SortedMap] lower", test_lower);
+                       add_test ("[SortedMap] higher", test_higher);
+                       add_test ("[SortedMap] floor", test_floor);
+                       add_test ("[SortedMap] ceil", test_ceil);
+                       add_test ("[SortedMap] iterator_at", test_iterator_at);
+                       add_test ("[SortedMap] submap and subsets", test_submap_and_subsets);
+               }
+
+               public override void set_up () {
+                       test.set_up ();
+                       master = test.test_map as SortedMap<string,string>;
+                       switch (type) {
+                       case Type.HEAD:
+                               submap = master.head_map ("one"); break;
+                       case Type.TAIL:
+                               submap = master.tail_map ("six"); break;
+                       case Type.SUB:
+                               submap = master.sub_map ("four", "three"); break;
+                       case Type.EMPTY:
+                               submap = master.sub_map ("three", "four"); break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public override void tear_down () {
+                       test.tear_down ();
+               }
+               
+               protected void set_default_values (out string[] contains = null, out string[] not_contains = null) {
+                       master.set ("one", "one");
+                       master.set ("two", "two");
+                       master.set ("three", "three");
+                       master.set ("four", "four");
+                       master.set ("five", "five");
+                       master.set ("six", "six");
+                       switch (type) {
+                       case Type.HEAD:
+                               contains = {"five", "four"};
+                               not_contains = {"one", "two", "three", "six"};
+                               break;
+                       case Type.TAIL:
+                               contains = {"six", "three", "two"};
+                               not_contains = {"one", "four", "five"};
+                               break;
+                       case Type.SUB:
+                               contains = {"four", "one", "six"};
+                               not_contains = {"two", "three", "five"};
+                               break;
+                       case Type.EMPTY:
+                               contains = {};
+                               not_contains = {"one", "two", "three", "four", "five", "six"};
+                               break;
+                       }
+               }
+               
+               public void test_has_key_size_is_empty () {
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       assert (submap.size == contains.length);
+                       assert (submap.is_empty == (contains.length == 0));
+
+                       foreach (var s in contains) {
+                               assert (submap.has_key (s));
+                               assert (submap.has (s, s));
+                       }
+                       foreach (var s in not_contains) {
+                               assert (!submap.has_key (s));
+                               assert (!submap.has (s, s));
+                       }
+               }
+
+               public void test_get () {
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       foreach (var s in contains) {
+                               assert (submap.get (s) == s);
+                       }
+               }
+               
+               public void test_keys () {
+                       var keys = submap.keys;
+                       
+                       assert (keys.size == 0);
+                       assert (keys.is_empty);
+
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       assert (keys.size == contains.length);
+                       foreach (var s in contains)
+                               assert (keys.contains (s));
+                       foreach (var s in not_contains)
+                               assert (!keys.contains (s));
+       
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               keys.add ("three");
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+       
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               keys.remove ("three");
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+               }
+
+               public void test_values () {
+                       var values = submap.values;
+                       
+                       assert (values.size == 0);
+                       assert (values.is_empty);
+
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       assert (values.size == contains.length);
+                       foreach (var s in contains)
+                               assert (values.contains (s));
+                       foreach (var s in not_contains)
+                               assert (!values.contains (s));
+
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               values.add ("three");
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               values.remove ("three");
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+               }
+
+               public void test_entries () {
+                       var entries = submap.entries;
+                       
+                       assert (entries.size == 0);
+                       assert (entries.is_empty);
+
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       assert (entries.size == contains.length);
+                       foreach (var s in contains)
+                               assert (entries.contains (MapTests.entry_for (s, s)));
+                       foreach (var s in not_contains)
+                               assert (!entries.contains (MapTests.entry_for (s, s)));
+
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               entries.add (MapTests.entry_for ("three", "three"));
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+
+                       if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                          TestTrapFlags.SILENCE_STDERR)) {
+                               entries.remove (MapTests.entry_for ("three", "three"));
+                               Posix.exit (0);
+                       }
+                       Test.trap_assert_failed ();
+               }
+               
+               public void test_set () {
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       string[] success, fail;
+                       switch (type) {
+                       case Type.HEAD:
+                               success = {"a", "o"};
+                               fail = {"oz", "z"};
+                               break;
+                       case Type.TAIL:
+                               success = {"siz", "z"};
+                               fail = {"sia", "a"};
+                               break;
+                       case Type.SUB:
+                               success = {"o", "th"};
+                               fail = {"f", "u"};
+                               break;
+                       case Type.EMPTY:
+                               success = {};
+                               fail = {"o", "th", "f", "u"};
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+                       
+                       foreach (var s in success) {
+                               submap.set (s, s);
+                               assert (submap.has (s, s));
+                               assert (master.has (s, s));
+                       }
+
+                       foreach (var s in fail) {
+                               submap.set (s, s);
+                               assert (!submap.has_key (s));
+                               assert (!master.has_key (s));
+                       }
+                       
+                       assert (master.size == 6 + success.length);
+               }
+               
+               public void test_unset () {
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       foreach (var s in contains) {
+                               string? value;
+                               assert (submap.unset (s, out value));
+                               assert (value == s);
+                               assert (!master.has_key (s));
+                       }
+                       foreach (var s in not_contains) {
+                               assert (!submap.unset (s));
+                               assert (master.has (s, s));
+                       }
+
+                       assert (master.size == 6 - contains.length);
+               }
+
+               public void test_clear () {
+                       string[] contains, not_contains;
+
+                       set_default_values (out contains, out not_contains);
+
+                       submap.clear ();
+                       
+                       foreach (var s in contains) {
+                               assert (!master.has_key (s));
+                       }
+                       foreach (var s in not_contains) {
+                               assert (!submap.unset (s));
+                               assert (master.has (s, s));
+                       }
+                       
+                       assert (master.size == 6 - contains.length);
+               }
+
+               public void test_iterators () {
+                       string[] contains, not_contains;
+
+                       var _map_iter = submap.bidir_map_iterator ();
+
+                       assert (!_map_iter.has_next ());
+                       assert (!_map_iter.next ());
+                       assert (!_map_iter.has_previous ());
+                       assert (!_map_iter.previous ());
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       var i = 0;
+                       _map_iter = submap.bidir_map_iterator ();
+                       while (_map_iter.next ()) {
+                               assert (_map_iter.get_key () == contains[i]);
+                               assert (_map_iter.get_value () == contains[i]);
+                               i++;
+                       }
+                       assert (i == contains.length);
+                       
+                       i = 0;
+                       foreach (var k in submap.keys)
+                               assert (k == contains[i++]);
+                       assert (i == contains.length);
+                       
+                       i = 0;
+                       foreach (var e in submap.entries) {
+                               MapTests.assert_entry (e, contains[i], contains[i]);
+                               i++;
+                       }
+                       assert (i == contains.length);
+                       
+                       var keys_iter = submap.ascending_keys.bidir_iterator ();
+                       var entries_iter = submap.ascending_entries.bidir_iterator ();
+                       var map_iter = submap.bidir_map_iterator ();
+                       if (type != Type.EMPTY) {
+                               assert (map_iter.last ());
+                               assert (map_iter.get_key () == contains[contains.length - 1]);
+                               assert (map_iter.get_value () == contains[contains.length - 1]);
+
+                               map_iter = submap.bidir_map_iterator ();
+                               assert (map_iter.next ());
+
+                               assert (map_iter.get_key () == contains[0]);
+                               assert (map_iter.get_value () == contains[0]);
+
+                               assert (map_iter.has_next ());
+                               assert (map_iter.next ());
+                               assert (map_iter.get_key () == contains[1]);
+                               assert (map_iter.get_value () == contains[1]);
+
+                               assert (map_iter.has_previous ());
+                               map_iter.unset ();
+                               assert (map_iter.has_previous ());
+                               if (type != Type.HEAD)
+                                       assert (map_iter.has_next ());
+                               else
+                                       assert (!map_iter.has_next ());
+                               assert (map_iter.previous ());
+                               assert (map_iter.get_key () == contains[0]);
+                               assert (map_iter.get_value () == contains[0]);
+                               
+                               // Repeat for keys
+                               master.clear ();
+                               set_default_values (out contains, out not_contains);
+                               
+                               assert (keys_iter.last ());
+                               assert (keys_iter.get () == contains[contains.length - 1]);
+                               assert (keys_iter.first ());
+
+                               assert (keys_iter.get () == contains[0]);
+                               assert (keys_iter.has_next ());
+                               assert (keys_iter.next ());
+                               assert (keys_iter.get () == contains[1]);
+                               assert (keys_iter.has_previous ());
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       keys_iter.remove ();
+                                       Posix.exit (0);
+                               }
+                               assert (keys_iter.has_previous ());
+                               if (type != Type.HEAD)
+                                       assert (keys_iter.has_next ());
+                               else
+                                       assert (!keys_iter.has_next ());
+                               assert (keys_iter.previous ());
+                               assert (keys_iter.get () == contains[0]);
+                               
+                               // Repeat for entries
+                               master.clear ();
+                               set_default_values (out contains, out not_contains);
+
+                               assert (entries_iter.last ());
+                               MapTests.assert_entry (entries_iter.get (), contains[contains.length - 1], contains[contains.length - 1]);
+                               assert (entries_iter.first ());
+
+                               MapTests.assert_entry (entries_iter.get (), contains[0], contains[0]);
+                               assert (entries_iter.has_next ());
+                               assert (entries_iter.next ());
+                               MapTests.assert_entry (entries_iter.get (), contains[1], contains[1]);
+                               assert (entries_iter.has_previous ());
+                               entries_iter.remove ();
+                               assert (entries_iter.has_previous ());
+                               if (type != Type.HEAD)
+                                       assert (entries_iter.has_next ());
+                               else
+                                       assert (!entries_iter.has_next ());
+                               assert (entries_iter.previous ());
+                               MapTests.assert_entry (entries_iter.get (), contains[0], contains[0]);
+                       } else {
+                               assert (!keys_iter.first ());
+                               assert (!keys_iter.last ());
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       keys_iter.remove ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                               assert (!entries_iter.first ());
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       entries_iter.remove ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                       }
+               }
+               
+               public void test_boundaries () {
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+
+                       string[] contains, not_contains;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               assert (keys.first () == "five");
+                               assert (keys.last () == "four");
+                               assert_entry (entries.first (), "five", "five");
+                               assert_entry (entries.last (), "four", "four");
+                               break;
+                       case Type.TAIL:
+                               assert (keys.first () == "six");
+                               assert (keys.last () == "two");
+                               assert_entry (entries.first (), "six", "six");
+                               assert_entry (entries.last (), "two", "two");
+                               break;
+                       case Type.SUB:
+                               assert (keys.first () == "four");
+                               assert (keys.last () == "six");
+                               assert_entry (entries.first (), "four", "four");
+                               assert_entry (entries.last (), "six", "six");
+                               break;
+                       case Type.EMPTY:
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       keys.first ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       keys.last ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       entries.first ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                               if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT |
+                                                      TestTrapFlags.SILENCE_STDERR)) {
+                                       entries.last ();
+                                       Posix.exit (0);
+                               }
+                               Test.trap_assert_failed ();
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public void test_lower () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               assert (keys.lower ("a") == null);
+                               assert (entries.lower (MapTests.entry_for ("a", "a")) == null);
+                               assert (keys.lower ("five") == null);
+                               assert (entries.lower (MapTests.entry_for ("five", "five")) == null);
+                               assert (keys.lower ("four") == "five");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("four", "four")), "five", "five");
+                               assert (keys.lower ("six") == "four");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("six", "six")), "four", "four");
+                               break;
+                       case Type.TAIL:
+                               assert (keys.lower ("one") == null);
+                               assert (entries.lower (MapTests.entry_for ("one", "one")) == null);
+                               assert (keys.lower ("six") == null);
+                               assert (entries.lower (MapTests.entry_for ("six", "six")) == null);
+                               assert (keys.lower ("three") == "six");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("three", "three")), "six", "six");
+                               assert (keys.lower ("two") == "three");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("two", "two")), "three", "three");
+                               assert (keys.lower ("z") == "two");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("z", "z")), "two", "two");
+                               break;
+                       case Type.SUB:
+                               assert (keys.lower ("five") == null);
+                               assert (entries.lower (MapTests.entry_for ("five", "five")) == null);
+                               assert (keys.lower ("four") == null);
+                               assert (entries.lower (MapTests.entry_for ("four", "four")) == null);
+                               assert (keys.lower ("one") == "four");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("one", "one")), "four", "four");
+                               assert (keys.lower ("six") == "one");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("six", "six")), "one", "one");
+                               assert (keys.lower ("three") == "six");
+                               MapTests.assert_entry (entries.lower (MapTests.entry_for ("three", "three")), "six", "six");
+                               break;
+                       case Type.EMPTY:
+                               assert (keys.lower ("six") == null);
+                               assert (entries.lower (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public void test_higher () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               assert (keys.higher ("a") == "five");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("a", "a")), "five", "five");
+                               assert (keys.higher ("five") == "four");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("five", "five")), "four", "four");
+                               assert (keys.higher ("four") == null);
+                               assert (entries.higher (MapTests.entry_for ("four", "four")) == null);
+                               assert (keys.higher ("six") == null);
+                               assert (entries.higher (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       case Type.TAIL:
+                               assert (keys.higher ("one") == "six");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("one", "one")), "six", "six");
+                               assert (keys.higher ("six") == "three");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("six", "six")), "three", "three");
+                               assert (keys.higher ("three") == "two");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("three", "three")), "two", "two");
+                               assert (keys.higher ("two") == null);
+                               assert (entries.higher (MapTests.entry_for ("two", "two")) == null);
+                               assert (keys.higher ("z") == null);
+                               assert (entries.higher (MapTests.entry_for ("z", "z")) == null);
+                               break;
+                       case Type.SUB:
+                               assert (keys.higher ("five") == "four");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("five", "five")), "four", "four");
+                               assert (keys.higher ("four") == "one");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("four", "four")), "one", "one");
+                               assert (keys.higher ("one") == "six");
+                               MapTests.assert_entry (entries.higher (MapTests.entry_for ("one", "one")), "six", "six");
+                               assert (keys.higher ("six") == null);
+                               assert (entries.higher (MapTests.entry_for ("six", "six")) == null);
+                               assert (keys.higher ("three") == null);
+                               assert (entries.higher (MapTests.entry_for ("three", "three")) == null);
+                               break;
+                       case Type.EMPTY:
+                               assert (keys.higher ("six") == null);
+                               assert (entries.higher (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public void test_floor () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               assert (keys.floor ("a") == null);
+                               assert (entries.floor (MapTests.entry_for ("a", "a")) == null);
+                               assert (keys.floor ("five") == "five");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("five", "fiv")), "five", "five");
+                               assert (keys.floor ("four") == "four");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("four", "four")), "four", "four");
+                               assert (keys.floor ("six") == "four");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("six", "six")), "four", "four");
+                               break;
+                       case Type.TAIL:
+                               assert (keys.floor ("one") == null);
+                               assert (entries.floor (MapTests.entry_for ("one", "one")) == null);
+                               assert (keys.floor ("six") == "six");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("six", "six")), "six", "six");
+                               assert (keys.floor ("three") == "three");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("three", "three")), "three", "three");
+                               assert (keys.floor ("two") == "two");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("two", "two")), "two", "two");
+                               assert (keys.floor ("z") == "two");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("z", "z")), "two", "two");
+                               break;
+                       case Type.SUB:
+                               assert (keys.floor ("five") == null);
+                               assert (entries.floor (MapTests.entry_for ("five", "five")) == null);
+                               assert (keys.floor ("four") == "four");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("four", "four")), "four", "four");
+                               assert (keys.floor ("one") == "one");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("one", "one")), "one", "one");
+                               assert (keys.floor ("six") == "six");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("six", "six")), "six", "six");
+                               assert (keys.floor ("three") == "six");
+                               MapTests.assert_entry (entries.floor (MapTests.entry_for ("three", "three")), "six", "six");
+                               break;
+                       case Type.EMPTY:
+                               assert (keys.floor ("six") == null);
+                               assert (entries.floor (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+
+               public void test_ceil () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               assert (keys.ceil ("a") == "five");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("a", "a")), "five", "five");
+                               assert (keys.ceil ("five") == "five");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("five", "five")), "five", "five");
+                               assert (keys.ceil ("four") == "four");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("four", "four")), "four", "four");
+                               assert (keys.ceil ("six") == null);
+                               assert (entries.ceil (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       case Type.TAIL:
+                               assert (keys.ceil ("one") == "six");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("one", "one")), "six", "six");
+                               assert (keys.ceil ("six") == "six");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("six", "six")), "six", "six");
+                               assert (keys.ceil ("three") == "three");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("three", "three")), "three", "three");
+                               assert (keys.ceil ("two") == "two");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("two", "two")), "two", "two");
+                               assert (keys.ceil ("z") == null);
+                               assert (entries.ceil (MapTests.entry_for ("z", "z")) == null);
+                               break;
+                       case Type.SUB:
+                               assert (keys.ceil ("five") == "four");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("five", "five")), "four", "four");
+                               assert (keys.ceil ("four") == "four");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("four", "four")), "four", "four");
+                               assert (keys.ceil ("one") == "one");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("one", "one")), "one", "one");
+                               assert (keys.ceil ("six") == "six");
+                               MapTests.assert_entry (entries.ceil (MapTests.entry_for ("six", "six")), "six", "six");
+                               assert (keys.ceil ("three") == null);
+                               assert (entries.ceil (MapTests.entry_for ("three", "three")) == null);
+                               break;
+                       case Type.EMPTY:
+                               assert (keys.ceil ("six") == null);
+                               assert (entries.ceil (MapTests.entry_for ("six", "six")) == null);
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+               
+               public void test_iterator_at () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       foreach (var s in contains) {
+                               var key_iter = keys.iterator_at (s);
+                               var entry_iter = entries.iterator_at (MapTests.entry_for (s, s));
+                               assert (key_iter != null);
+                               assert (key_iter.get () == s);
+                               MapTests.assert_entry (entry_iter.get (), s, s);
+                       }
+                       foreach (var s in not_contains) {
+                               var key_iter = keys.iterator_at (s);
+                               var entry_iter = entries.iterator_at (MapTests.entry_for (s, s));
+                               assert (key_iter == null);
+                               assert (entry_iter == null);
+                       }
+                       assert (keys.iterator_at ("seven") == null);
+                       assert (entries.iterator_at (MapTests.entry_for ("seven", "seven")) == null);
+               }
+               
+               public void test_submap_and_subsets () {
+                       string[] contains, not_contains;
+                       var keys = submap.ascending_keys;
+                       var entries = submap.ascending_entries;
+                       
+                       set_default_values (out contains, out not_contains);
+                       
+                       switch (type) {
+                       case Type.HEAD:
+                               var subsubmap = submap.head_map ("four");
+                               var keyssubset = keys.head_set ("four");
+                               var entriessubset = entries.head_set (MapTests.entry_for ("four", "four"));
+
+                               assert (subsubmap.size == 1);
+                               assert (keyssubset.size == 1);
+                               assert (entriessubset.size == 1);
+
+                               subsubmap = submap.tail_map ("four");
+                               keyssubset = keys.tail_set ("four");
+                               entriessubset = entries.tail_set (MapTests.entry_for ("four", "four"));
+
+                               assert (subsubmap.size == 1);
+                               assert (keyssubset.size == 1);
+                               assert (entriessubset.size == 1);
+
+                               subsubmap = submap.sub_map ("four", "one");
+                               keyssubset = keys.sub_set ("four", "one");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("four", "four"), MapTests.entry_for ("one", "one"));
+
+                               assert (subsubmap.size == 1);
+                               assert (keyssubset.size == 1);
+                               assert (entriessubset.size == 1);
+
+                               subsubmap = submap.sub_map ("four", "four");
+                               keyssubset = keys.sub_set ("four", "four");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("four", "four"), MapTests.entry_for ("four", "four"));
+
+                               assert (subsubmap.size == 0);
+                               assert (keyssubset.size == 0);
+                               assert (entriessubset.size == 0);
+                               break;
+                       case Type.TAIL:
+                               var subsubmap = submap.head_map ("two");
+                               var keyssubset = keys.head_set ("two");
+                               var entriessubset = entries.head_set (MapTests.entry_for ("two", "two"));
+
+                               assert (subsubmap.size == 2);
+                               assert (keyssubset.size == 2);
+                               assert (entriessubset.size == 2);
+
+                               subsubmap = submap.tail_map ("three");
+                               keyssubset = keys.tail_set ("three");
+                               entriessubset = entries.tail_set (MapTests.entry_for ("three", "three"));
+
+                               assert (subsubmap.size == 2);
+                               assert (keyssubset.size == 2);
+                               assert (entriessubset.size == 2);
+
+                               subsubmap = submap.sub_map ("three", "two");
+                               keyssubset = keys.sub_set ("three", "two");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("three", "three"), MapTests.entry_for ("two", "two"));
+
+                               assert (subsubmap.size == 1);
+                               assert (keyssubset.size == 1);
+                               assert (entriessubset.size == 1);
+                               break;
+                       case Type.SUB:
+                               var subsubmap = submap.head_map ("six");
+                               var keyssubset = keys.head_set ("six");
+                               var entriessubset = entries.head_set (MapTests.entry_for ("six", "six"));
+
+                               assert (subsubmap.size == 2);
+                               assert (keyssubset.size == 2);
+                               assert (entriessubset.size == 2);
+
+                               subsubmap = submap.tail_map ("one");
+                               keyssubset = keys.tail_set ("one");
+                               entriessubset = entries.tail_set (MapTests.entry_for ("one", "one"));
+
+                               assert (subsubmap.size == 2);
+                               assert (keyssubset.size == 2);
+                               assert (entriessubset.size == 2);
+
+                               subsubmap = submap.sub_map ("one", "six");
+                               keyssubset = keys.sub_set ("one", "six");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("one", "one"), MapTests.entry_for ("six", "six"));
+
+                               assert (subsubmap.size == 1);
+                               assert (keyssubset.size == 1);
+                               assert (entriessubset.size == 1);
+
+                               subsubmap = submap.sub_map ("five", "two");
+                               keyssubset = keys.sub_set ("five", "two");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("five", "five"), MapTests.entry_for ("two", "two"));
+
+                               assert (subsubmap.size == 3);
+                               assert (keyssubset.size == 3);
+                               assert (entriessubset.size == 3);
+                               break;
+                       case Type.EMPTY:
+                               var subsubmap = submap.head_map ("six");
+                               var keyssubset = keys.head_set ("six");
+                               var entriessubset = entries.head_set (MapTests.entry_for ("six", "six"));
+
+                               assert (subsubmap.size == 0);
+                               assert (keyssubset.size == 0);
+                               assert (entriessubset.size == 0);
+
+                               subsubmap = submap.tail_map ("three");
+                               keyssubset = keys.tail_set ("three");
+                               entriessubset = entries.tail_set (MapTests.entry_for ("three", "three"));
+
+                               assert (subsubmap.size == 0);
+                               assert (keyssubset.size == 0);
+                               assert (entriessubset.size == 0);
+
+                               subsubmap = submap.sub_map ("one", "six");
+                               keyssubset = keys.sub_set ("one", "six");
+                               entriessubset = entries.sub_set (MapTests.entry_for ("one", "one"), MapTests.entry_for ("six", "six"));
+
+                               assert (subsubmap.size == 0);
+                               assert (keyssubset.size == 0);
+                               assert (entriessubset.size == 0);
+                               break;
+                       default:
+                               assert_not_reached ();
+                       }
+               }
+       }
+}
+
index 99a54d8..6cb7857 100644 (file)
 
 using Gee;
 
-public class TreeMapTests : MapTests {
+public class TreeMapTests : SortedMapTests {
 
        public TreeMapTests () {
                base ("TreeMap");
-               add_test ("[TreeMap] key ordering", test_key_ordering);
        }
 
        public override void set_up () {
@@ -37,51 +36,4 @@ public class TreeMapTests : MapTests {
        public override void tear_down () {
                test_map = null;
        }
-
-       public void test_key_ordering () {
-               var test_tree_map = test_map as TreeMap<string,string>;
-
-               // Check the map exists
-               assert (test_tree_map != null);
-
-               test_tree_map.set ("one", "one");
-               test_tree_map.set ("two", "two");
-               test_tree_map.set ("three", "three");
-               test_tree_map.set ("four", "four");
-               test_tree_map.set ("five", "five");
-               test_tree_map.set ("six", "six");
-               test_tree_map.set ("seven", "seven");
-               test_tree_map.set ("eight", "eight");
-               test_tree_map.set ("nine", "nine");
-               test_tree_map.set ("ten", "ten");
-               test_tree_map.set ("eleven", "eleven");
-               test_tree_map.set ("twelve", "twelve");
-
-               Iterator<string> iterator = test_tree_map.keys.iterator ();
-               assert (iterator.next ());
-               assert (iterator.get () == "eight");
-               assert (iterator.next ());
-               assert (iterator.get () == "eleven");
-               assert (iterator.next ());
-               assert (iterator.get () == "five");
-               assert (iterator.next ());
-               assert (iterator.get () == "four");
-               assert (iterator.next ());
-               assert (iterator.get () == "nine");
-               assert (iterator.next ());
-               assert (iterator.get () == "one");
-               assert (iterator.next ());
-               assert (iterator.get () == "seven");
-               assert (iterator.next ());
-               assert (iterator.get () == "six");
-               assert (iterator.next ());
-               assert (iterator.get () == "ten");
-               assert (iterator.next ());
-               assert (iterator.get () == "three");
-               assert (iterator.next ());
-               assert (iterator.get () == "twelve");
-               assert (iterator.next ());
-               assert (iterator.get () == "two");
-               assert (iterator.next () == false);
-       }
 }