[libgee] Introduce PriorityQueue implementation of the Queue interface



commit 03b56a8a993d332d4bc410c686248d786f03f34e
Author: Didier 'Ptitjes <ptitjes free fr>
Date:   Sat Sep 12 00:09:36 2009 +0200

    Introduce PriorityQueue implementation of the Queue interface

 gee/Makefile.am              |    2 +
 gee/abstractqueue.vala       |   65 ++++
 gee/priorityqueue.vala       |  823 ++++++++++++++++++++++++++++++++++++++++++
 tests/Makefile.am            |    1 +
 tests/testmain.vala          |    1 +
 tests/testpriorityqueue.vala |  104 ++++++
 6 files changed, 996 insertions(+), 0 deletions(-)
---
diff --git a/gee/Makefile.am b/gee/Makefile.am
index 592625e..22f6113 100644
--- a/gee/Makefile.am
+++ b/gee/Makefile.am
@@ -17,6 +17,7 @@ libgee_la_VALASOURCES = \
 	abstractcollection.vala \
 	abstractlist.vala \
 	abstractmap.vala \
+	abstractqueue.vala \
 	abstractset.vala \
 	arraylist.vala \
 	collection.vala \
@@ -33,6 +34,7 @@ libgee_la_VALASOURCES = \
 	map.vala \
 	multimap.vala \
 	multiset.vala \
+	priorityqueue.vala \
 	queue.vala \
 	readonlycollection.vala \
 	readonlylist.vala \
