[libgee] Add left-leaning red-black tree based set and map
- From: Didier 'Ptitjes' Villevalois <dvillevalois src gnome org>
- To: svn-commits-list gnome org
- Subject: [libgee] Add left-leaning red-black tree based set and map
- Date: Wed, 22 Jul 2009 15:01:07 +0000 (UTC)
commit 01f1bc34185cf4fb8919a16d64e1b5d449d3abaa
Author: Maciej Piechotka <uzytkownik2 gmail com>
Date: Sun Jul 19 22:29:17 2009 +0200
Add left-leaning red-black tree based set and map
Fixes bug 583728.
Signed-off-by: Didier 'Ptitjes <ptitjes free fr>
gee/Makefile.am | 3 +
gee/functions.vala | 36 ++++
gee/treemap.vala | 443 ++++++++++++++++++++++++++++++++++++++++++++++++
gee/treeset.vala | 317 ++++++++++++++++++++++++++++++++++
tests/Makefile.am | 18 ++
tests/testtreemap.vala | 310 +++++++++++++++++++++++++++++++++
tests/testtreeset.vala | 287 +++++++++++++++++++++++++++++++
7 files changed, 1414 insertions(+), 0 deletions(-)
---
diff --git a/gee/Makefile.am b/gee/Makefile.am
index 7838a1e..dd0b35c 100644
--- a/gee/Makefile.am
+++ b/gee/Makefile.am
@@ -15,6 +15,7 @@ lib_LTLIBRARIES = \
libgee_la_VALASOURCES = \
arraylist.vala \
collection.vala \
+ functions.vala \
hashmap.vala \
hashset.vala \
iterable.vala \
@@ -26,6 +27,8 @@ libgee_la_VALASOURCES = \
readonlymap.vala \
readonlyset.vala \
set.vala \
+ treemap.vala \
+ treeset.vala \
$(NULL)
libgee_la_SOURCES = \
diff --git a/gee/functions.vala b/gee/functions.vala
new file mode 100644
index 0000000..85777f0
--- /dev/null
+++ b/gee/functions.vala
@@ -0,0 +1,36 @@
+/* functions.vala
+ *
+ * Copyright (C) 2009 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>
+ */
+
+using GLib;
+
+namespace Gee {
+ public static int direct_compare (void* _val1, void* _val2) {
+ long val1 = (long)_val1, val2 = (long)_val2;
+ if (val1 > val2) {
+ return 1;
+ } else if (val1 == val2) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+}
diff --git a/gee/treemap.vala b/gee/treemap.vala
new file mode 100644
index 0000000..e286779
--- /dev/null
+++ b/gee/treemap.vala
@@ -0,0 +1,443 @@
+/* treemap.vala
+ *
+ * Copyright (C) 2009 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>
+ */
+
+using GLib;
+
+/**
+ * Left-leaning red-black tree implementation of the Map interface.
+ */
+public class Gee.TreeMap<K,V> : Object, Map<K,V> {
+ public int size {
+ get { return _size; }
+ }
+
+ public CompareFunc key_compare_func { construct; get; }
+ public EqualFunc value_equal_func { construct; get; }
+
+ private int _size = 0;
+
+ public TreeMap (CompareFunc key_compare_func = Gee.direct_compare, EqualFunc value_equal_func = GLib.direct_equal) {
+ this.key_compare_func = key_compare_func;
+ this.value_equal_func = value_equal_func;
+ }
+
+ public Set<K> get_keys () {
+ return new KeySet<K,V> (this);
+ }
+
+ public Collection<V> get_values () {
+ return new ValueCollection<K,V> (this);
+ }
+
+ private void rotate_right (ref Node<K, V> root) {
+ Node<K,V> pivot = (owned) root.left;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.left = (owned) pivot.right;
+ pivot.right = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private void rotate_left (ref Node<K, V> root) {
+ Node<K,V> pivot = (owned) root.right;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.right = (owned) pivot.left;
+ pivot.left = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private bool is_red (Node<K, V>? n) {
+ return n != null && n.color == Node.Color.RED;
+ }
+
+ private bool is_black (Node<K, V>? n) {
+ return n == null || n.color == Node.Color.BLACK;
+ }
+
+ public bool contains (K key) {
+ weak Node<K, V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return true;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return false;
+ }
+
+ public new V? get (K key) {
+ weak Node<K, V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return cur.value;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ private void set_to_node (ref Node<K, V>? node, K key, V value, Node<K, V>? prev, Node<K, V>? next) {
+ if (node == null) {
+ node = new Node<K,V> (key, value, prev, next);
+ if (prev == null) {
+ first = node;
+ }
+ _size++;
+ }
+
+ if (is_red (node.left) && is_red (node.right)) {
+ node.flip ();
+ }
+
+ int cmp = key_compare_func (key, node.key);
+ if (cmp == 0) {
+ node.value = value;
+ } else if (cmp < 0) {
+ set_to_node (ref node.left, key, value, node.prev, node);
+ } else {
+ set_to_node (ref node.right, key, value, node, node.next);
+ }
+
+ fix_up (ref node);
+ }
+
+ public new void set (K key, V value) {
+ set_to_node (ref root, key, value, null, null);
+ root.color = Node.Color.BLACK;
+ }
+
+ private void move_red_left (ref Node<K, V> root) {
+ root.flip ();
+ if (is_red (root.right.left)) {
+ rotate_right (ref root.right);
+ rotate_left (ref root);
+ root.flip ();
+ }
+ }
+
+ private void move_red_right (ref Node<K, V> root) {
+ root.flip ();
+ if (is_red (root.left.left)) {
+ rotate_right (ref root.right);
+ root.flip ();
+ }
+ }
+
+ private void remove_minimal (ref Node<K,V> node, out K key, out V value) {
+ if (node.left == null) {
+ Node<K,V> n = (owned) node;
+ key = (owned) n.key;
+ value = (owned) n.value;
+ node = null;
+ return;
+ }
+
+ if (is_black (node.left) && is_black (node.left.left)) {
+ move_red_left (ref node);
+ }
+
+ remove_minimal (ref node.left, out key, out value);
+
+ fix_up (ref node);
+ }
+
+ private bool remove_from_node (ref Node<K, V>? node, K key) {
+ if (node == null) {
+ return false;
+ } else if (key_compare_func (key, node.key) < 0) {
+ weak Node<K,V> left = node.left;
+ if (left == null) {
+ return false;
+ }
+ if (is_black (left) && is_black (left.left)) {
+ move_red_left (ref node);
+ }
+ bool r = remove_from_node (ref node.left, key);
+ fix_up (ref node);
+ return r;
+ } else {
+ if (is_red (node.left)) {
+ rotate_right (ref node);
+ }
+
+ weak Node<K,V> r = node.right;
+ if (key_compare_func (key, node.key) == 0 && r == null) {
+ node = null;
+ _size--;
+ return true;
+ }
+ if (is_black (r) && is_black (r.left)) {
+ move_red_right (ref node);
+ }
+ if (key_compare_func (key, node.key) == 0) {
+ remove_minimal (ref node.right, out node.key, out node.value);
+ fix_up (ref node);
+ _size--;
+ return true;
+ } else {
+ bool re = remove_from_node (ref node.right, key);
+ fix_up (ref node);
+ return re;
+ }
+ }
+ }
+
+ private void fix_up (ref Node<K,V> node) {
+ if (is_black (node.left) && is_red (node.right)) {
+ rotate_left (ref node);
+ }
+ if (is_red (node.left) && is_black (node.right)) {
+ rotate_right (ref node);
+ }
+ }
+
+ public bool remove (K key) {
+ bool b = remove_from_node (ref root, key);
+ if (root != null) {
+ root.color = Node.Color.BLACK;
+ }
+ stamp++;
+ return b;
+ }
+
+ public void clear () {
+ root = null;
+ _size = 0;
+ stamp++;
+ }
+
+ [Compact]
+ private class Node<K, V> {
+ public enum Color {
+ RED,
+ BLACK;
+
+ public Color flip () {
+ if (this == RED) {
+ return BLACK;
+ } else {
+ return RED;
+ }
+ }
+ }
+
+ public Node (owned K key, owned V value, Node<K,V>? prev, Node<K,V>? next) {
+ this.key = (owned) key;
+ this.value = (owned) value;
+ this.color = Color.RED;
+ this.prev = prev;
+ this.next = next;
+ if (prev != null) {
+ prev.next = this;
+ }
+ if (next != null) {
+ next.prev = this;
+ }
+ }
+
+ ~Node () {
+ if (prev != null) {
+ prev.next = this.next;
+ }
+ if (next != null) {
+ next.prev = this.prev;
+ }
+ }
+
+ public void flip () {
+ color.flip ();
+ if (left != null) {
+ left.color = left.color.flip ();
+ }
+ if (right != null) {
+ right.color = right.color.flip ();
+ }
+ }
+
+ public K key;
+ public V value;
+ public Color color;
+ public Node<K, V>? left;
+ public Node<K, V>? right;
+ public weak Node<K, V>? prev;
+ public weak Node<K, V>? next;
+ }
+
+ private Node<K, V>? root;
+ private weak Node<K, V>? first;
+ private int stamp = 0;
+
+ private class KeySet<K,V> : Object, Iterable<K>, Collection<K>, Set<K> {
+ public TreeMap<K,V> map { construct; get; }
+
+ public KeySet (TreeMap<K,V> map) {
+ this.map = map;
+ }
+
+ public Type get_element_type () {
+ return typeof (K);
+ }
+
+ public Iterator<K> iterator () {
+ return new KeyIterator<K,V> (map);
+ }
+
+ public int size {
+ get { return map.size; }
+ }
+
+ public bool add (K key) {
+ assert_not_reached ();
+ }
+
+ public void clear () {
+ assert_not_reached ();
+ }
+
+ public bool remove (K key) {
+ assert_not_reached ();
+ }
+
+ public bool contains (K key) {
+ return map.contains (key);
+ }
+ }
+
+ private class ValueCollection<K,V> : Object, Iterable<K>, Collection<V> {
+ public TreeMap<K,V> map { construct; get; }
+
+ public ValueCollection (TreeMap map) {
+ this.map = map;
+ }
+
+ public Type get_element_type () {
+ return typeof (V);
+ }
+
+ public Iterator<V> iterator () {
+ return new ValueIterator<K,V> (map);
+ }
+
+ public int size {
+ get { return map.size; }
+ }
+
+ public bool add (V key) {
+ assert_not_reached ();
+ }
+
+ public void clear () {
+ assert_not_reached ();
+ }
+
+ public bool remove (V key) {
+ assert_not_reached ();
+ }
+
+ public 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 KeyIterator<K,V> : Object, Gee.Iterator<K> {
+ public TreeMap<K,V> map { construct; get; }
+ private int stamp;
+ construct {
+ stamp = map.stamp;
+ }
+
+ public KeyIterator (TreeMap<K,V> map) {
+ this.map = map;
+ }
+
+ public bool next () {
+ if (current != null) {
+ current = current.next;
+ return current != null;
+ } else if (!run){
+ run = true;
+ current = map.first;
+ return current != null;
+ } else {
+ return false;
+ }
+ }
+
+ public new K? get () {
+ assert (stamp == map.stamp);
+ assert (current != null);
+ return current.key;
+ }
+
+ private weak Node<K, V>? current;
+ private bool run = false;
+ }
+
+ private class ValueIterator<K,V> : Object, Gee.Iterator<V> {
+ public TreeMap<K,V> map { construct; get; }
+ private int stamp;
+ construct {
+ stamp = map.stamp;
+ }
+
+ public ValueIterator (TreeMap<K,V> map) {
+ this.map = map;
+ }
+
+ public bool next () {
+ if (current != null) {
+ current = current.next;
+ return current != null;
+ } else if (!run) {
+ run = true;
+ current = map.first;
+ return current != null;
+ } else {
+ return false;
+ }
+ }
+
+ public new V? get () {
+ assert (stamp == map.stamp);
+ assert (current != null);
+ return current.value;
+ }
+
+ private weak Node<K, V>? current;
+ private bool run = false;
+ }
+}
diff --git a/gee/treeset.vala b/gee/treeset.vala
new file mode 100644
index 0000000..0104bec
--- /dev/null
+++ b/gee/treeset.vala
@@ -0,0 +1,317 @@
+/* treeset.vala
+ *
+ * Copyright (C) 2009 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>
+ */
+
+using GLib;
+
+/**
+ * Left-leaning red-black tree implementation of the Set interface.
+ */
+public class Gee.TreeSet<G> : Object, Iterable<G>, Collection<G>, Set<G> {
+ public int size {
+ get {return _size;}
+ }
+
+ public CompareFunc compare_func { construct; get; }
+
+ private int _size = 0;
+
+ public TreeSet (CompareFunc compare_func = Gee.direct_compare) {
+ this.compare_func = compare_func;
+ }
+
+ public bool contains (G item) {
+ weak Node<G>? cur = root;
+ while (cur != null) {
+ int res = compare_func (item, cur.key);
+ if (res == 0) {
+ return true;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return false;
+ }
+
+ private void rotate_right (ref Node<G> root) {
+ Node<G> pivot = (owned) root.left;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.left = (owned) pivot.right;
+ pivot.right = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private void rotate_left (ref Node<G> root) {
+ Node<G> pivot = (owned) root.right;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.right = (owned) pivot.left;
+ pivot.left = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private bool is_red (Node<G>? n) {
+ return n != null && n.color == Node.Color.RED;
+ }
+
+ private bool is_black (Node<G>? n) {
+ return n == null || n.color == Node.Color.BLACK;
+ }
+
+ private void fix_up (ref Node<G> node) {
+ if (is_black (node.left) && is_red (node.right)) {
+ rotate_left (ref node);
+ }
+ if (is_red (node.left) && is_black (node.right)) {
+ rotate_right (ref node);
+ }
+ }
+
+ private bool add_to_node (ref Node<G>? node, owned G item, Node<G>? prev, Node<G>? next) {
+ if (node == null) {
+ node = new Node<G> ((owned) item, prev, next);
+ if (prev == null) {
+ first = node;
+ }
+ _size++;
+ return true;
+ }
+
+ if (is_red (node.left) && is_red (node.right)) {
+ node.flip ();
+ }
+
+ int cmp = compare_func (item, node.key);
+ if (cmp == 0) {
+ fix_up (ref node);
+ return false;
+ } else if (cmp < 0) {
+ bool r = add_to_node (ref node.left, item, node.prev, node);
+ fix_up (ref node);
+ return r;
+ } else {
+ bool r = add_to_node (ref node.right, item, node, node.next);
+ fix_up (ref node);
+ return r;
+ }
+ }
+
+ public bool add (G item) {
+ bool r = add_to_node (ref root, item, null, null);
+ root.color = Node.Color.BLACK;
+ stamp++;
+ return r;
+ }
+
+ private void move_red_left (ref Node<G> root) {
+ root.flip ();
+ if (is_red (root.right.left)) {
+ rotate_right (ref root.right);
+ rotate_left (ref root);
+ root.flip ();
+ }
+ }
+
+ private void move_red_right (ref Node<G> root) {
+ root.flip ();
+ if (is_red (root.left.left)) {
+ rotate_right (ref root.right);
+ root.flip ();
+ }
+ }
+
+ private void remove_minimal (ref Node<G> node, out G key) {
+ if (node.left == null) {
+ Node<G> n = (owned) node;
+ key = (owned) n.key;
+ node = null;
+ return;
+ }
+
+ if (is_black (node.left) && is_black (node.left.left)) {
+ move_red_left (ref node);
+ }
+
+ remove_minimal (ref node.left, out key);
+
+ fix_up (ref node);
+ }
+
+ private bool remove_from_node (ref Node<G>? node, G item) {
+ if (node == null) {
+ return false;
+ } else if (compare_func (item, node.key) < 0) {
+ weak Node<G> left = node.left;
+ if (left == null) {
+ return false;
+ }
+ if (is_black (left) && is_black (left.left)) {
+ move_red_left (ref node);
+ }
+ bool r = remove_from_node (ref node.left, item);
+ fix_up (ref node);
+ return r;
+ } else {
+ if (is_red (node.left)) {
+ rotate_right (ref node);
+ }
+
+ weak Node<G> r = node.right;
+ if (compare_func (item, node.key) == 0 && r == null) {
+ node = null;
+ _size--;
+ return true;
+ }
+ if (is_black (r) && is_black (r.left)) {
+ move_red_right (ref node);
+ }
+ if (compare_func (item, node.key) == 0) {
+ remove_minimal (ref node.right, out node.key);
+ fix_up (ref node);
+ _size--;
+ return true;
+ } else {
+ bool re = remove_from_node (ref node.right, item);
+ fix_up (ref node);
+ return re;
+ }
+ }
+ }
+
+ public bool remove (G item) {
+ bool b = remove_from_node (ref root, item);
+ if (root != null) {
+ root.color = Node.Color.BLACK;
+ }
+ stamp++;
+ return b;
+ }
+
+ public void clear () {
+ root = null;
+ _size = 0;
+ stamp++;
+ }
+
+ public Type get_element_type () {
+ return typeof (G);
+ }
+
+ public Gee.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ [Compact]
+ private class Node<G> {
+ public enum Color {
+ RED,
+ BLACK;
+
+ public Color flip () {
+ if (this == RED) {
+ return BLACK;
+ } else {
+ return RED;
+ }
+ }
+ }
+
+ public Node (owned G node, Node<G>? prev, Node<G>? next) {
+ this.key = (owned) node;
+ this.color = Color.RED;
+ this.prev = prev;
+ this.next = next;
+ if (prev != null) {
+ prev.next = this;
+ }
+ if (next != null) {
+ next.prev = this;
+ }
+ }
+
+ ~Node () {
+ if (prev != null) {
+ prev.next = this.next;
+ }
+ if (next != null) {
+ next.prev = this.prev;
+ }
+ }
+
+ public void flip () {
+ color.flip ();
+ if (left != null) {
+ left.color = left.color.flip ();
+ }
+ if (right != null) {
+ right.color = right.color.flip ();
+ }
+ }
+
+ public G key;
+ public Color color;
+ public Node<G>? left;
+ public Node<G>? right;
+ public weak Node<G>? prev;
+ public weak Node<G>? next;
+ }
+
+ private class Iterator<G> : Object, Gee.Iterator<G> {
+ public new TreeSet<G> set {construct; get;}
+ private int stamp;
+ construct {
+ stamp = set.stamp;
+ }
+
+ public Iterator (TreeSet<G> set) {
+ this.set = set;
+ }
+
+ public bool next () {
+ if (current != null) {
+ current = current.next;
+ return current != null;
+ } else if (!run){
+ run = true;
+ current = set.first;
+ return current != null;
+ } else {
+ return false;
+ }
+ }
+
+ public new G? get () {
+ assert (stamp == set.stamp);
+ assert (current != null);
+ return current.key;
+ }
+
+ private weak Node<G>? current;
+ private bool run = false;
+ }
+
+ private Node<G>? root;
+ private weak Node<G>? first;
+ private int stamp = 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cbfcb34..68cfec5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -38,3 +38,21 @@ $(testhashset_SOURCES): $(testhashset_VALASOURCES)
testhashset_LDADD = $(progs_ldadd)
EXTRA_DIST += $(testhashset_VALASOURCES)
+TEST_PROGS += testtreeset
+testtreeset_VALASOURCES = testtreeset.vala
+testtreeset_SOURCES = testtreeset.c testtreeset.h
+$(testtreeset_SOURCES): $(testtreeset_VALASOURCES)
+ $(VALAC) -C --basedir $(top_srcdir) --vapidir $(top_srcdir)/gee --pkg gee-1.0 $^
+ touch $@
+testtreeset_LDADD = $(progs_ldadd)
+EXTRA_DIST += $(testtreeset_VALASOURCES)
+
+TEST_PROGS += testtreemap
+testtreemap_VALASOURCES = testtreemap.vala
+testtreemap_SOURCES = testtreemap.c testtreemap.h
+$(testtreemap_SOURCES): $(testtreemap_VALASOURCES)
+ $(VALAC) -C --basedir $(top_srcdir) --vapidir $(top_srcdir)/gee --pkg gee-1.0 $^
+ touch $@
+testtreemap_LDADD = $(progs_ldadd)
+EXTRA_DIST += $(testtreemap_VALASOURCES)
+
diff --git a/tests/testtreemap.vala b/tests/testtreemap.vala
new file mode 100644
index 0000000..b92f3ef
--- /dev/null
+++ b/tests/testtreemap.vala
@@ -0,0 +1,310 @@
+/* testtreeset.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+using GLib;
+using Gee;
+
+const string CODE_NOT_REACHABLE = "*code should not be reached*";
+
+void test_treemap_get () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // Check get from empty map
+ assert (treemap.get ("foo") == null);
+
+ // Check get from map with one items
+ treemap.set ("key", "value");
+ assert (treemap.get ("key") == "value");
+
+ // Check get from non-existing key
+ assert (treemap.get ("foo") == null);
+
+ // Check get from map with multiple items
+ treemap.set ("key2", "value2");
+ treemap.set ("key3", "value3");
+ assert (treemap.get ("key") == "value");
+ assert (treemap.get ("key2") == "value2");
+ assert (treemap.get ("key3") == "value3");
+}
+
+void test_treemap_set () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // check map is empty
+ assert (treemap.size == 0);
+
+ // check set an item to map
+ treemap.set ("abc", "one");
+ assert (treemap.contains ("abc"));
+ assert (treemap.get ("abc") == "one");
+ assert (treemap.size == 1);
+
+ // check set an item to map with same value
+ treemap.set ("def", "one");
+ assert (treemap.contains ("def"));
+ assert (treemap.get ("abc") == "one");
+ assert (treemap.get ("def") == "one");
+ assert (treemap.size == 2);
+
+ // check set with same key
+ treemap.set ("def", "two");
+ assert (treemap.contains ("def"));
+ assert (treemap.get ("abc") == "one");
+ assert (treemap.get ("def") == "two");
+ assert (treemap.size == 2);
+}
+
+void test_treemap_remove () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // check removing when map is empty
+ treemap.remove ("foo");
+ assert (treemap.size == 0);
+
+ // add items
+ treemap.set ("aaa", "111");
+ treemap.set ("bbb", "222");
+ treemap.set ("ccc", "333");
+ treemap.set ("ddd", "444");
+ assert (treemap.size == 4);
+
+ // check remove on first place
+ treemap.remove ("aaa");
+ assert (treemap.size == 3);
+
+ // check remove in between
+ treemap.remove ("ccc");
+ assert (treemap.size == 2);
+
+ // check remove in last place
+ treemap.remove ("ddd");
+ assert (treemap.size == 1);
+
+ // check remove invalid key
+ treemap.remove ("bar");
+
+ // check remove last in map
+ treemap.remove ("bbb");
+ assert (treemap.size == 0);
+}
+
+void test_treemap_contains () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // Check on empty map
+ assert (!treemap.contains ("111"));
+
+ // Check items
+ treemap.set ("10", "111");
+ assert (treemap.contains ("10"));
+ assert (!treemap.contains ("20"));
+ assert (!treemap.contains ("30"));
+
+ assert (treemap.get ("10") == "111");
+
+ treemap.set ("20", "222");
+ assert (treemap.contains ("10"));
+ assert (treemap.contains ("20"));
+ assert (!treemap.contains ("30"));
+
+ assert (treemap.get ("10") == "111");
+ assert (treemap.get ("20") == "222");
+
+ treemap.set ("30", "333");
+ assert (treemap.contains ("10"));
+ assert (treemap.contains ("20"));
+ assert (treemap.contains ("30"));
+
+ assert (treemap.get ("10") == "111");
+ assert (treemap.get ("20") == "222");
+ assert (treemap.get ("30") == "333");
+
+ // Clear and recheck
+ treemap.clear ();
+ assert (!treemap.contains ("10"));
+ assert (!treemap.contains ("20"));
+ assert (!treemap.contains ("30"));
+
+ var treemapOfInt = new TreeMap<int,int> ();
+
+ // Check items
+ treemapOfInt.set (10, 111);
+ assert (treemapOfInt.contains (10));
+ assert (!treemapOfInt.contains (20));
+ assert (!treemapOfInt.contains (30));
+
+ assert (treemapOfInt.get (10) == 111);
+
+ treemapOfInt.set (20, 222);
+ assert (treemapOfInt.contains (10));
+ assert (treemapOfInt.contains (20));
+ assert (!treemapOfInt.contains (30));
+
+ assert (treemapOfInt.get (10) == 111);
+ assert (treemapOfInt.get (20) == 222);
+
+ treemapOfInt.set (30, 333);
+ assert (treemapOfInt.contains (10));
+ assert (treemapOfInt.contains (20));
+ assert (treemapOfInt.contains (30));
+
+ assert (treemapOfInt.get (10) == 111);
+ assert (treemapOfInt.get (20) == 222);
+ assert (treemapOfInt.get (30) == 333);
+}
+
+void test_treemap_size () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // Check empty map
+ assert (treemap.size == 0);
+
+ // Check when one item
+ treemap.set ("1", "1");
+ assert (treemap.size == 1);
+
+ // Check when more items
+ treemap.set ("2", "2");
+ assert (treemap.size == 2);
+
+ // Check when items cleared
+ treemap.clear ();
+ assert (treemap.size == 0);
+}
+
+void test_treemap_get_keys () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // Check keys on empty map
+ var keySet = treemap.get_keys ();
+ assert (keySet.size == 0);
+
+ // Check keys on map with one item
+ treemap.set ("aaa", "111");
+ assert (keySet.size == 1);
+ assert (keySet.contains ("aaa"));
+ keySet = treemap.get_keys ();
+ assert (keySet.size == 1);
+ assert (keySet.contains ("aaa"));
+
+ // Check modify key set directly
+ if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT | TestTrapFlags.SILENCE_STDERR)) {
+ keySet.add ("ccc");
+ return;
+ }
+ Test.trap_assert_failed ();
+ Test.trap_assert_stderr (CODE_NOT_REACHABLE);
+
+ // Check keys on map with multiple items
+ treemap.set ("bbb", "222");
+ assert (keySet.size == 2);
+ assert (keySet.contains ("aaa"));
+ assert (keySet.contains ("bbb"));
+ keySet = treemap.get_keys ();
+ assert (keySet.size == 2);
+ assert (keySet.contains ("aaa"));
+ assert (keySet.contains ("bbb"));
+
+ // Check keys on map clear
+ treemap.clear ();
+ assert (keySet.size == 0);
+ keySet = treemap.get_keys ();
+ assert (keySet.size == 0);
+}
+
+void test_treemap_get_values () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+
+ // Check keys on empty map
+ var valueCollection = treemap.get_values ();
+ assert (valueCollection.size == 0);
+
+ // Check keys on map with one item
+ treemap.set ("aaa", "111");
+ assert (valueCollection.size == 1);
+ assert (valueCollection.contains ("111"));
+ valueCollection = treemap.get_values ();
+ assert (valueCollection.size == 1);
+ assert (valueCollection.contains ("111"));
+
+ // Check modify key set directly
+ if (Test.trap_fork (0, TestTrapFlags.SILENCE_STDOUT | TestTrapFlags.SILENCE_STDERR)) {
+ valueCollection.add ("ccc");
+ return;
+ }
+ Test.trap_assert_failed ();
+ Test.trap_assert_stderr (CODE_NOT_REACHABLE);
+
+ // Check keys on map with multiple items
+ treemap.set ("bbb", "222");
+ assert (valueCollection.size == 2);
+ assert (valueCollection.contains ("111"));
+ assert (valueCollection.contains ("222"));
+ valueCollection = treemap.get_values ();
+ assert (valueCollection.size == 2);
+ assert (valueCollection.contains ("111"));
+ assert (valueCollection.contains ("222"));
+
+ // Check keys on map clear
+ treemap.clear ();
+ assert (valueCollection.size == 0);
+ valueCollection = treemap.get_values ();
+ assert (valueCollection.size == 0);
+}
+
+void test_treemap_clear () {
+ var treemap = new TreeMap<string,string> ((CompareFunc) strcmp, str_equal);
+ assert (treemap.size == 0);
+
+ // Check clear on empty map
+ treemap.clear ();
+ assert (treemap.size == 0);
+
+ // Check clear one item
+ treemap.set ("1", "1");
+ assert (treemap.size == 1);
+ treemap.clear ();
+ assert (treemap.size == 0);
+
+ // Check clear multiple items
+ treemap.set ("1", "1");
+ treemap.set ("2", "2");
+ treemap.set ("3", "3");
+ assert (treemap.size == 3);
+ treemap.clear ();
+ assert (treemap.size == 0);
+}
+
+void main (string[] args) {
+ Test.init (ref args);
+
+ Test.add_func ("/TreeMap/Map/get", test_treemap_get);
+ Test.add_func ("/TreeMap/Map/set", test_treemap_set);
+ Test.add_func ("/TreeMap/Map/remove", test_treemap_remove);
+ Test.add_func ("/TreeMap/Map/contains", test_treemap_contains);
+ Test.add_func ("/TreeMap/Map/size", test_treemap_size);
+ Test.add_func ("/TreeMap/Map/get_keys", test_treemap_get_keys);
+ Test.add_func ("/TreeMap/Map/get_values", test_treemap_get_values);
+ Test.add_func ("/TreeMap/Map/clear", test_treemap_clear);
+
+ Test.run ();
+}
diff --git a/tests/testtreeset.vala b/tests/testtreeset.vala
new file mode 100644
index 0000000..a3d6385
--- /dev/null
+++ b/tests/testtreeset.vala
@@ -0,0 +1,287 @@
+/* testtreeset.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+using GLib;
+using Gee;
+
+void test_treeset_add () {
+ // Check adding of strings
+ var treeset = new TreeSet<string> ((CompareFunc) strcmp);
+
+ treeset.add ("42");
+ assert (treeset.contains ("42"));
+ assert (treeset.size == 1);
+
+ treeset.add ("43");
+ assert (treeset.contains ("42"));
+ assert (treeset.contains ("43"));
+ assert (treeset.size == 2);
+
+ // Check add same element
+ assert (treeset.size == 2);
+ treeset.add ("43");
+ assert (treeset.contains ("42"));
+ assert (treeset.contains ("43"));
+ assert (treeset.size == 2);
+
+ // Check adding of ints
+ var treesetInt = new TreeSet<int> ();
+
+ treesetInt.add (42);
+ assert (treesetInt.contains (42));
+ assert (treesetInt.size == 1);
+
+ treesetInt.add (43);
+ assert (treesetInt.contains (42));
+ assert (treesetInt.contains (43));
+ assert (treesetInt.size == 2);
+
+ // Check add same element
+ assert (treesetInt.size == 2);
+ treesetInt.add (43);
+ assert (treesetInt.contains (42));
+ assert (treesetInt.contains (43));
+ assert (treesetInt.size == 2);
+
+ // Check adding of objects
+ var treesetObject = new TreeSet<Object> ();
+
+ var fooObject = new Object();
+ treesetObject.add (fooObject);
+ assert (treesetObject.contains (fooObject));
+ assert (treesetObject.size == 1);
+
+ var fooObject2 = new Object();
+ treesetObject.add (fooObject2);
+ assert (treesetObject.contains (fooObject));
+ assert (treesetObject.contains (fooObject2));
+ assert (treesetObject.size == 2);
+
+ // Check add same element
+ assert (treesetObject.size == 2);
+ treesetObject.add (fooObject2);
+ assert (treesetObject.contains (fooObject));
+ assert (treesetObject.contains (fooObject2));
+ assert (treesetObject.size == 2);
+}
+
+void test_treeset_clear () {
+ var treeset = new TreeSet<string> ((CompareFunc) strcmp);
+ assert (treeset.size == 0);
+
+ // Check clear on empty set
+ treeset.clear ();
+ assert (treeset.size == 0);
+
+ // Check clear one item
+ treeset.add ("1");
+ assert (treeset.size == 1);
+ treeset.clear ();
+ assert (treeset.size == 0);
+
+ // Check clear multiple items
+ treeset.add ("1");
+ treeset.add ("2");
+ treeset.add ("3");
+ assert (treeset.size == 3);
+ treeset.clear ();
+ assert (treeset.size == 0);
+}
+
+void test_treeset_contains () {
+ var treesetString = new TreeSet<string> ((CompareFunc) strcmp);
+
+ // Check on empty set
+ assert (!treesetString.contains ("1"));
+
+ // Check items
+ treesetString.add ("10");
+ assert (treesetString.contains ("10"));
+ assert (!treesetString.contains ("20"));
+ assert (!treesetString.contains ("30"));
+
+ treesetString.add ("20");
+ assert (treesetString.contains ("10"));
+ assert (treesetString.contains ("20"));
+ assert (!treesetString.contains ("30"));
+
+ treesetString.add ("30");
+ assert (treesetString.contains ("10"));
+ assert (treesetString.contains ("20"));
+ assert (treesetString.contains ("30"));
+
+ // Clear and recheck
+ treesetString.clear ();
+ assert (!treesetString.contains ("10"));
+ assert (!treesetString.contains ("20"));
+ assert (!treesetString.contains ("30"));
+
+ var treesetInt = new TreeSet<int> ();
+
+ // Check items
+ treesetInt.add (10);
+ assert (treesetInt.contains (10));
+ assert (!treesetInt.contains (20));
+ assert (!treesetInt.contains (30));
+
+ treesetInt.add (20);
+ assert (treesetInt.contains (10));
+ assert (treesetInt.contains (20));
+ assert (!treesetInt.contains (30));
+
+ treesetInt.add (30);
+ assert (treesetInt.contains (10));
+ assert (treesetInt.contains (20));
+ assert (treesetInt.contains (30));
+
+ // Clear and recheck
+ treesetInt.clear ();
+ assert (!treesetInt.contains (10));
+ assert (!treesetInt.contains (20));
+ assert (!treesetInt.contains (30));
+}
+
+void test_treeset_remove () {
+ var treesetString = new TreeSet<string> ((CompareFunc) strcmp);
+
+ // Check remove if list is empty
+ treesetString.remove ("42");
+
+ // Add 5 different elements
+ treesetString.add ("42");
+ treesetString.add ("43");
+ treesetString.add ("44");
+ treesetString.add ("45");
+ treesetString.add ("46");
+ assert (treesetString.size == 5);
+
+ // Check remove first
+ treesetString.remove ("42");
+ assert (treesetString.size == 4);
+ assert (treesetString.contains ("43"));
+ assert (treesetString.contains ("44"));
+ assert (treesetString.contains ("45"));
+ assert (treesetString.contains ("46"));
+
+ // Check remove last
+ treesetString.remove ("46");
+ assert (treesetString.size == 3);
+ assert (treesetString.contains ("43"));
+ assert (treesetString.contains ("44"));
+ assert (treesetString.contains ("45"));
+
+ // Check remove in between
+ treesetString.remove ("44");
+ assert (treesetString.size == 2);
+ assert (treesetString.contains ("43"));
+ assert (treesetString.contains ("45"));
+
+ // Check removing of int element
+ var treesetInt = new TreeSet<int> ();
+
+ // Add 5 different elements
+ treesetInt.add (42);
+ treesetInt.add (43);
+ treesetInt.add (44);
+ treesetInt.add (45);
+ treesetInt.add (46);
+ assert (treesetInt.size == 5);
+
+ // Remove first
+ treesetInt.remove (42);
+ assert (treesetInt.size == 4);
+ assert (treesetInt.contains (43));
+ assert (treesetInt.contains (44));
+ assert (treesetInt.contains (45));
+ assert (treesetInt.contains (46));
+
+ // Remove last
+ treesetInt.remove (46);
+ assert (treesetInt.size == 3);
+ assert (treesetInt.contains (43));
+ assert (treesetInt.contains (44));
+ assert (treesetInt.contains (45));
+
+ // Remove in between
+ treesetInt.remove (44);
+ assert (treesetInt.size == 2);
+ assert (treesetInt.contains (43));
+ assert (treesetInt.contains (45));
+}
+
+void test_treeset_size () {
+ var treeset = new TreeSet<string> ((CompareFunc) strcmp);
+
+ // Check empty list
+ assert (treeset.size == 0);
+
+ // Check when one item
+ treeset.add ("1");
+ assert (treeset.size == 1);
+
+ // Check when more items
+ treeset.add ("2");
+ assert (treeset.size == 2);
+
+ // Check when items cleared
+ treeset.clear ();
+ assert (treeset.size == 0);
+}
+
+void test_treeset_iterator () {
+ var treeset = new TreeSet<string> ((CompareFunc) strcmp);
+
+ // Check iterate empty list
+ var iterator = treeset.iterator ();
+ assert (!iterator.next());
+
+ // Check iterate list
+ treeset.add ("42");
+ treeset.add ("43");
+
+ iterator = treeset.iterator ();
+
+ assert (iterator.next());
+ string firstString = iterator.get();
+ assert (treeset.contains (firstString));
+ assert (firstString == "42");
+
+ assert (iterator.next());
+ string secondString = iterator.get();
+ assert (treeset.contains (secondString));
+ assert (secondString == "43");
+
+ assert (!iterator.next());
+}
+
+void main (string[] args) {
+ Test.init (ref args);
+
+ Test.add_func ("/TreeSet/Collection/add", test_treeset_add);
+ Test.add_func ("/TreeSet/Collection/clear", test_treeset_clear);
+ Test.add_func ("/TreeSet/Collection/contains", test_treeset_contains);
+ Test.add_func ("/TreeSet/Collection/remove", test_treeset_remove);
+ Test.add_func ("/TreeSet/Collection/size", test_treeset_size);
+ Test.add_func ("/TreeSet/Iterable/iterator", test_treeset_iterator);
+
+ Test.run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]