diff --git a/gee/abstractqueue.vala b/gee/abstractqueue.vala
new file mode 100644
index 0000000..3cc9cca
--- /dev/null
+++ b/gee/abstractqueue.vala
@@ -0,0 +1,65 @@
+/* abstractqueue.vala
+ *
+ * Copyright (C) 2009  Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the { link Gee.Queue} interface.
+ *
+ * Contains common code shared by all queue implementations.
+ *
+ * @see Gee.PriorityQueue
+ */
+public abstract class Gee.AbstractQueue<G> : Gee.AbstractCollection<G>, Queue<G> {
+	/**
+	 * @inheritDoc
+	 */
+	public abstract int capacity { get; }
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract int remaining_capacity { get; }
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract bool is_full { get; }
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract bool offer (G element);
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract G? peek ();
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract G? poll ();
+
+	/**
+	 * @inheritDoc
+	 */
+	public abstract int drain (Collection<G> recipient, int amount = -1);
+}
diff --git a/gee/priorityqueue.vala b/gee/priorityqueue.vala
new file mode 100644
index 0000000..7bcf503
--- /dev/null
+++ b/gee/priorityqueue.vala
@@ -0,0 +1,823 @@
+/* abstractqueue.vala
+ *
+ * Copyright (C) 2009  Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * A unbounded priority queue implementation of the { link Gee.Queue}.
+ *
+ * The elements of the priority queue are ordered according to their natural
+ * ordering, or by a compare_func provided at queue construction time. A
+ * priority queue does not permit null elements and does not have bounded
+ * capacity.
+ *
+ * This implementation provides O(1) time for offer and peek methods, and
+ * O(log n) for poll method. It is based on the algorithms described by
+ * Boyapati Chandra Sekhar in:
+ *
+ *   "Worst Case Efficient Data Structures
+ *      for Priority Queues and Deques with Heap Order"
+ *   Boyapati Chandra Sekhar (under the guidance of Prof. C. Pandu Rangan)
+ *   Department of Computer Science and Engineering
+ *   Indian Institute of Technology, Madras
+ *   May 1996
+ */
+public class Gee.PriorityQueue<G> : Gee.AbstractQueue<G> {
+
+	/**
+	 * The elements' comparator function.
+	 */
+	public CompareFunc compare_func { private set; get; }
+
+	private int _size = 0;
+	private int _stamp = 0;
+	private Type1Node<G>? _r = null;
+	private Type2Node<G>? _r_prime = null;
+	private Type2Node<G>? _lm_head = null;
+	private Type2Node<G>? _lm_tail = null;
+	private Type1Node<G>? _p = null;
+	private Type1Node<G>?[] _a = new Type1Node<G>[0];
+	private NodePair<G>? _lp_head = null;
+	private NodePair<G>? _lp_tail = null;
+	private bool[] _b = new bool[0];
+	private Type1Node<G>? _ll_head = null;
+	private Type1Node<G>? _ll_tail = null;
+
+	public PriorityQueue (CompareFunc? compare_func = null) {
+		if (compare_func == null) {
+			compare_func = Functions.get_compare_func_for (typeof (G));
+		}
+		this.compare_func = compare_func;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override int capacity {
+		get { return UNBOUNDED_CAPACITY; }
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override int remaining_capacity {
+		get { return UNBOUNDED_CAPACITY; }
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override bool is_full {
+		get { return false; }
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override bool offer (G element) {
+		if (_r == null) {
+			_r = new Type1Node<G> (element);
+			_p = _r;
+		} else if (_r_prime == null) {
+			_r_prime = new Type2Node<G> (element);
+			_r_prime.parent = _r;
+			_r.type2_child = _r_prime;
+		} else {
+			// Form a tree with a single node N of type I consisting of element e
+			Type1Node<G> node = new Type1Node<G> (element);
+
+			//Add(Q, N)
+			_add (node);
+		}
+
+		_stamp++;
+		_size++;
+		return true;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override G? peek () {
+		if (_r == null) {
+			return null;
+		}
+		return _r.data;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override G? poll () {
+		// 1a. M inElement <- R.element
+		if (_r == null) {
+			return null;
+		}
+		G min = _r.data;
+		_stamp++;
+		_size--;
+
+		// 1b. R.element = R'.element
+		if (_r_prime == null) {
+			_r = null;
+			_p = null;
+			return min;
+		}
+		_r.data = _r_prime.data;
+
+		// 1c. R'' <- The child of R' containing the minimum element among the children of R'
+		if (_r_prime.type1_children_head == null) {
+			_remove_type2_node (_r_prime);
+			_r_prime = null;
+			return min;
+		}
+		Type1Node<G>? r_second = null;
+		Type1Node<G> node = _r_prime.type1_children_head;
+		while (node != null) {
+			if (r_second == null || _compare (node, r_second) < 0) {
+				r_second = node;
+			}
+			node = node.brothers_next;
+		}
+
+		// 1d. R'.element <- R''.element
+		_r_prime.data = r_second.data;
+
+		// 2a. Delete the subtree rooted at R'' from Q
+		_remove_type1_node (r_second);
+
+		// 2b. For all children N of type I of R'' do make N a child of R' of Q
+		node = r_second.type1_children_head;
+		while (node != null) {
+			Type1Node<G> next = node.brothers_next;
+			_remove_type1_node (node);
+			_add_in_r_prime (node);
+			node = next;
+		}
+
+		// 3a. If R'' has no child of type II then goto Step 4.
+		if (r_second.type2_child != null) {
+			// 3b. Let M' be the child of type II of R''. Insert(Q, M'.element)
+			Type2Node<G> m_prime = r_second.type2_child;
+			_remove_type2_node (m_prime);
+			offer (m_prime.data);
+
+			// 3c. For all children N of M do make N a child of R' of Q
+			node = m_prime.type1_children_head;
+			while (node != null) {
+				Type1Node<G> next = node.brothers_next;
+				_remove_type1_node (node);
+				_add_in_r_prime (node);
+				node = next;
+			}
+		}
+
+		// 4. Adjust(Q, P, P)
+		_adjust (_p, _p);
+
+		// 5a. if LM is empty then goto Step 6
+		if (_lm_head != null) {
+			// 5b. M <- Head(LM); LM <- Tail(LM)
+			Type2Node<G> m = _lm_head;
+
+			// 5c. Delete M from Q
+			_remove_type2_node (m);
+
+			// 5d. I nsert(Q, M.element)
+			offer (m.data);
+
+			// 5e. For all children N of M do make M a child of R' of Q
+			node = m.type1_children_head;
+			while (node != null) {
+				Type1Node<G> next = node.brothers_next;
+				_remove_type1_node (node);
+				_add_in_r_prime (node);
+				node = next;
+			}
+		}
+
+		// 6. While among the children of R' there exist any two different nodes Ri and Rj
+		// such that Ri.degree = Rj.degree do Link(Q, Ri, Rj)
+		while (_check_linkable ()) {}
+
+		if (_p == null) {
+			_p = _r;
+		}
+
+		// 7. Return MinElement
+		return min;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override int drain (Collection<G> recipient, int amount = -1) {
+		if (amount == -1) {
+			amount = this._size;
+		}
+		for (int i = 0; i < amount; i++) {
+			if (this._size == 0) {
+				return i;
+			}
+			recipient.add (poll ());
+		}
+		return amount;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override int size {
+		get { return _size; }
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override bool contains (G item) {
+		foreach (G an_item in this) {
+			if (compare_func (item, an_item) == 0) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override bool add (G item) {
+		return offer (item);
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override bool remove (G item) {
+		Iterator<G> iterator = new Iterator<G> (this);
+		while (iterator.next ()) {
+			G an_item = iterator.get ();
+			if (compare_func (item, an_item) == 0) {
+				_delete (iterator.get_node ());
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override void clear () {
+		_size = 0;
+		_r = null;
+		_r_prime = null;
+		_lm_head = null;
+		_lm_tail = null;
+		_p = null;
+		_a = new Type1Node<G>[0];
+		_lp_head = null;
+		_lp_tail = null;
+		_b = new bool[0];
+		_ll_head = null;
+		_ll_tail = null;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public override Gee.Iterator<G> iterator () {
+		return new Iterator<G> (this);
+	}
+
+	private inline int _compare (Node<G> node1, Node<G> node2) {
+		// Assume there can't be two nodes pending drop
+		if (node1.pending_drop) {
+			return -1;
+		} else if (node2.pending_drop) {
+			return 1;
+		} else {
+			return compare_func (node1.data, node2.data);
+		}
+	}
+
+	private inline void _swap_data (Node<G> node1, Node<G> node2) {
+		G temp_data = (owned) node1.data;
+		bool temp_pending_drop = node1.pending_drop;
+		node1.data = (owned) node2.data;
+		node1.pending_drop = node2.pending_drop;
+		node2.data = (owned) temp_data;
+		node2.pending_drop = temp_pending_drop;
+	}
+
+	private void _link (Type1Node<G> ri, Type1Node<G> rj) {
+		assert (ri.degree () == rj.degree ());
+
+		// Delete the subtrees rooted at Ri and Rj from Q
+		_remove_type1_node (ri);
+		_remove_type1_node (rj);
+
+		// If Ri.element > Rj.element then Swap(Ri,Rj)
+		if (_compare (ri, rj) > 0) {
+			Type1Node<G> temp = ri;
+			ri = rj;
+			rj = temp;
+		}
+
+		// Make Rj the last child of Ri
+		_add_to (rj, ri);
+
+		// Make Ri (whose degree now = d+1) a child of R' of Q
+		_add_in_r_prime (ri);
+	}
+
+	private void _add (Type1Node<G> n) {
+		// Make N a child of R' of Q
+		_add_in_r_prime (n);
+
+		// If N.element < R'.element then Swap(N.element, R'.element)
+		if (_compare (n, _r_prime) < 0) {
+			_swap_data (n, _r_prime);
+		}
+
+		// If R'.element < R.element then Swap(R'.element, R.element)
+		if (_compare (_r_prime, _r) < 0) {
+			_swap_data (_r_prime, _r);
+		}
+
+		// If among the children of R' there exist any two different nodes Ri and Rj
+		// such that Ri.degree = Rj.degree then Link(Q, Ri, Rj)
+		_check_linkable ();
+	}
+
+	private bool _check_linkable () {
+		if (_lp_head != null) {
+			NodePair<G> pair = _lp_head;
+			if (_lp_head.lp_next != null) {
+				_lp_head.lp_next.lp_prev = null;
+			}
+			_lp_head = _lp_head.lp_next;
+			_link (pair.node1, pair.node2);
+			return true;
+		}
+		return false;
+	}
+
+	private Node<G> _re_insert (Type1Node<G> n) {
+		assert (n != _r);
+
+		//Parent <- N.parent
+		Node<G> parent = n.parent;
+
+		// Delete the subtree rooted at N from Q
+		_remove_type1_node (n);
+
+		// Add(Q, N)
+		_add (n);
+
+		// Return Parent
+		return parent;
+	}
+
+	private void _adjust (Type1Node<G> p1, Type1Node<G> p2) {
+		// If M.lost <= 1 for all nodes M in Q then return
+		if (_ll_head == null) {
+			return;
+		}
+
+		// If P1.lost > P2.lost then M <- P1 else M <- P2
+		Type1Node<G> m;
+		if (p1.lost > p2.lost) {
+			m = p1;
+		} else {
+			m = p2;
+		}
+
+		// If M.lost <= 1 then M <- M' for some node M' in Q such that M'.lost > 1
+		if (m.lost <= 1) {
+			m = _ll_head;
+			if (_ll_head.ll_next != null) {
+				_ll_head.ll_next.ll_prev = null;
+			}
+			_ll_head = _ll_head.ll_next;
+		}
+
+		// P <- ReInsert(Q, M)
+		_p = (Type1Node<G>) _re_insert (m);
+	}
+
+	private void _delete (Node<G> n) {
+		// DecreaseKey(Q, N, infinite)
+		_decrease_key (n);
+
+		// DeleteMin(Q)
+		poll ();
+	}
+
+	private void _decrease_key (Node<G> n) {
+		n.pending_drop = true;
+
+		// If (N = R or R') and (R'.element < R.element) then
+		// Swap(R'.element, R.element); return
+		if (n == _r || n == _r_prime) {
+			if (_r_prime != null && _compare (_r_prime, _r) < 0) {
+				_swap_data (_r_prime, _r);
+			}
+			return;
+		}
+
+		// If (N is of type II) and (N.element < N.parent.element) then
+		// Swap(N.element, N.parent.element); N <- N.parent
+		if (n is Type2Node && _compare (n, n.parent) < 0) {
+			_swap_data (n, n.parent);
+			n = n.parent;
+		}
+
+		// If N.element >= N.parent.element then return
+		if (n.parent != null && _compare (n, n.parent) >= 0) {
+			return;
+		}
+
+		// P' <- ReInsert(Q, N)
+		Node<G> p_prime = _re_insert ((Type1Node<G>) n);
+
+		if (p_prime is Type2Node) {
+			// Adjust(Q, P, P);
+			_adjust (_p, _p);
+		} else {
+			// Adjust(Q, P, P');
+			_adjust (_p, (Type1Node<G>) p_prime);
+		}
+	}
+
+	private void _add_to (Type1Node<G> node, Type1Node<G> parent) {
+		parent.add (node);
+		parent.lost = 0;
+	}
+
+	private void _add_in_r_prime (Type1Node<G> node) {
+		int degree = node.degree ();
+
+		Type1Node<G>? insertion_point = null;
+		for (int i = degree - 1; i >= 0; i--) {
+			if (i >= _a.length) {
+				continue;
+			}
+			if (_a[i] != null) {
+				insertion_point = _a[i];
+				break;
+			}
+		}
+
+		if (insertion_point == null) {
+			node.brothers_prev = _r_prime.type1_children_tail;
+			if (node.brothers_prev != null) {
+				node.brothers_prev.brothers_next = node;
+			}
+			_r_prime.type1_children_tail = node;
+		} else {
+			if (insertion_point.brothers_prev != null) {
+				insertion_point.brothers_prev.brothers_next = node;
+				node.brothers_prev = insertion_point.brothers_prev;
+			} else {
+				_r_prime.type1_children_head = node;
+			}
+
+			node.brothers_next = insertion_point;
+			insertion_point.brothers_prev = node;
+		}
+		if (_r_prime.type1_children_head == null) {
+			_r_prime.type1_children_head = node;
+		}
+		node.parent = _r_prime;
+
+		if (degree >= _a.length) {
+			_a.resize (degree + 1);
+			_b.resize (degree + 1);
+		}
+		if (_a[degree] == null) {
+			_a[degree] = node;
+			_b[degree] = true;
+		} else {
+			if (_b[degree] == true) {
+				NodePair<G> pair = new NodePair<G> (node.brothers_prev, node);
+				node.brothers_prev.pair = pair;
+				node.pair = pair;
+				if (_lp_head == null) {
+					_lp_head = pair;
+					_lp_tail = pair;
+				} else {
+					pair.lp_prev = _lp_tail;
+					if (_lp_tail != null) {
+						_lp_tail.lp_next = pair;
+					}
+					_lp_tail = pair.lp_prev;
+				}
+				_b[degree] = false;
+			} else {
+				_b[degree] = true;
+			}
+		}
+	}
+
+	private void _remove_type1_node (Type1Node<G> node) {
+		if (node.parent == _r_prime) {
+			// Maintain the A and B arrays
+			int degree = node.degree ();
+			if (_a[degree] == node) {
+				Type1Node<G> next = node.brothers_next;
+				if (next != null && next.degree () == degree) {
+					_a[degree] = next;
+					_b[degree] = ! _b[degree];
+				} else {
+					_a[degree] = null;
+					_b[degree] = false;
+
+					int i = degree;
+					while (_a[i] == null) {
+						i--;
+					}
+					_a.resize (i + 1);
+					_b.resize (i + 1);
+				}
+			}
+		} else if (node.parent != null && node.parent.parent != _r_prime) {
+			// Increment parent's lost count
+			Type1Node<G> parent = (Type1Node<G>) node.parent;
+			parent.lost++;
+
+			// And add it to LL if needed
+			if (parent.lost > 1) {
+				if (_ll_head == null) {
+					_ll_head = parent;
+					_ll_tail = parent;
+				} else {
+					parent.ll_prev = _ll_tail;
+					if (_ll_tail != null) {
+						_ll_tail.ll_next = parent;
+					}
+					_ll_tail = node.ll_prev;
+				}
+			}
+		}
+
+		// Check whether removed node is P
+		if (node == _p) {
+			_p = null;
+		}
+
+		// Maintain LL
+		if (node.ll_prev != null) {
+			node.ll_prev.ll_next = node.ll_next;
+		} else {
+			_ll_head = node.ll_next;
+		}
+		if (node.ll_next != null) {
+			node.ll_next.ll_prev = node.ll_prev;
+		} else {
+			_ll_tail = node.ll_prev;
+		}
+
+		// Maintain LP
+		if (node.pair != null) {
+			NodePair<G> pair = node.pair;
+			Type1Node<G> other = (pair.node1 == node ? pair.node2 : pair.node1);
+			node.pair = null;
+			other.pair = null;
+			if (pair.lp_prev != null) {
+				pair.lp_prev.lp_next = pair.lp_next;
+			} else {
+				_lp_head = pair.lp_next;
+			}
+			if (pair.lp_next != null) {
+				pair.lp_next.lp_prev = pair.lp_prev;
+			} else {
+				_lp_tail = pair.lp_prev;
+			}
+		}
+
+		// Maintain brothers list
+		node.remove ();
+	}
+
+	private void _remove_type2_node (Type2Node<G> node) {
+		((Type1Node<G>) node.parent).type2_child = null;
+		node.parent = null;
+
+		// Maintain LM
+		if (node != _r_prime) {
+			if (node.lm_prev != null) {
+				node.lm_prev.lm_next = node.lm_next;
+			} else {
+				_lm_head = node.lm_next;
+			}
+			if (node.lm_next != null) {
+				node.lm_next.lm_prev = node.lm_prev;
+			} else {
+				_lm_tail = node.lm_prev;
+			}
+			node.lm_next = null;
+			node.lm_prev = null;
+		}
+	}
+
+	private class Node<G> {
+		public G data;
+		public weak Node<G>? parent = null;
+
+		public int type1_children_count;
+		public Type1Node<G>? type1_children_head = null;
+		public Type1Node<G>? type1_children_tail = null;
+
+		public bool pending_drop;
+
+		public Node (G data) {
+			this.data = data;
+		}
+
+		public virtual int degree () {
+			return type1_children_count;
+		}
+
+		public string children_to_string () {
+			StringBuilder builder = new StringBuilder ();
+			bool first = true;
+			Type1Node<G> child = type1_children_head;
+			while (child != null) {
+				if (!first) {
+					builder.append (", ");
+					first = false;
+				}
+				builder.append (child.to_string ());
+				child = child.brothers_next;
+			}
+			return builder.str;
+		}
+
+		public virtual string to_string () {
+			return "";
+		}
+	}
+
+	private class Type1Node<G> : Node<G> {
+		public uint lost;
+		public weak Type1Node<G>? brothers_prev = null;
+		public Type1Node<G>? brothers_next = null;
+		public Type2Node<G>? type2_child = null;
+		public weak Type1Node<G>? ll_prev = null;
+		public Type1Node<G>? ll_next = null;
+		public weak NodePair<G>? pair = null;
+
+		public Type1Node (G data) {
+			base (data);
+		}
+
+		public override int degree () {
+			return base.degree () + (type2_child == null ? 0 : 1);
+		}
+
+		public inline void add (Type1Node<G> node) {
+			node.parent = this;
+			if (type1_children_head == null) {
+				type1_children_head = node;
+			} else {
+				node.brothers_prev = type1_children_tail;
+			}
+			if (type1_children_tail != null) {
+				type1_children_tail.brothers_next = node;
+			}
+			type1_children_tail = node;
+			type1_children_count++;
+		}
+
+		public inline void remove () {
+			if (brothers_prev == null) {
+				parent.type1_children_head = brothers_next;
+			} else {
+				brothers_prev.brothers_next = brothers_next;
+			}
+			if (brothers_next == null) {
+				parent.type1_children_tail = brothers_prev;
+			} else {
+				brothers_next.brothers_prev = brothers_prev;
+			}
+			parent.type1_children_count--;
+			parent = null;
+			brothers_prev = null;
+			brothers_next = null;
+		}
+
+		public override string to_string () {
+			return "(\"%s\"/%d; %s, %s)".printf ((string) data, (int) lost, children_to_string (), type2_child != null ? type2_child.to_string () : "-");
+		}
+	}
+
+	private class Type2Node<G> : Node<G> {
+		public weak Type2Node<G>? lm_prev = null;
+		public Type2Node<G>? lm_next = null;
+
+		public Type2Node (G data) {
+			base (data);
+		}
+
+		public override string to_string () {
+			return "[\"%s\"; %s]".printf ((string) data, children_to_string ());
+		}
+	}
+
+	private class NodePair<G> {
+		public weak NodePair<G>? lp_prev = null;
+		public NodePair<G>? lp_next = null;
+		public Type1Node<G> node1 = null;
+		public Type1Node<G> node2 = null;
+
+		public NodePair (Type1Node<G> node1, Type1Node<G> node2) {
+			this.node1 = node1;
+			this.node2 = node2;
+		}
+	}
+
+	private class Iterator<G> : Object, Gee.Iterator<G> {
+		private PriorityQueue<G> queue;
+		private bool started = false;
+		private bool from_type1_children = false;
+		private bool from_type2_child = false;
+		private unowned Node<G>? position;
+		private int stamp;
+
+		public Iterator (PriorityQueue<G> queue) {
+			this.queue = queue;
+			this.position = queue._r;
+			this.stamp = queue._stamp;
+		}
+
+		public bool next () {
+			assert (stamp == queue._stamp);
+
+			if (!started) {
+				started = true;
+				return position != null;
+			} else if (position is Type1Node) {
+				var node = position as Type1Node<G>;
+				if (!from_type1_children && node.type1_children_head != null) {
+					position = node.type1_children_head;
+					from_type1_children = false;
+					from_type2_child = false;
+					return true;
+				} else if (!from_type2_child && node.type2_child != null) {
+					position = node.type2_child;
+					from_type1_children = false;
+					from_type2_child = false;
+					return true;
+				} else if (node.brothers_next != null) {
+					position = node.brothers_next;
+					return true;
+				}
+				from_type1_children = true;
+			} else if (position is Type2Node) {
+				var node = position as Type2Node<G>;
+				if (!from_type1_children && node.type1_children_head != null) {
+					position = node.type1_children_head;
+					from_type1_children = false;
+					from_type2_child = false;
+					return true;
+				}
+				from_type2_child = true;
+			}
+			if (position != queue._r) {
+				position = position.parent;
+				return next ();
+			}
+			return false;
+		}
+
+		public new G get () {
+			assert (stamp == queue._stamp);
+			assert (position != null);
+			return position.data;
+		}
+
+		internal Node<G> get_node () {
+			assert (stamp == queue._stamp);
+			assert (position != null);
+			return position;
+		}
+	}
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6b6ae94..48e98c6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -29,6 +29,7 @@ tests_VALASOURCES = \
        testmap.vala \
        testmultimap.vala \
        testmultiset.vala \
+       testpriorityqueue.vala \
        testqueue.vala \
        testreadonlycollection.vala \
        testreadonlylist.vala \
diff --git a/tests/testmain.vala b/tests/testmain.vala
index 6fb1c3a..ddb6a7f 100644
--- a/tests/testmain.vala
+++ b/tests/testmain.vala
@@ -30,6 +30,7 @@ void main (string[] args) {
 	TestSuite.get_root ().add_suite (new HashMultiSetTests ().get_suite ());
 	TestSuite.get_root ().add_suite (new LinkedListTests ().get_suite ());
 	TestSuite.get_root ().add_suite (new LinkedListAsDequeTests ().get_suite ());
+	TestSuite.get_root ().add_suite (new PriorityQueueTests ().get_suite ());
 	TestSuite.get_root ().add_suite (new ReadOnlyListTests ().get_suite ());
 	TestSuite.get_root ().add_suite (new TreeMapTests ().get_suite ());
 
diff --git a/tests/testpriorityqueue.vala b/tests/testpriorityqueue.vala
new file mode 100644
index 0000000..9669069
--- /dev/null
+++ b/tests/testpriorityqueue.vala
@@ -0,0 +1,104 @@
+/* testlinkedlistasdeque.vala
+ *
+ * Copyright (C) 2009  Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ * 	Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+using Gee;
+
+public class PriorityQueueTests : QueueTests {
+
+	public PriorityQueueTests () {
+		base ("PriorityQueue");
+		add_test ("[PriorityQueue] selected functions", test_selected_functions);
+		add_test ("[PriorityQueue] poll gives minimum", test_poll_gives_minimum);
+	}
+
+	public override void set_up () {
+		test_collection = new PriorityQueue<string> ();
+	}
+
+	public override void tear_down () {
+		test_collection = null;
+	}
+
+	private void test_selected_functions () {
+		var test_queue = test_collection as PriorityQueue<string>;
+
+		// Check the queue exists
+		assert (test_queue != null);
+
+		// Check the selected compare function
+		assert (test_queue.compare_func == strcmp);
+	}
+
+	private void test_poll_gives_minimum () {
+		var test_queue = test_collection as Gee.Queue<string>;
+
+		// Check the queue exists
+		assert (test_queue != null);
+
+		// Add two elements and remove the greatest
+		assert (test_queue.offer ("one") == true);
+		assert (test_queue.offer ("two") == true);
+		assert (test_queue.peek () == "one");
+		assert (test_queue.remove ("two"));
+		assert (test_queue.peek () == "one");
+		assert (test_queue.poll () == "one");
+
+		// Add twelve elements
+		assert (test_queue.offer ("one") == true);
+		assert (test_queue.offer ("two") == true);
+		assert (test_queue.offer ("three") == true);
+		assert (test_queue.offer ("four") == true);
+		assert (test_queue.offer ("five") == true);
+		assert (test_queue.offer ("six") == true);
+		assert (test_queue.offer ("seven") == true);
+		assert (test_queue.offer ("eight") == true);
+		assert (test_queue.offer ("nine") == true);
+		assert (test_queue.offer ("ten") == true);
+		assert (test_queue.offer ("eleven") == true);
+		assert (test_queue.offer ("twelve") == true);
+
+		assert (test_queue.peek () == "eight");
+		assert (test_queue.poll () == "eight");
+		assert (test_queue.peek () == "eleven");
+		assert (test_queue.poll () == "eleven");
+		assert (test_queue.peek () == "five");
+		assert (test_queue.poll () == "five");
+		assert (test_queue.peek () == "four");
+		assert (test_queue.poll () == "four");
+		assert (test_queue.peek () == "nine");
+		assert (test_queue.poll () == "nine");
+		assert (test_queue.peek () == "one");
+		assert (test_queue.poll () == "one");
+		assert (test_queue.peek () == "seven");
+		assert (test_queue.poll () == "seven");
+		assert (test_queue.peek () == "six");
+		assert (test_queue.poll () == "six");
+		assert (test_queue.peek () == "ten");
+		assert (test_queue.poll () == "ten");
+		assert (test_queue.peek () == "three");
+		assert (test_queue.poll () == "three");
+		assert (test_queue.peek () == "twelve");
+		assert (test_queue.poll () == "twelve");
+		assert (test_queue.peek () == "two");
+		assert (test_queue.poll () == "two");
+	}
+}



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