[vala/wip/gee: 41/44] Update internal gee from libgee 0.18.0+bfa28bbc
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/gee: 41/44] Update internal gee from libgee 0.18.0+bfa28bbc
- Date: Mon, 10 Oct 2016 20:25:24 +0000 (UTC)
commit 559a82279c4060bac83924c32cd88b5660e4158f
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Tue Sep 20 23:56:04 2016 +0200
Update internal gee from libgee 0.18.0+bfa28bbc
https://bugzilla.gnome.org/show_bug.cgi?id=704754
configure.ac | 2 +-
gee/Makefile.am | 25 +-
gee/abstractbidirlist.vala | 12 +-
gee/abstractbidirsortedmap.vala | 12 +-
gee/abstractbidirsortedset.vala | 12 +-
gee/abstractcollection.vala | 12 +-
gee/abstractlist.vala | 12 +-
gee/abstractmap.vala | 12 +-
gee/abstractmultimap.vala | 22 +-
gee/abstractmultiset.vala | 16 +
gee/abstractset.vala | 12 +-
gee/abstractsortedmap.vala | 13 +-
gee/abstractsortedset.vala | 12 +-
gee/arraylist.vala | 243 ++++++-
gee/arrayqueue.vala | 50 ++-
gee/bidirlistiterator.vala | 6 +-
gee/collection.vala | 491 +++++++++++++-
gee/comparable.vala | 12 +
gee/concurrentlist.vala | 92 ++-
gee/concurrentset.vala | 1445 +++++++++++++++++++++++++++++++++++++++
gee/functions.vala | 35 +-
gee/future.vala | 261 +++++++
gee/hashable.vala | 19 +-
gee/hashmap.vala | 177 ++++--
gee/hashmultimap.vala | 31 +-
gee/hashmultiset.vala | 30 +-
gee/hashset.vala | 112 +++-
gee/hazardpointer.vala | 101 ++--
gee/iterator.vala | 7 +-
gee/lazy.vala | 109 +++
gee/lightmapfuture.vala | 62 ++
gee/linkedlist.vala | 310 ++++++----
gee/listiterator.vala | 5 +-
gee/map.vala | 38 +-
gee/mapiterator.vala | 14 +-
gee/multimap.vala | 8 +-
gee/multiset.vala | 19 +
gee/priorityqueue.vala | 94 ++-
gee/promise.vala | 210 ++++++
gee/queue.vala | 4 +-
gee/readonlycollection.vala | 25 +-
gee/readonlymap.vala | 8 +-
gee/readonlymultimap.vala | 131 ++++
gee/readonlymultiset.vala | 57 ++
gee/streamiterator.vala | 183 +++++
gee/task.vala | 97 +++
gee/teeiterator.vala | 116 ++++
gee/timsort.vala | 6 +-
gee/traversable.vala | 204 ++++--
gee/treemap.vala | 188 +++++-
gee/treemultimap.vala | 17 +-
gee/treemultiset.vala | 6 +-
gee/treeset.vala | 96 +++-
gee/unrolledlinkedlist.vala | 1152 +++++++++++++++++++++++++++++++
gee/utils/assume.h | 33 +
gee/utils/async.h | 31 +
gee/utils/free.h | 30 +
gee/utils/misc.h | 30 +
gee/utils/utils.vapi | 20 +
59 files changed, 6051 insertions(+), 538 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 744a26f..2be16f9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,7 +71,7 @@ AC_SUBST(COVERAGE_LIBS)
GLIB_REQUIRED=2.32.0
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED)
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
diff --git a/gee/Makefile.am b/gee/Makefile.am
index e57a70c..260956a 100644
--- a/gee/Makefile.am
+++ b/gee/Makefile.am
@@ -5,6 +5,7 @@ NULL =
AM_CPPFLAGS = \
$(COVERAGE_CFLAGS) \
$(GLIB_CFLAGS) \
+ -I$(srcdir)/utils \
$(NULL)
BUILT_SOURCES = gee.vala.stamp
@@ -37,8 +38,10 @@ libgee_la_VALASOURCES = \
collection.vala \
comparable.vala \
concurrentlist.vala \
+ concurrentset.vala \
deque.vala \
functions.vala \
+ future.vala \
hashable.vala \
hashmap.vala \
hashmultimap.vala \
@@ -48,6 +51,7 @@ libgee_la_VALASOURCES = \
iterable.vala \
iterator.vala \
lazy.vala \
+ lightmapfuture.vala \
linkedlist.vala \
listiterator.vala \
list.vala \
@@ -56,6 +60,7 @@ libgee_la_VALASOURCES = \
multimap.vala \
multiset.vala \
priorityqueue.vala \
+ promise.vala \
queue.vala \
readonlybidirlist.vala \
readonlybidirsortedmap.vala \
@@ -63,12 +68,17 @@ libgee_la_VALASOURCES = \
readonlycollection.vala \
readonlylist.vala \
readonlymap.vala \
+ readonlymultimap.vala \
+ readonlymultiset.vala \
readonlyset.vala \
readonlysortedmap.vala \
readonlysortedset.vala \
set.vala \
sortedmap.vala \
sortedset.vala \
+ streamiterator.vala \
+ task.vala \
+ teeiterator.vala \
timsort.vala \
traversable.vala \
treemap.vala \
@@ -76,6 +86,7 @@ libgee_la_VALASOURCES = \
treemultiset.vala \
treeset.vala \
unfolditerator.vala \
+ unrolledlinkedlist.vala \
$(NULL)
libgee_la_SOURCES = \
@@ -94,7 +105,8 @@ gee.vapi gee.vala.stamp: $(libgee_la_VALASOURCES)
$(COVERAGE_VALAFLAGS) \
$(VALAFLAGS) \
-C \
- --vapidir $(top_srcdir)/vapi --pkg gobject-2.0 \
+ --vapidir $(srcdir)/utils --pkg utils \
+ --vapidir $(top_srcdir)/vapi --pkg gobject-2.0 --pkg gio-2.0 \
-H valagee.h \
--library gee \
$^
@@ -105,7 +117,16 @@ libgee_la_LIBADD = \
$(GLIB_LIBS) \
$(NULL)
-EXTRA_DIST = $(libgee_la_VALASOURCES) gee.vapi gee.vala.stamp
+EXTRA_DIST = \
+ $(libgee_la_VALASOURCES) \
+ gee.vapi \
+ gee.vala.stamp \
+ utils/assume.h \
+ utils/async.h \
+ utils/free.h \
+ utils/utils.vapi \
+ utils/misc.h \
+ $(NULL)
MAINTAINERCLEANFILES = \
gee.vapi \
diff --git a/gee/abstractbidirlist.vala b/gee/abstractbidirlist.vala
index 41040f5..81e9bf1 100644
--- a/gee/abstractbidirlist.vala
+++ b/gee/abstractbidirlist.vala
@@ -26,18 +26,20 @@ public abstract class Vala.AbstractBidirList<G> : AbstractList<G>, BidirList<G>
*/
public abstract BidirListIterator<G> bidir_list_iterator ();
- private weak BidirList<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new BidirList<G> read_only_view {
owned get {
- BidirList<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ BidirList<G>? instance = (BidirList<G>?)_read_only_view.get();
+ if (instance == null) {
instance = new ReadOnlyBidirList<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractbidirsortedmap.vala b/gee/abstractbidirsortedmap.vala
index 2290c17..d2d345f 100644
--- a/gee/abstractbidirsortedmap.vala
+++ b/gee/abstractbidirsortedmap.vala
@@ -33,18 +33,20 @@ public abstract class Vala.AbstractBidirSortedMap<K,V> : Vala.AbstractSortedMap<
*/
public abstract BidirMapIterator<K,V> bidir_map_iterator ();
- private weak BidirSortedMap<K,V> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new BidirSortedMap<K,V> read_only_view {
owned get {
- BidirSortedMap<K,V> instance = _read_only_view;
- if (_read_only_view == null) {
+ BidirSortedMap<K,V>? instance = (BidirSortedMap<K,V>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlyBidirSortedMap<K,V> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractbidirsortedset.vala b/gee/abstractbidirsortedset.vala
index 219664a..5956f90 100644
--- a/gee/abstractbidirsortedset.vala
+++ b/gee/abstractbidirsortedset.vala
@@ -33,18 +33,20 @@ public abstract class Vala.AbstractBidirSortedSet<G> : Vala.AbstractSortedSet<G>
*/
public abstract BidirIterator<G> bidir_iterator ();
- private weak BidirSortedSet<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new BidirSortedSet<G> read_only_view {
owned get {
- BidirSortedSet<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ BidirSortedSet<G>? instance = (BidirSortedSet<G>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlyBidirSortedSet<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractcollection.vala b/gee/abstractcollection.vala
index a2421ce..a11ec4f 100644
--- a/gee/abstractcollection.vala
+++ b/gee/abstractcollection.vala
@@ -70,18 +70,20 @@ public abstract class Vala.AbstractCollection<G> : Object, Traversable<G>, Itera
return iterator ().foreach (f);
}
- private weak Collection<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual Collection<G> read_only_view {
owned get {
- Collection<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ Collection<G>? instance = (Collection<G>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlyCollection<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractlist.vala b/gee/abstractlist.vala
index 581ad7f..184b21c 100644
--- a/gee/abstractlist.vala
+++ b/gee/abstractlist.vala
@@ -66,18 +66,20 @@ public abstract class Vala.AbstractList<G> : Vala.AbstractCollection<G>, List<G>
*/
public abstract List<G>? slice (int start, int stop);
- private weak List<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new List<G> read_only_view {
owned get {
- List<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ List<G>? instance = (List<G>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlyList<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractmap.vala b/gee/abstractmap.vala
index bc24604..b5ece89 100644
--- a/gee/abstractmap.vala
+++ b/gee/abstractmap.vala
@@ -91,18 +91,20 @@ public abstract class Vala.AbstractMap<K,V> : Object, Traversable<Map.Entry<K,V>
*/
public abstract void clear ();
- private weak Map<K,V> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual Map<K,V> read_only_view {
owned get {
- Map<K,V> instance = _read_only_view;
- if (_read_only_view == null) {
+ Map<K,V>? instance = (Map<K,V>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlyMap<K,V> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractmultimap.vala b/gee/abstractmultimap.vala
index 9c96c70..0e60e01 100644
--- a/gee/abstractmultimap.vala
+++ b/gee/abstractmultimap.vala
@@ -162,7 +162,7 @@ public abstract class Vala.AbstractMultiMap<K,V> : Object, MultiMap<K,V> {
_multi_map = multi_map;
}
- public override Vala.Iterator<K> iterator () {
+ public override Vala.Iterator<V> iterator () {
return new ValueIterator<K, V> (_multi_map._storage_map.map_iterator ());
}
@@ -179,11 +179,11 @@ public abstract class Vala.AbstractMultiMap<K,V> : Object, MultiMap<K,V> {
return false;
}
- public override bool add (V key) {
+ public override bool add (V value) {
assert_not_reached ();
}
- public override bool remove (V item) {
+ public override bool remove (V value) {
assert_not_reached ();
}
@@ -308,4 +308,20 @@ public abstract class Vala.AbstractMultiMap<K,V> : Object, MultiMap<K,V> {
public bool mutable { get { return false; } }
}
+
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
+
+ public virtual new MultiMap<K, V> read_only_view {
+ owned get {
+ MultiMap<K, V>? instance = (MultiMap<K, V>?)_read_only_view.get ();
+ if (instance == null) {
+ instance = new ReadOnlyMultiMap<K, V> (this);
+ _read_only_view.set (instance);
+ }
+ return instance;
+ }
+ }
}
diff --git a/gee/abstractmultiset.vala b/gee/abstractmultiset.vala
index 4d2f781..4145ea3 100644
--- a/gee/abstractmultiset.vala
+++ b/gee/abstractmultiset.vala
@@ -92,6 +92,22 @@ public abstract class Vala.AbstractMultiSet<G> : AbstractCollection<G>, MultiSet
_nitems = 0;
}
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
+
+ public virtual new MultiSet<G> read_only_view {
+ owned get {
+ MultiSet<G>? instance = (MultiSet<G>?)_read_only_view.get ();
+ if (instance == null) {
+ instance = new ReadOnlyMultiSet<G> (this);
+ _read_only_view.set (instance);
+ }
+ return instance;
+ }
+ }
+
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
private AbstractMultiSet<G> _set;
diff --git a/gee/abstractset.vala b/gee/abstractset.vala
index 71effc5..7a83d06 100644
--- a/gee/abstractset.vala
+++ b/gee/abstractset.vala
@@ -31,18 +31,20 @@
*/
public abstract class Vala.AbstractSet<G> : Vala.AbstractCollection<G>, Set<G> {
- private weak Set<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new Set<G> read_only_view {
owned get {
- Set<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ Set<G>? instance = (Set<G>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlySet<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractsortedmap.vala b/gee/abstractsortedmap.vala
index 876a4c3..58d7f04 100644
--- a/gee/abstractsortedmap.vala
+++ b/gee/abstractsortedmap.vala
@@ -46,17 +46,20 @@ public abstract class Vala.AbstractSortedMap<K, V> : AbstractMap<K,V>, SortedMap
*/
public abstract SortedSet<Map.Entry<K,V>> ascending_entries { owned get; }
- private weak SortedMap<K,V> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
+
/**
* 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) {
+ SortedMap<K,V>? instance = (SortedMap<K,V>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlySortedMap<K,V> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/abstractsortedset.vala b/gee/abstractsortedset.vala
index 03f02f3..830bb2d 100644
--- a/gee/abstractsortedset.vala
+++ b/gee/abstractsortedset.vala
@@ -78,18 +78,20 @@ public abstract class Vala.AbstractSortedSet<G> : Vala.AbstractSet<G>, SortedSet
*/
public abstract SortedSet<G> sub_set (G from, G to);
- private weak SortedSet<G> _read_only_view;
+ private WeakRef _read_only_view;
+ construct {
+ _read_only_view = WeakRef(null);
+ }
/**
* {@inheritDoc}
*/
public virtual new SortedSet<G> read_only_view {
owned get {
- SortedSet<G> instance = _read_only_view;
- if (_read_only_view == null) {
+ SortedSet<G>? instance = (SortedSet<G>?)_read_only_view.get ();
+ if (instance == null) {
instance = new ReadOnlySortedSet<G> (this);
- _read_only_view = instance;
- instance.add_weak_pointer ((void**) (&_read_only_view));
+ _read_only_view.set (instance);
}
return instance;
}
diff --git a/gee/arraylist.vala b/gee/arraylist.vala
index 4bcb3e0..51a0a1d 100644
--- a/gee/arraylist.vala
+++ b/gee/arraylist.vala
@@ -4,6 +4,7 @@
* Copyright (C) 2005 David Waite
* Copyright (C) 2007-2008 Jürg Billeter
* Copyright (C) 2009 Didier Villevalois
+ * Copyright (C) 2010-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,7 +25,7 @@
* Didier 'Ptitjes Villevalois <ptitjes free fr>
*/
-using GLib;
+using Vala.Utils.Assume;
/**
* Resizable array implementation of the {@link List} interface.
@@ -56,10 +57,16 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
* The elements' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<G> equal_func { private set; get; }
+ public EqualDataFunc<G> equal_func {
+ private set {}
+ get {
+ return _equal_func.func;
+ }
+ }
- internal G[] _items = new G[4];
+ internal G[] _items;
internal int _size;
+ private Functions.EqualDataFuncClosure<G> _equal_func;
// concurrent modification protection
private int _stamp = 0;
@@ -76,7 +83,33 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
if (equal_func == null) {
equal_func = Functions.get_equal_func_for (typeof (G));
}
- this.equal_func = equal_func;
+ _equal_func = new Functions.EqualDataFuncClosure<G>((owned)equal_func);
+ _items = new G[4];
+ _size = 0;
+ }
+
+ /**
+ * Constructs a new array list based on provided array.
+ *
+ * If not provided, the function parameter is requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param items initial items to be put into array
+ * @param equal_func an optional element equality testing function
+ */
+ public ArrayList.wrap (owned G[] items, owned EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
+ _equal_func = new Functions.EqualDataFuncClosure<G>((owned)equal_func);
+ _size = items.length;
+ _items = do_wrap<G> ((owned)items);
+ }
+
+ internal ArrayList.with_closure (owned Functions.EqualDataFuncClosure<G> equal_func) {
+ _equal_func = equal_func;
+ _items = new G[4];
+ _size = 0;
}
/**
@@ -226,7 +259,7 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
return_val_if_fail (start >= 0, null);
return_val_if_fail (stop <= _size, null);
- var slice = new ArrayList<G> (this.equal_func);
+ var slice = new ArrayList<G>.with_closure (_equal_func);
for (int i = start; i < stop; i++) {
slice.add (this[i]);
}
@@ -249,9 +282,15 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
}
private void shift (int start, int delta) {
+#if !DISABLE_INTERNAL_ASSERTS
assert (start >= 0);
assert (start <= _size);
assert (start >= -delta);
+#else
+ assume (start >= 0);
+ assume (start <= _size);
+ assume (start >= -delta);
+#endif
_items.move (start, start + delta, _size - start);
@@ -259,7 +298,11 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
}
private void grow_if_needed (int new_count) {
+#if !DISABLE_INTERNAL_ASSERTS
assert (new_count >= 0);
+#else
+ assume (new_count >= 0);
+#endif
int minimum_size = _size + new_count;
if (minimum_size > _items.length) {
@@ -269,24 +312,26 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
}
private void set_capacity (int value) {
+#if !DISABLE_INTERNAL_ASSERTS
assert (value >= _size);
+#endif
_items.resize (value);
}
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G>, BidirIterator<G>,
ListIterator<G>, BidirListIterator<G> {
- private ArrayList<G> _list;
- private int _index = -1;
- private bool _removed = false;
-
- // concurrent modification protection
- private int _stamp = 0;
-
- public Iterator (ArrayList list) {
+ public Iterator (ArrayList<G> list) {
_list = list;
_stamp = _list._stamp;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _list = iter._list;
+ _index = iter._index;
+ _removed = iter._removed;
+ _stamp = iter._stamp;
+ }
+
public bool next () {
assert (_stamp == _list._stamp);
if (_index + 1 < _list._size) {
@@ -314,17 +359,24 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
public new G get () {
assert (_stamp == _list._stamp);
+ assert (! _removed);
assert (_index >= 0);
+#if !DISABLE_INTERNAL_ASSERTS
assert (_index < _list._size);
- assert (! _removed);
+#else
+ assume (_index < _list._size);
+#endif
return _list._items[_index];
}
public void remove () {
assert (_stamp == _list._stamp);
- assert (_index >= 0);
+ assert (! _removed && _index >= 0);
+#if !DISABLE_INTERNAL_ASSERTS
assert (_index < _list._size);
- assert (! _removed);
+#else
+ assume (_index < _list._size);
+#endif
_list.remove_at (_index);
_index--;
_removed = true;
@@ -333,6 +385,10 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
public bool previous () {
assert (_stamp == _list._stamp);
+ if (_removed && _index >= 0) {
+ _removed = false;
+ return true;
+ }
if (_index > 0) {
_index--;
return true;
@@ -342,7 +398,7 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
public bool has_previous () {
assert (_stamp == _list._stamp);
- return (_index - 1 >= 0);
+ return (_index > 0 || (_removed && _index >= 0));
}
public bool last () {
@@ -356,27 +412,39 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
public new void set (G item) {
assert (_stamp == _list._stamp);
+ assert (! _removed);
assert (_index >= 0);
+#if !DISABLE_INTERNAL_ASSERTS
assert (_index < _list._size);
+#else
+ assume (_index < _list._size);
+#endif
_list._items[_index] = item;
_stamp = ++_list._stamp;
}
public void insert (G item) {
assert (_stamp == _list._stamp);
- assert (_index >= 0);
assert (_index < _list._size);
- _list.insert (_index, item);
+ if (_index == -1) {
+ _list.insert (0, item);
+ _removed = true;
+ }
+ if (_removed) {
+ _list.insert (_index + 1, item);
+ } else {
+ _list.insert (_index, item);
+ }
_index++;
_stamp = _list._stamp;
}
public void add (G item) {
assert (_stamp == _list._stamp);
- assert (_index >= 0);
assert (_index < _list._size);
_list.insert (_index + 1, item);
_index++;
+ _removed = false;
_stamp = _list._stamp;
}
@@ -413,6 +481,141 @@ public class Vala.ArrayList<G> : AbstractBidirList<G> {
_index = _list._size - 1;
return true;
}
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected ArrayList<G> _list;
+ protected int _index = -1;
+ protected bool _removed = false;
+ protected int _stamp = 0;
+ }
+
+ private static G[] do_wrap<G> (owned G[] data) {
+ var t = typeof (G);
+ if (t == typeof (bool)) {
+ return wrap_bool<G> ((bool[])data);
+ } else if (t == typeof (char)) {
+ return wrap_char<G> ((char[])data);
+ } else if (t == typeof (uchar)) {
+ return wrap_uchar<G> ((uchar[])data);
+ } else if (t == typeof (int)) {
+ return wrap_int<G> ((int[])data);
+ } else if (t == typeof (uint)) {
+ return wrap_uint<G> ((uint[])data);
+ } else if (t == typeof (int64)) {
+ return wrap_int64<G> ((int64[])data);
+ } else if (t == typeof (uint64)) {
+ return wrap_uint64<G> ((uint64[])data);
+ } else if (t == typeof (long)) {
+ return wrap_long<G> ((long[])data);
+ } else if (t == typeof (ulong)) {
+ return wrap_ulong<G> ((ulong[])data);
+ } else if (t == typeof (float)) {
+ return wrap_float<G> ((float?[])data);
+ } else if (t == typeof (double)) {
+ return wrap_double<G> ((double?[])data);
+ } else {
+ return (owned)data;
+ }
+ }
+
+ private static G[] wrap_bool<G> (bool[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_char<G> (char[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_uchar<G> (uchar[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_int<G> (int[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_uint<G> (uint[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_int64<G> (int64[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_uint64<G> (uint64[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_long<G> (long[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_ulong<G> (ulong[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_float<G> (float?[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
+ }
+
+ private static G[] wrap_double<G> (double?[] data) {
+ G[] arr = new G[data.length];
+ for (uint i = 0; i < data.length; i++) {
+ arr[i] = data[i];
+ }
+ return arr;
}
}
diff --git a/gee/arrayqueue.vala b/gee/arrayqueue.vala
index 9eac3e6..25c4721 100644
--- a/gee/arrayqueue.vala
+++ b/gee/arrayqueue.vala
@@ -1,6 +1,6 @@
/* arrayqueue.vala
*
- * Copyright (C) 2012 Maciej Piechotka
+ * Copyright (C) 2012-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -44,12 +44,17 @@ public class Vala.ArrayQueue<G> : Vala.AbstractQueue<G>, Deque<G> {
if (equal_func == null) {
equal_func = Functions.get_equal_func_for (typeof (G));
}
- this.equal_func = equal_func;
+ _equal_func = (owned)equal_func;
this._items = new G[10];
}
[CCode (notify = false)]
- public EqualDataFunc<G> equal_func { private set; get; }
+ public EqualDataFunc<G> equal_func {
+ private set {}
+ get { return _equal_func; }
+ }
+
+ private EqualDataFunc<G> _equal_func;
/**
* {@inheritDoc}
@@ -127,6 +132,18 @@ public class Vala.ArrayQueue<G> : Vala.AbstractQueue<G>, Deque<G> {
/**
* {@inheritDoc}
*/
+ public override bool foreach (ForallFunc<G> f) {
+ for (int i = 0; i < _length; i++) {
+ if (!f (_items[(_start + i) % _items.length])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public override G? peek () {
return peek_head ();
}
@@ -277,6 +294,12 @@ public class Vala.ArrayQueue<G> : Vala.AbstractQueue<G>, Deque<G> {
_queue = queue;
_stamp = _queue._stamp;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _queue = iter._queue;
+ _stamp = iter._stamp;
+ _offset = iter._offset;
+ _removed = iter._removed;
+ }
public bool next () {
assert (_queue._stamp == _stamp);
@@ -328,10 +351,23 @@ public class Vala.ArrayQueue<G> : Vala.AbstractQueue<G>, Deque<G> {
return true;
}
- private ArrayQueue _queue;
- private int _stamp;
- private int _offset = -1;
- private bool _removed = false;
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected ArrayQueue _queue;
+ protected int _stamp;
+ protected int _offset = -1;
+ protected bool _removed = false;
}
private G[] _items;
diff --git a/gee/bidirlistiterator.vala b/gee/bidirlistiterator.vala
index 094a5f7..10f524b 100644
--- a/gee/bidirlistiterator.vala
+++ b/gee/bidirlistiterator.vala
@@ -23,7 +23,11 @@
public interface Vala.BidirListIterator<G> : Vala.BidirIterator<G>, Vala.ListIterator<G> {
/**
* Inserts the specified item before the current item in the iteration. The
- * cursor is let to point to the current item.
+ * iterator points to the same element as before.
+ *
+ * Please note that if iterator points in-between elements the element
+ * is added between neighbouring elements and the iterator point between
+ * added element and the next one.
*/
public abstract void insert (G item);
}
diff --git a/gee/collection.vala b/gee/collection.vala
index 112e6ac..cd9c6ea 100644
--- a/gee/collection.vala
+++ b/gee/collection.vala
@@ -28,17 +28,20 @@ public interface Vala.Collection<G> : Iterable<G> {
/**
* The number of items in this collection.
*/
+ [CCode (ordering = 9)]
public abstract int size { get; }
/**
* Specifies whether this collection is empty.
*/
+ [CCode (ordering = 10)]
public virtual bool is_empty { get { return size == 0; } }
/**
* Specifies whether this collection can change - i.e. wheather {@link add},
* {@link remove} etc. are legal operations.
*/
+ [CCode (ordering = 11)]
public abstract bool read_only { get; }
/**
@@ -48,6 +51,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if item is found, ``false`` otherwise
*/
+ [CCode (ordering = 0)]
public abstract bool contains (G item);
/**
@@ -58,6 +62,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 1)]
public abstract bool add (G item);
/**
@@ -68,12 +73,14 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 2)]
public abstract bool remove (G item);
/**
* Removes all items from this collection. Must not be called on
* read-only collections.
*/
+ [CCode (ordering = 3)]
public abstract void clear ();
/**
@@ -84,6 +91,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 4)]
public virtual bool add_all (Collection<G> collection) {
return collection.fold<bool> ((item, changed) => changed | add (item), false);
}
@@ -97,6 +105,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 5)]
public virtual bool contains_all (Collection<G> collection) {
return collection.foreach ((item) => contains (item));
}
@@ -112,6 +121,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 6)]
public virtual bool remove_all (Collection<G> collection) {
return collection.fold<bool> ((item, changed) => changed | remove (item), false);
}
@@ -126,6 +136,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return ``true`` if the collection has been changed, ``false`` otherwise
*/
+ [CCode (ordering = 7)]
public virtual bool retain_all (Collection<G> collection) {
bool changed = false;
for (Iterator<G> iter = iterator(); iter.next ();) {
@@ -143,6 +154,7 @@ public interface Vala.Collection<G> : Iterable<G> {
*
* @return an array containing all of items from this collection
*/
+ [CCode (ordering = 8)]
public virtual G[] to_array () {
var t = typeof (G);
if (t == typeof (bool)) {
@@ -171,12 +183,182 @@ public interface Vala.Collection<G> : Iterable<G> {
G[] array = new G[size];
int index = 0;
foreach (G element in this) {
- array[index++] = element;
+ array[index++] = (owned)element;
}
return array;
}
}
+ /**
+ * Adds all items in the input array to this collection.
+ *
+ * @param array the array which items will be added to this
+ * collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ [CCode (ordering = 13)]
+ public virtual bool add_all_array (G[] array) {
+ var t = typeof (G);
+ if (t == typeof (bool)) {
+ return add_all_bool_array ((Collection<bool>) this, (bool [])array);
+ } else if (t == typeof (char)) {
+ return add_all_char_array ((Collection<char>) this, (char [])array);
+ } else if (t == typeof (uchar)) {
+ return add_all_uchar_array ((Collection<uchar>) this, (uchar [])array);
+ } else if (t == typeof (int)) {
+ return add_all_int_array ((Collection<int>) this, (int [])array);
+ } else if (t == typeof (uint)) {
+ return add_all_uint_array ((Collection<uint>) this, (uint [])array);
+ } else if (t == typeof (int64)) {
+ return add_all_int64_array ((Collection<int64?>) this, (int64? [])array);
+ } else if (t == typeof (uint64)) {
+ return add_all_uint64_array ((Collection<uint64?>) this, (uint64? [])array);
+ } else if (t == typeof (long)) {
+ return add_all_long_array ((Collection<long>) this, (long [])array);
+ } else if (t == typeof (ulong)) {
+ return add_all_ulong_array ((Collection<ulong>) this, (ulong [])array);
+ } else if (t == typeof (float)) {
+ return add_all_float_array ((Collection<float>) this, (float? [])array);
+ } else if (t == typeof (double)) {
+ return add_all_double_array ((Collection<double>) this, (double? [])array);
+ } else {
+ bool changed = false;
+ foreach (unowned G item in array) {
+ changed |= add (item);
+ }
+ return changed;
+ }
+ }
+
+ /**
+ * Returns ``true`` it this collection contains all items as the input
+ * array.
+ *
+ * @param array the array which items will be compared with
+ * this collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ [CCode (ordering = 14)]
+ public virtual bool contains_all_array (G[] array) {
+ var t = typeof (G);
+ if (t == typeof (bool)) {
+ return contains_all_bool_array ((Collection<bool>) this, (bool [])array);
+ } else if (t == typeof (char)) {
+ return contains_all_char_array ((Collection<char>) this, (char [])array);
+ } else if (t == typeof (uchar)) {
+ return contains_all_uchar_array ((Collection<uchar>) this, (uchar [])array);
+ } else if (t == typeof (int)) {
+ return contains_all_int_array ((Collection<int>) this, (int [])array);
+ } else if (t == typeof (uint)) {
+ return contains_all_uint_array ((Collection<uint>) this, (uint [])array);
+ } else if (t == typeof (int64)) {
+ return contains_all_int64_array ((Collection<int64?>) this, (int64? [])array);
+ } else if (t == typeof (uint64)) {
+ return contains_all_uint64_array ((Collection<uint64?>) this, (uint64? [])array);
+ } else if (t == typeof (long)) {
+ return contains_all_long_array ((Collection<long>) this, (long [])array);
+ } else if (t == typeof (ulong)) {
+ return contains_all_ulong_array ((Collection<ulong>) this, (ulong [])array);
+ } else if (t == typeof (float)) {
+ return contains_all_float_array ((Collection<float>) this, (float? [])array);
+ } else if (t == typeof (double)) {
+ return contains_all_double_array ((Collection<double>) this, (double? [])array);
+ } else {
+ foreach (unowned G item in array) {
+ if (!contains (item)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Removes the subset of items in this collection corresponding to the
+ * elments in the input array. If there is several occurrences of
+ * the same value in this collection they are decremented of the number
+ * of occurrences in the input array.
+ *
+ * @param array the array which items will be compared with
+ * this collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ [CCode (ordering = 15)]
+ public virtual bool remove_all_array (G[] array) {
+ var t = typeof (G);
+ if (t == typeof (bool)) {
+ return remove_all_bool_array ((Collection<bool>) this, (bool [])array);
+ } else if (t == typeof (char)) {
+ return remove_all_char_array ((Collection<char>) this, (char [])array);
+ } else if (t == typeof (uchar)) {
+ return remove_all_uchar_array ((Collection<uchar>) this, (uchar [])array);
+ } else if (t == typeof (int)) {
+ return remove_all_int_array ((Collection<int>) this, (int [])array);
+ } else if (t == typeof (uint)) {
+ return remove_all_uint_array ((Collection<uint>) this, (uint [])array);
+ } else if (t == typeof (int64)) {
+ return remove_all_int64_array ((Collection<int64?>) this, (int64? [])array);
+ } else if (t == typeof (uint64)) {
+ return remove_all_uint64_array ((Collection<uint64?>) this, (uint64? [])array);
+ } else if (t == typeof (long)) {
+ return remove_all_long_array ((Collection<long>) this, (long [])array);
+ } else if (t == typeof (ulong)) {
+ return remove_all_ulong_array ((Collection<ulong>) this, (ulong [])array);
+ } else if (t == typeof (float)) {
+ return remove_all_float_array ((Collection<float>) this, (float? [])array);
+ } else if (t == typeof (double)) {
+ return remove_all_double_array ((Collection<double>) this, (double? [])array);
+ } else {
+ bool changed = false;
+ foreach (unowned G item in array) {
+ changed |= remove (item);
+ }
+ return changed;
+ }
+ }
+
+ [CCode (ordering = 16)]
+ public virtual bool add_all_iterator (Iterator<G> iter) {
+ bool changed = false;
+ iter.foreach ((val) => {
+ changed |= add (val);
+ return true;
+ });
+ return changed;
+ }
+
+ [CCode (ordering = 17)]
+ public virtual bool contains_all_iterator (Iterator<G> iter) {
+ return iter.foreach ((val) => {return contains (val);});
+ }
+
+ [CCode (ordering = 18)]
+ public virtual bool remove_all_iterator (Iterator<G> iter) {
+ bool changed = false;
+ return iter.foreach ((val) => {
+ changed |= remove (val);
+ return true;
+ });
+ }
+
+ /**
+ * The read-only view of this collection.
+ */
+ [CCode (ordering = 12)]
+ public abstract Collection<G> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty collection.
+ *
+ * @return an immutable empty collection
+ */
+ public static Collection<G> empty<G> () {
+ return new HashSet<G> ().read_only_view;
+ }
+
private static bool[] to_bool_array (Collection<bool> coll) {
bool[] array = new bool[coll.size];
int index = 0;
@@ -222,20 +404,20 @@ public interface Vala.Collection<G> : Iterable<G> {
return array;
}
- private static int64[] to_int64_array (Collection<int64?> coll) {
- int64[] array = new int64[coll.size];
+ private static int64?[] to_int64_array (Collection<int64?> coll) {
+ int64?[] array = new int64?[coll.size];
int index = 0;
- foreach (int64 element in coll) {
- array[index++] = element;
+ foreach (int64? element in coll) {
+ array[index++] = (owned)element;
}
return array;
}
- private static uint64[] to_uint64_array (Collection<uint64?> coll) {
- uint64[] array = new uint64[coll.size];
+ private static uint64?[] to_uint64_array (Collection<uint64?> coll) {
+ uint64?[] array = new uint64?[coll.size];
int index = 0;
- foreach (uint64 element in coll) {
- array[index++] = element;
+ foreach (uint64? element in coll) {
+ array[index++] = (owned)element;
}
return array;
}
@@ -261,8 +443,8 @@ public interface Vala.Collection<G> : Iterable<G> {
private static float?[] to_float_array (Collection<float?> coll) {
float?[] array = new float?[coll.size];
int index = 0;
- foreach (float element in coll) {
- array[index++] = element;
+ foreach (float? element in coll) {
+ array[index++] = (owned)element;
}
return array;
}
@@ -270,24 +452,285 @@ public interface Vala.Collection<G> : Iterable<G> {
private static double?[] to_double_array (Collection<double?> coll) {
double?[] array = new double?[coll.size];
int index = 0;
- foreach (double element in coll) {
- array[index++] = element;
+ foreach (double? element in coll) {
+ array[index++] = (owned)element;
}
return array;
}
- /**
- * The read-only view of this collection.
- */
- public abstract Collection<G> read_only_view { owned get; }
+ private static bool add_all_bool_array (Collection<bool> coll, bool[] arr) {
+ bool changed = false;
+ foreach (bool el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
- /**
- * Returns an immutable empty collection.
- *
- * @return an immutable empty collection
- */
- public static Collection<G> empty<G> () {
- return new HashSet<G> ().read_only_view;
+ private static bool add_all_char_array (Collection<char> coll, char[] arr) {
+ bool changed = false;
+ foreach (char el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_uchar_array (Collection<uchar> coll, uchar[] arr) {
+ bool changed = false;
+ foreach (uchar el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_int_array (Collection<int> coll, int[] arr) {
+ bool changed = false;
+ foreach (int el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_uint_array (Collection<uint> coll, uint[] arr) {
+ bool changed = false;
+ foreach (uint el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_int64_array (Collection<int64?> coll, int64?[] arr) {
+ bool changed = false;
+ foreach (unowned int64? el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_uint64_array (Collection<uint64?> coll, uint64?[] arr) {
+ bool changed = false;
+ foreach (unowned uint64? el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_long_array (Collection<long> coll, long[] arr) {
+ bool changed = false;
+ foreach (long el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_ulong_array (Collection<ulong> coll, ulong[] arr) {
+ bool changed = false;
+ foreach (ulong el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_float_array (Collection<float?> coll, float?[] arr) {
+ bool changed = false;
+ foreach (unowned float? el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool add_all_double_array (Collection<double?> coll, double?[] arr) {
+ bool changed = false;
+ foreach (unowned double? el in arr) {
+ changed |= coll.add (el);
+ }
+ return changed;
+ }
+
+ private static bool contains_all_bool_array (Collection<bool> coll, bool[] arr) {
+ foreach (bool el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_char_array (Collection<char> coll, char[] arr) {
+ foreach (char el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_uchar_array (Collection<uchar> coll, uchar[] arr) {
+ foreach (uchar el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_int_array (Collection<int> coll, int[] arr) {
+ foreach (int el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_uint_array (Collection<uint> coll, uint[] arr) {
+ foreach (uint el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_int64_array (Collection<int64?> coll, int64?[] arr) {
+ foreach (unowned int64? el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_uint64_array (Collection<uint64?> coll, uint64?[] arr) {
+ foreach (unowned uint64? el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_long_array (Collection<long> coll, long[] arr) {
+ foreach (long el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_ulong_array (Collection<ulong> coll, ulong[] arr) {
+ foreach (ulong el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_float_array (Collection<float?> coll, float?[] arr) {
+ foreach (unowned float? el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool contains_all_double_array (Collection<double?> coll, double?[] arr) {
+ foreach (unowned double? el in arr) {
+ if (!coll.contains (el)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static bool remove_all_bool_array (Collection<bool> coll, bool[] arr) {
+ bool changed = false;
+ foreach (bool el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_char_array (Collection<char> coll, char[] arr) {
+ bool changed = false;
+ foreach (char el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_uchar_array (Collection<uchar> coll, uchar[] arr) {
+ bool changed = false;
+ foreach (uchar el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_int_array (Collection<int> coll, int[] arr) {
+ bool changed = false;
+ foreach (int el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_uint_array (Collection<uint> coll, uint[] arr) {
+ bool changed = false;
+ foreach (uint el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_int64_array (Collection<int64?> coll, int64?[] arr) {
+ bool changed = false;
+ foreach (unowned int64? el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_uint64_array (Collection<uint64?> coll, uint64?[] arr) {
+ bool changed = false;
+ foreach (unowned uint64? el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_long_array (Collection<long> coll, long[] arr) {
+ bool changed = false;
+ foreach (long el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_ulong_array (Collection<ulong> coll, ulong[] arr) {
+ bool changed = false;
+ foreach (ulong el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_float_array (Collection<float?> coll, float?[] arr) {
+ bool changed = false;
+ foreach (unowned float? el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
+ }
+
+ private static bool remove_all_double_array (Collection<double?> coll, double?[] arr) {
+ bool changed = false;
+ foreach (unowned double? el in arr) {
+ changed |= coll.remove (el);
+ }
+ return changed;
}
}
diff --git a/gee/comparable.vala b/gee/comparable.vala
index 489a7c8..8520ad2 100644
--- a/gee/comparable.vala
+++ b/gee/comparable.vala
@@ -24,6 +24,18 @@
* This interface defines a total ordering among instances of each class
* implementing it.
*
+ * In other words:
+ *
+ * * It's irreflexive: For all `a` it holds that `a.compare_to(a) == 0`
+ * * It's transitive: For all `a`, `b` and `c` if `a.compare_to(b) < 0` and
+ * `b.compare_to(c) < 0` then `a.compare_to(c) < 0`.
+ * * It's trichotomous: For all `a` and `b` it holds that
+ * `a.compare_to(b) = -b.compare_to(a)`.
+ *
+ * Note: The relationship must be immutable. In other words if at one point of
+ * program `a.compare_to(b)` had certain value then call `a.compare_to(b)`
+ * //must always// return the original value until end of `a` and `b` lifetime.
+ *
* @see Hashable
*/
public interface Vala.Comparable<G> : Object {
diff --git a/gee/concurrentlist.vala b/gee/concurrentlist.vala
index 485e2d2..e020375 100644
--- a/gee/concurrentlist.vala
+++ b/gee/concurrentlist.vala
@@ -1,6 +1,6 @@
/* concurrentlist.vala
*
- * Copyright (C) 2011 Maciej Piechotka
+ * Copyright (C) 2011-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,7 @@
* [[http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf|Mikhail Fomitchev and Eric Ruppert paper ]].
*
* Many threads are allowed to operate on the same structure as well as modification
- * of structure during iteration is allowed. However the change may not be immidiatly
+ * of structure during iteration is allowed. However the change may not be immediately
* visible to other threads.
*/
public class Vala.ConcurrentList<G> : AbstractList<G> {
@@ -33,7 +33,12 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
* The elements' equality testing function.
*/
[CCode (notify = false)]
- public Vala.EqualDataFunc<G> equal_func { private set; get; }
+ public Vala.EqualDataFunc<G> equal_func {
+ private set {}
+ get {
+ return _equal_func.func;
+ }
+ }
/**
* Construct new, empty single linked list
@@ -44,15 +49,23 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
* @param equal_func an optional element equality testing function
*/
public ConcurrentList (owned Vala.EqualDataFunc<G>? equal_func = null) {
- if (equal_func == null)
+ if (equal_func == null) {
equal_func = Vala.Functions.get_equal_func_for (typeof (G));
- this.equal_func = (owned)equal_func;
+ }
+ _equal_func = new Functions.EqualDataFuncClosure<G>((owned)equal_func);
+ _head = new Node<G>.head ();
+ HazardPointer.set_pointer<Node<G>> (&_tail, _head);
+ }
+
+ internal ConcurrentList.with_closure (owned Functions.EqualDataFuncClosure<G> equal_func) {
+ _equal_func = (owned)equal_func;
_head = new Node<G>.head ();
HazardPointer.set_pointer<Node<G>> (&_tail, _head);
}
~ConcurrentList () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
_head = null;
HazardPointer.set_pointer<Node<G>?> (&_tail, null);
}
@@ -72,6 +85,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
public override int size {
get {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
int result = 0;
for (var iter = iterator (); iter.next ();)
result++;
@@ -93,6 +107,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override bool contains (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
for (var iter = iterator (); iter.next ();)
if (equal_func (item, iter.get ()))
return true;
@@ -104,6 +119,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override bool add (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
Node<G> node = new Node<G> (item);
node.insert (get_tail (), null);
return true;
@@ -114,6 +130,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override bool remove (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
Vala.Iterator<G> iter = iterator ();
while (iter.next ()) {
if (equal_func (item, iter.get ())) {
@@ -129,6 +146,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override void clear () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
var iter = iterator ();
while (iter.next ())
iter.remove ();
@@ -154,6 +172,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override G? get (int index) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (index >= 0);
for (var iterator = iterator (); iterator.next ();)
if (index-- == 0)
@@ -166,6 +185,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override void set (int index, G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (index >= 0);
for (var iterator = list_iterator (); iterator.next ();) {
if (index-- == 0) {
@@ -181,6 +201,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override int index_of (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
int index = 0;
for (var iterator = list_iterator (); iterator.next (); index++)
if (equal_func (item, iterator.get ()))
@@ -193,6 +214,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override void insert (int index, G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (index >= 0);
if (index == 0) {
var prev = _head;
@@ -215,6 +237,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override G remove_at (int index) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
for (var iterator = list_iterator (); iterator.next ();) {
if (index-- == 0) {
G data = iterator.get ();
@@ -230,9 +253,10 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
*/
public override List<G>? slice (int start, int end) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (0 <= start);
assert (start <= end);
- var list = new ConcurrentList<G> (equal_func);
+ var list = new ConcurrentList<G>.with_closure (_equal_func);
var iterator = iterator ();
int idx = 0;
for (; iterator.next (); idx++)
@@ -258,25 +282,32 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
private Node<G> _head;
private Node<G> *_tail;
+ private Functions.EqualDataFuncClosure<G> _equal_func;
private class Iterator<G> : Object, Vala.Traversable<G>, Vala.Iterator<G>, ListIterator<G> {
public Iterator (Node<G> head) {
- _started = false;
_removed = false;
_index = -1;
_prev = null;
_curr = head;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _removed = iter._removed;
+ _index = iter._index;
+ _prev = iter._prev;
+ _curr = iter._curr;
+ }
+
public bool next () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
Node<G>? _old_prev = _removed ? _prev : null;
bool success = Node.proceed<G> (ref _prev, ref _curr);
if (success) {
if (_removed)
- _prev = _old_prev;
+ _prev = (owned)_old_prev;
_removed = false;
- _started = true;
_index++;
}
return success;
@@ -284,19 +315,22 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
public bool has_next () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
Node<G>? prev = _prev;
- Node<G>? curr = _curr;
+ Node<G> curr = _curr;
return Node.proceed<G> (ref prev, ref curr);
}
public new G get () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (valid);
return HazardPointer.get_pointer<G> (&_curr._data);
}
public new void set (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (valid);
#if DEBUG
G item_copy = item;
@@ -309,6 +343,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
public void remove () {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (valid);
_curr.remove (_prev);
_removed = true;
@@ -316,7 +351,10 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
}
public bool valid {
- get { return _started && !_removed && _curr != null; }
+ get {
+ assert (_curr != null);
+ return _prev != null && !_removed;
+ }
}
public bool read_only { get { return false; } }
@@ -328,6 +366,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
public void add (G item) {
HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
assert (valid);
if (!Node.proceed<G> (ref _prev, ref _curr)) {
_prev = (owned)_curr;
@@ -337,11 +376,13 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
new_node.insert (_prev, _curr);
_curr = (owned)new_node;
_index++;
+ _removed = false;
}
public new bool foreach (ForallFunc<G> f) {
HazardPointer.Context ctx = new HazardPointer.Context ();
- if (_started && !_removed) {
+ Utils.Misc.unused (ctx);
+ if (_prev != null && !_removed) {
if (!f (HazardPointer.get_pointer<G> (&_curr._data))) {
return false;
}
@@ -349,9 +390,8 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
Node<G>? _old_prev = _removed ? _prev : null;
while (Node.proceed<G> (ref _prev, ref _curr)) {
if (_removed)
- _prev = _old_prev;
+ _prev = (owned)_old_prev;
_removed = false;
- _started = true;
_index++;
if (!f (HazardPointer.get_pointer<G> (&_curr._data))) {
return false;
@@ -360,11 +400,23 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
return true;
}
- private bool _started;
- private bool _removed;
- private int _index;
- private Node<G> _prev;
- private Node<G>? _curr;
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected bool _removed;
+ protected int _index;
+ protected Node<G>? _prev;
+ protected Node<G> _curr;
}
private class Node<G> {
@@ -463,7 +515,7 @@ public class Vala.ConcurrentList<G> : AbstractList<G> {
}
search_for<G> (next, ref prev);
}
-
+
}
public inline void help_flagged (Node<G> prev) {
diff --git a/gee/concurrentset.vala b/gee/concurrentset.vala
new file mode 100644
index 0000000..5c16696
--- /dev/null
+++ b/gee/concurrentset.vala
@@ -0,0 +1,1445 @@
+/* concurrentset.vala
+ *
+ * Copyright (C) 2012-2014 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 skip-linked list. This implementation is based on
+ * [[http://www.cse.yorku.ca/~ruppert/Mikhail.pdf|Mikhail Fomitchev Master Thesis]].
+ *
+ * Many threads are allowed to operate on the same structure as well as modification
+ * of structure during iteration is allowed. However the change may not be immidiatly
+ * visible to other threads.
+ */
+public class Vala.ConcurrentSet<G> : AbstractSortedSet<G> {
+ public ConcurrentSet (owned CompareDataFunc<G>? compare_func = null) {
+ if (compare_func == null) {
+ compare_func = Functions.get_compare_func_for (typeof (G));
+ }
+ _cmp = (owned)compare_func;
+ }
+
+ ~ConcurrentSet () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ _head = null;
+ }
+
+ public override int size { get { return GLib.AtomicInt.get (ref _size); } }
+
+ public override bool read_only { get { return false; } }
+
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this, _head);
+ }
+
+ public override bool contains (G key) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _head;
+ return Tower.search<G> (_cmp, key, ref prev, null);
+ }
+
+ public override bool add (G key) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Rand *rnd = rand.get ();
+ if (rnd == null) {
+ rand.set (rnd = new Rand ());
+ }
+ uint32 rand_int = rnd->int_range (0, int32.MAX);
+ uint8 height = 1 + (uint8)GLib.Bit.nth_lsf (~rand_int, -1);
+ TowerIter<G> prev = TowerIter<G>();
+ prev._iter[height - 1] = _head;
+ if (Tower.search<G> (_cmp, key, ref prev._iter[height - 1], null, height - 1)) {
+ return false;
+ }
+ for (int i = height - 2; i >= 0; i--) {
+ prev._iter[i] = prev._iter[height - 1];
+ }
+ Tower<G>? result = Tower.insert<G> (_cmp, ref prev, key, height - 1);
+ if (result != null) {
+ GLib.AtomicInt.inc (ref _size);
+ }
+ return result != null;
+ }
+
+ public override bool remove (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ TowerIter<G> prev = TowerIter<G>();
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ prev._iter[i] = _head;
+ }
+ bool result = Tower.remove_key<G> (_cmp, ref prev, item);
+ if (result) {
+ GLib.AtomicInt.dec_and_test (ref _size);
+ }
+ return result;
+ }
+
+ public override void clear () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? first;
+ while ((first = _head.get_next (0)) != null) {
+ remove (first._data);
+ }
+ }
+
+ public override G first () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? prev = null;
+ Tower<G> curr = _head;
+ if (Tower.proceed<G> (_cmp, ref prev, ref curr, 0)) {
+ return curr._data;
+ } else {
+ return null;
+ }
+ }
+
+ public override G last () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? prev = null;
+ Tower<G> curr = _head;
+ bool found = false;
+ for (int i = _MAX_HEIGHT; i >= 0; i--) {
+ while (Tower.proceed<G> (_cmp, ref prev, ref curr, 0)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ return null;
+ }
+ return curr._data;
+ }
+
+ public override Vala.Iterator<G>? iterator_at (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ TowerIter<G> prev = TowerIter<G> ();
+ TowerIter<G> curr;
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ prev._iter[i] = _head;
+ }
+ if (!Tower.search_from_bookmark<G> (_cmp, element, ref prev, out curr)) {
+ return null;
+ }
+ return new Iterator<G>.point_at (this, ref prev, curr._iter[0]);
+ }
+
+ public override G? lower (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _head;
+ Tower.search<G> (_cmp, element, ref prev);
+ if (prev == _head) {
+ return null;
+ }
+ return prev._data;
+ }
+
+ public override G? higher (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _head;
+ Tower<G>? next;
+ if (Tower.search<G> (_cmp, element, ref prev, out next)) {
+ if (!Tower.proceed<G> (_cmp, ref prev, ref next, 0)) {
+ return null;
+ }
+ }
+ if (next == null) {
+ return null;
+ }
+ return next._data;
+ }
+
+ public override G? floor (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _head;
+ Tower<G>? next;
+ if (Tower.search<G> (_cmp, element, ref prev, out next)) {
+ return next._data;
+ } else if (prev != _head) {
+ return prev._data;
+ } else {
+ return null;
+ }
+ }
+
+ public override G? ceil (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _head;
+ Tower<G>? next;
+ Tower.search<G> (_cmp, element, ref prev, out next);
+ if (next == null) {
+ return null;
+ }
+ return next._data;
+ }
+
+ public override SortedSet<G> head_set (G before) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (new Range<G>.head (this, before));
+ }
+
+ public override SortedSet<G> tail_set (G after) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (new Range<G>.tail (this, after));
+ }
+ public override SortedSet<G> sub_set (G from, G to) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (new Range<G> (this, from, to));
+ }
+
+ private unowned G max (G a, G b, out bool changed = null) {
+ changed = _cmp (a, b) < 0;
+ return changed ? b : a;
+ }
+
+ private unowned G min (G a, G b, out bool changed = null) {
+ changed = _cmp (a, b) > 0;
+ return changed ? b : a;
+ }
+
+#if DEBUG
+ public void dump () {
+ for (int i = _MAX_HEIGHT - 1; i >= 0; i--) {
+ bool printed = false;
+ Tower<G>? curr = _head;
+ State state;
+ while ((curr = curr.get_succ (out state, (uint8)i)) != null) {
+ if (!printed) {
+ stderr.printf("Level %d\n", i);
+ printed = true;
+ }
+ stderr.printf(" Node %p%s - %s\n", curr, state == State.NONE ? "" : state
== State.MARKED ? " (MARKED)" : " (FLAGGED)", (string)curr._data);
+ assert (curr._height > i);
+ }
+ }
+ }
+#endif
+
+ private int _size = 0;
+ private Tower<G> _head = new Tower<G>.head ();
+ private CompareDataFunc<G>? _cmp;
+ private const int _MAX_HEIGHT = 31;
+ private static Private rand = new Private((ptr) => {
+ Rand *rnd = (Rand *)ptr;
+ delete rnd;
+ });
+
+ private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
+ public Iterator (ConcurrentSet cset, Tower<G> head) {
+ _curr = head;
+ _set = cset;
+ assert (_curr != null);
+ }
+
+ public Iterator.point_at (ConcurrentSet cset, ref TowerIter<G> prev, Tower<G> curr) {
+ _curr = curr;
+ _set = cset;
+ _prev = prev;
+ assert (_curr != null);
+ }
+
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _curr = iter._curr;
+ _set = iter._set;
+ _prev = iter._prev;
+ _removed = iter._removed;
+ }
+
+ public new bool foreach (ForallFunc<G> f) {
+ assert (_curr != null);
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (_prev._iter[0] != null && !_removed) {
+ if (!f (_curr._data)) {
+ assert (_curr != null);
+ return false;
+ }
+ }
+ Tower<G> new_prev = _prev._iter[0];
+ Tower<G>? new_curr = _curr;
+ while (Tower.proceed<G> (_set._cmp, ref new_prev, ref new_curr, 0)) {
+ assert (_curr != null);
+ if (!_removed) {
+ //FIXME: Help mark/delete on the way
+ _prev._iter[0] = new_prev;
+ int prev_height = _prev._iter[0].get_height();
+ for (int i = 1; i < prev_height; i++) {
+ _prev._iter[i] = _prev._iter[0];
+ }
+ }
+ _curr = new_curr;
+ _removed = false;
+ if (!f (_curr._data)) {
+ assert (_curr != null);
+ return false;
+ }
+ }
+ assert (_curr != null);
+ return true;
+ }
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ public bool next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? new_prev = _prev._iter[0];
+ Tower<G>? new_curr = _curr;
+ bool success = Tower.proceed<G> (_set._cmp, ref new_prev, ref new_curr, 0);
+ if (success) {
+ if (!_removed) {
+ //FIXME: Help mark/delete on the way
+ _prev._iter[0] = (owned)new_prev;
+ int prev_height = _prev._iter[0].get_height();
+ for (int i = 1; i < prev_height; i++) {
+ _prev._iter[i] = _prev._iter[0];
+ }
+ }
+ _curr = (owned)new_curr;
+ _removed = false;
+ }
+ assert (_curr != null);
+ return success;
+ }
+
+ public bool has_next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G> prev = _prev._iter[0];
+ Tower<G>? curr = _curr;
+ return Tower.proceed<G> (_set._cmp, ref prev, ref curr, 0);
+ }
+
+ public new G get () {
+ assert (valid);
+ return _curr._data;
+ }
+
+ public void remove () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ assert (valid);
+ if (Tower.remove<G> (_set._cmp, ref _prev, _curr)) {
+ AtomicInt.dec_and_test (ref _set._size);
+ }
+ _removed = true;
+ }
+
+ public bool valid { get { return _prev._iter[0] != null && !_removed; } }
+
+ public bool read_only { get { return true; } }
+
+ protected bool _removed = false;
+ protected ConcurrentSet<G> _set;
+ protected TowerIter<G> _prev;
+ protected Tower<G> _curr;
+ }
+
+ private class SubSet<G> : AbstractSortedSet<G> {
+ public override int size {
+ get {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? curr;
+ Range.improve_bookmark<G> (_range, out curr);
+ if (curr != null) {
+ int acc = 1;
+ Tower<G>? prev = HazardPointer.get_pointer<Tower<G>>
(&_range._bookmark._iter[0]);
+ while (Range.proceed<G> (_range, ref prev, ref curr, 0)) {
+ acc++;
+ }
+ return acc;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public bool is_empty {
+ get {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? curr;
+ Range.improve_bookmark<G> (_range, out curr);
+ return curr != null;
+ }
+ }
+
+ public override bool read_only { get { return false; } }
+
+ public SubSet (Range<G> range) {
+ _range = range;
+ }
+
+ public override Vala.Iterator<G> iterator () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubIterator<G> (_range);
+ }
+
+ public override bool contains (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (!Range.inside<G> (_range, item)) {
+ return false;
+ }
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ return Tower.search_from_bookmark<G> (_range._set._cmp, item, ref prev);
+ }
+
+ public override bool add (G key) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (!Range.inside<G> (_range, key)) {
+ return false;
+ }
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ Rand *rnd = ConcurrentSet.rand.get ();
+ if (rnd == null) {
+ rand.set (rnd = new Rand ());
+ }
+ uint32 rand_int = rnd->int_range (0, int32.MAX);
+ uint8 height = 1 + (uint8)GLib.Bit.nth_lsf (~rand_int, -1);
+ if (Tower.search_from_bookmark<G> (_range._set._cmp, key, ref prev, null, height -
1)) {
+ return false;
+ }
+ for (int i = height - 2; i >= 0; i--) {
+ prev._iter[i] = prev._iter[height - 1];
+ }
+ Tower<G>? result = Tower.insert<G> (_range._set._cmp, ref prev, key, height - 1);
+ if (result != null) {
+ GLib.AtomicInt.inc (ref _range._set._size);
+ }
+ return result != null;
+ }
+
+ public override bool remove (G key) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (!Range.inside<G> (_range, key)) {
+ return false;
+ }
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ // FIXME: Use full bookmark
+ bool result = Tower.remove_key<G> (_range._set._cmp, ref prev, key);
+ if (result) {
+ GLib.AtomicInt.dec_and_test (ref _range._set._size);
+ }
+ return result;
+ }
+
+ public override void clear () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ TowerIter<G> prev;
+ Tower<G>? first;
+ Range.improve_bookmark<G> (_range, out first, out prev);
+ while (first != null) {
+ Tower.remove<G> (_range._set._cmp, ref prev, first);
+ Range.improve_bookmark<G> (_range, out first, out prev);
+ }
+ }
+
+ public override G? first () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ Tower<G>? first;
+ Range.improve_bookmark<G> (_range, out first);
+ if (first == null) {
+ return null;
+ }
+ return first._data;
+ }
+
+ public override G? last () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ Tower<G>? curr = null;
+ for (int i = _MAX_HEIGHT - 1; i >= 0; i--) {
+ if (curr == null) {
+ curr = prev._iter[i].get_next ((uint8)i);
+ if (curr == null || !Range.inside<G> (_range, curr._data)) {
+ curr = null;
+ continue;
+ }
+ }
+ bool improved = false;
+ while (Range.proceed<G> (_range, ref prev._iter[i], ref curr, (uint8)i)) {
+ improved = true;
+ }
+ if (improved && i > 0) {
+ prev._iter[i - 1] = prev._iter[i];
+ }
+ }
+ if (curr == null) {
+ return null;
+ }
+ return curr._data;
+ }
+
+ public override Vala.Iterator<G>? iterator_at (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (!Range.inside<G> (_range, element)) {
+ return null;
+ }
+ TowerIter<G> prev;
+ TowerIter<G> next;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ if (!Tower.search_from_bookmark<G> (_range._set._cmp, element, ref prev, out next)) {
+ return null;
+ }
+ return new SubIterator<G>.point_at (_range, ref prev, next._iter[0]);
+ }
+
+ public override G? lower (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ switch (Range.cmp<G> (_range, element)) {
+ case Range.Position.BEFORE:
+ case Range.Position.EMPTY:
+ return null;
+ case Range.Position.INSIDE:
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ Tower.search_from_bookmark<G> (_range._set._cmp, element, ref prev);
+ if (prev._iter[0] == _range._set._head || !Range.inside (_range,
prev._iter[0]._data)) {
+ return null;
+ }
+ return prev._iter[0]._data;
+ case Range.Position.AFTER:
+ return last ();
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public override G? higher (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ switch (Range.cmp<G> (_range, element)) {
+ case Range.Position.BEFORE:
+ return first ();
+ case Range.Position.INSIDE:
+ TowerIter<G> prev;
+ TowerIter<G> curr;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ if (Tower.search_from_bookmark<G> (_range._set._cmp, element, ref prev, out
curr)) {
+ if (!Tower.proceed<G> (_range._set._cmp, ref prev._iter[0], ref
curr._iter[0], 0)) {
+ return null;
+ }
+ }
+ if (curr._iter[0] == null || !Range.inside(_range, curr._iter[0]._data)) {
+ return null;
+ }
+ return curr._iter[0]._data;
+ case Range.Position.AFTER:
+ case Range.Position.EMPTY:
+ return null;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public override G? floor (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ switch (Range.cmp<G> (_range, element)) {
+ case Range.Position.BEFORE:
+ case Range.Position.EMPTY:
+ return null;
+ case Range.Position.INSIDE:
+ TowerIter<G> curr;
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ if (!Tower.search_from_bookmark<G> (_range._set._cmp, element, ref prev, out
curr)) {
+ curr._iter[0] = (owned)prev._iter[0];
+ }
+ if (curr._iter[0] == null || curr._iter[0].is_head () ||
!Range.inside(_range, curr._iter[0]._data)) {
+ return null;
+ }
+ return curr._iter[0]._data;
+ case Range.Position.AFTER:
+ return last ();
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public override G? ceil (G element) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ switch (Range.cmp<G> (_range, element)) {
+ case Range.Position.BEFORE:
+ return first ();
+ case Range.Position.INSIDE:
+ TowerIter<G> curr;
+ TowerIter<G> prev;
+ Range.improve_bookmark<G> (_range, null, out prev);
+ Tower.search_from_bookmark<G> (_range._set._cmp, element, ref prev, out curr);
+ if (curr._iter[0] == null || !Range.inside(_range, curr._iter[0]._data)) {
+ return null;
+ }
+ return curr._iter[0]._data;
+ case Range.Position.AFTER:
+ case Range.Position.EMPTY:
+ return null;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public override SortedSet<G> head_set (G before) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (Range.cut_tail (_range, before));
+ }
+
+ public override SortedSet<G> tail_set (G after) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (Range.cut_head (_range, after));
+ }
+
+ public override SortedSet<G> sub_set (G from, G to) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ return new SubSet<G> (Range.cut (_range, from, to));
+ }
+
+ private Range<G> _range;
+ }
+
+ private class SubIterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
+ public SubIterator (Range<G> range) {
+ Range.improve_bookmark<G> (range);
+ _range = range;
+ }
+
+ public SubIterator.point_at (Range<G> range, ref TowerIter<G> prev, owned Tower<G> curr) {
+ Range.improve_bookmark<G> (range);
+ _range = range;
+ _prev = prev;
+ _curr = curr;
+ }
+
+ public SubIterator.from_iterator (SubIterator<G> iter) {
+ Range.improve_bookmark<G> (iter._range);
+ _range = iter._range;
+ _prev = iter._prev;
+ _curr = iter._curr;
+ _removed = iter._removed;
+ }
+
+ public new bool foreach (ForallFunc<G> f) {
+ assert (_curr != null);
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (!begin ()) {
+ return true;
+ }
+ if (_prev._iter[0] != null && !_removed) {
+ if (!f (_curr._data)) {
+ assert (_curr != null);
+ return false;
+ }
+ }
+ Tower<G> new_prev = _prev._iter[0];
+ Tower<G>? new_curr = _curr;
+ while (Range.proceed<G> (_range, ref new_prev, ref new_curr, 0)) {
+ assert (_curr != null);
+ if (!f (_curr._data)) {
+ assert (_curr != null);
+ return false;
+ }
+ if (!_removed) {
+ //FIXME: Help mark/delete on the way
+ _prev._iter[0] = (owned)new_prev;
+ int prev_height = _prev._iter[0].get_height();
+ for (int i = 1; i < prev_height; i++) {
+ _prev._iter[i] = _prev._iter[0];
+ }
+ }
+ _curr = (owned)new_curr;
+ _removed = false;
+ }
+ assert (_curr != null);
+ return true;
+ }
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new SubIterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ public bool next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (_prev._iter[0] == null) {
+ return begin ();
+ } else {
+ Tower<G> new_prev = _prev._iter[0];
+ Tower<G> new_curr = _curr;
+ if (Range.proceed<G> (_range, ref new_prev, ref new_curr, 0)) {
+ if (!_removed) {
+ //FIXME: Help mark/delete on the way
+ _prev._iter[0] = (owned)new_prev;
+ int prev_height = _prev._iter[0].get_height();
+ for (int i = 1; i < prev_height; i++) {
+ _prev._iter[i] = _prev._iter[0];
+ }
+ }
+ _curr = (owned)new_curr;
+ _removed = false;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public bool has_next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ if (_prev._iter[0] == null) {
+ Tower<G> next;
+ Range.improve_bookmark<G> (_range, out next);
+ if (next != null && Range.beyond<G> (_range, next)) {
+ next = null;
+ }
+ return next != null;
+ } else {
+ Tower<G> new_prev = _prev._iter[0];
+ Tower<G> new_curr = _curr;
+ return Range.proceed<G> (_range, ref new_prev, ref new_curr, 0);
+ }
+ }
+
+ public new G get () {
+ assert (valid);
+ return _curr._data;
+ }
+
+ public void remove () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Utils.Misc.unused (ctx);
+ assert (valid);
+ if (Tower.remove<G> (_range._set._cmp, ref _prev, _curr)) {
+ AtomicInt.dec_and_test (ref _range._set._size);
+ }
+ _removed = true;
+ }
+
+ public bool valid {
+ get {
+ bool is_valid = _prev._iter[0] != null && !_removed;
+ assert (!is_valid || _curr != null);
+ return is_valid;
+ }
+ }
+
+ public bool read_only { get { return false; } }
+
+ private bool begin () {
+ if (_prev._iter[0] != null) {
+ return true;
+ }
+ Range.improve_bookmark<G> (_range, out _curr, out _prev);
+ if (_curr == null) {
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ _prev._iter[i] = null;
+ }
+ }
+ return _curr != null;
+ }
+
+ protected Range<G> _range;
+ protected TowerIter<G> _prev;
+ protected Tower<G>? _curr = null;
+ protected bool _removed = false;
+ }
+
+ private class Range<G> {
+ public G? _start;
+ public G? _end;
+ public RangeType _type;
+ public TowerIter<G> _bookmark;
+ public ConcurrentSet<G> _set;
+
+ public Range (ConcurrentSet<G> cset, G start, G end) {
+ _start = start;
+ _end = end;
+ if (cset._cmp(start, end) < 0) {
+ _type = RangeType.BOUNDED;
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ _bookmark._iter[i] = cset._head;
+ }
+ } else {
+ _type = RangeType.EMPTY;
+ }
+ _set = cset;
+ }
+
+ public Range.head (ConcurrentSet<G> cset, G end) {
+ _end = end;
+ _type = RangeType.HEAD;
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ _bookmark._iter[i] = cset._head;
+ }
+ _set = cset;
+ }
+
+ public Range.tail (ConcurrentSet<G> cset, G start) {
+ _start = start;
+ _type = RangeType.TAIL;
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ _bookmark._iter[i] = cset._head;
+ }
+ _set = cset;
+ }
+
+ public Range.empty (ConcurrentSet<G> cset) {
+ _type = RangeType.EMPTY;
+ _set = cset;
+ }
+
+ private void copy_bookmark (Range<G> range) {
+ for (int i = 0; i < _MAX_HEIGHT; i++) {
+ _bookmark._iter[i] = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[i]);
+ }
+ }
+
+ public static Range<G> cut_head<G> (Range<G> from, G start) {
+ Range<G> result = new Range<G>.empty (from._set);
+ switch (from._type) {
+ case RangeType.HEAD:
+ if (from._set._cmp (start, from._end) < 0) {
+ result._start = start;
+ result._end = from._end;
+ result._type = RangeType.BOUNDED;
+ } else {
+ result._type = RangeType.EMPTY;
+ }
+ break;
+ case RangeType.TAIL:
+ result._start = from._set.max (from._start, start);
+ result._type = RangeType.TAIL;
+ break;
+ case RangeType.BOUNDED:
+ if (from._set._cmp (from._start, start) < 0) {
+ result._start = from._set.max (from._start, start);
+ result._end = from._end;
+ result._type = RangeType.BOUNDED;
+ } else {
+ result._type = RangeType.EMPTY;
+ }
+ break;
+ case RangeType.EMPTY:
+ result._type = RangeType.EMPTY;
+ break;
+ default:
+ assert_not_reached ();
+ }
+ if (result._type != RangeType.EMPTY) {
+ improve_bookmark<G> (from);
+ result.copy_bookmark (from);
+ improve_bookmark<G> (result);
+ }
+ return result;
+ }
+
+ public static Range<G> cut_tail<G> (Range<G> from, G end) {
+ Range<G> result = new Range<G>.empty (from._set);
+ switch (from._type) {
+ case RangeType.HEAD:
+ result._end = from._set.min (from._end, end);
+ result._type = RangeType.HEAD;
+ break;
+ case RangeType.TAIL:
+ if (from._set._cmp (from._start, end) < 0) {
+ result._start = from._start;
+ result._end = end;
+ result._type = RangeType.BOUNDED;
+ } else {
+ result._type = RangeType.EMPTY;
+ }
+ break;
+ case RangeType.BOUNDED:
+ if (from._set._cmp (from._start, end) < 0) {
+ result._start = from._start;
+ result._end = from._set.min (from._end, end);
+ result._type = RangeType.BOUNDED;
+ } else {
+ result._type = RangeType.EMPTY;
+ }
+ break;
+ case RangeType.EMPTY:
+ result._type = RangeType.EMPTY;
+ break;
+ default:
+ assert_not_reached ();
+ }
+ if (result._type != RangeType.EMPTY) {
+ improve_bookmark<G> (from);
+ result.copy_bookmark (from);
+ improve_bookmark<G> (result);
+ }
+ return result;
+ }
+
+ public static Range<G> cut<G> (Range<G> from, G start, G end) {
+ Range<G> result = new Range<G>.empty (from._set);
+ result._type = RangeType.BOUNDED;
+ switch (from._type) {
+ case RangeType.HEAD:
+ end = from._set.min (from._end, end);
+ break;
+ case RangeType.TAIL:
+ start = from._set.max (from._start, start);
+ break;
+ case RangeType.BOUNDED:
+ start = from._set.max (from._start, start);
+ end = from._set.min (from._end, end);
+ break;
+ case RangeType.EMPTY:
+ result._type = RangeType.EMPTY;
+ break;
+ default:
+ assert_not_reached ();
+ }
+ if (result._type != RangeType.EMPTY && from._set._cmp (start, end) < 0) {
+ result._start = start;
+ result._end = end;
+ result._type = RangeType.BOUNDED;
+ } else {
+ result._type = RangeType.EMPTY;
+ }
+ if (result._type != RangeType.EMPTY) {
+ improve_bookmark<G> (from);
+ result.copy_bookmark (from);
+ improve_bookmark<G> (result);
+ }
+ return result;
+ }
+
+ public static void improve_bookmark<G> (Range<G> range, out Tower<G>? out_curr = null, out
TowerIter<G> prev = null) {
+ prev = TowerIter<G>();
+ out_curr = null;
+ switch (range._type) {
+ case RangeType.HEAD:
+ if (&out_curr != null) {
+ out_curr = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[0]);
+ if (&prev != null) {
+ prev._iter[0] = (owned)out_curr;
+ out_curr = prev._iter[0].get_next (0);
+ } else {
+ out_curr = out_curr.get_next (0);
+ }
+ }
+ if (&prev != null) {
+ for (int i = &out_curr != null ? 1 : 0; i < _MAX_HEIGHT; i++) {
+ prev._iter[i] = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[i]);
+ }
+ }
+ break;
+ case RangeType.EMPTY:
+ out_curr = null;
+ break;
+ case RangeType.TAIL:
+ case RangeType.BOUNDED:
+ Tower<G>? last_best = null;
+ for (int i = _MAX_HEIGHT - 1; i >= 0; i--) {
+ Tower<G> curr = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[i]);
+ Tower<G> curr_old = curr;
+ assert (curr != null);
+ Tower.backtrace<G> (ref curr, (uint8)i);
+ if (last_best != null && last_best != curr && Tower.compare<G>
(range._set._cmp, curr, last_best) < 0) {
+ curr = last_best;
+ }
+ if (curr != curr_old) {
+ if (!HazardPointer.compare_and_exchange_pointer<Tower<G>>
(&range._bookmark._iter[i], curr_old, curr)) {
+ curr = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[i]);
+ }
+ }
+ Tower<G> next = curr.get_next ((uint8)i);
+ if (&out_curr != null && i == 0) {
+ out_curr = next;
+ }
+ while (next != null && Tower.compare_data<G> (range._set._cmp, next,
range._start) < 0) {
+ Tower.proceed<G> (range._set._cmp, ref curr, ref next,
(uint8)i, true);
+ if (&curr != null && i == 0 && next != null) {
+ out_curr = next;
+ }
+ if (Tower.compare_data<G> (range._set._cmp, curr,
range._start) < 0) {
+ if
(!HazardPointer.compare_and_exchange_pointer<Tower<G>> (&range._bookmark._iter[i], curr_old, curr)) {
+ curr = HazardPointer.get_pointer<Tower<G>>
(&range._bookmark._iter[i]);
+ }
+ curr_old = curr;
+ } else {
+ break;
+ }
+ }
+ if (&prev != null) {
+ prev._iter[i] = curr;
+ }
+ last_best = (owned)curr;
+ }
+ break;
+ default:
+ assert_not_reached ();
+ }
+ if (&out_curr != null && out_curr != null && Range.beyond<G> (range, out_curr)) {
+ out_curr = null;
+ }
+#if DEBUG
+ stderr.printf("Bookmark after:\n");
+ for (int i = _MAX_HEIGHT - 1; i >= 0; i--) {
+ stderr.printf(" Level %d:\n", i);
+ Tower<string>? t = HazardPointer.get_pointer<Tower<string>>
(&range._bookmark._iter[i]);
+ assert (t == null || t.get_height () > i);
+ while (t != null) {
+ stderr.printf(" %s\n", t.is_head () ? "<<head>>" : t._data);
+ t = t.get_next ((uint8)i);
+ assert (t == null || t.get_height () > i);
+ }
+ }
+#endif
+ }
+
+ public static bool proceed<G> (Range<G> range, ref Tower<G>? prev, ref Tower<G> curr, uint8
level) {
+ switch (range._type) {
+ case RangeType.EMPTY:
+ return false;
+ case RangeType.TAIL:
+ return Tower.proceed<G> (range._set._cmp, ref prev, ref curr, level);
+ case RangeType.HEAD:
+ case RangeType.BOUNDED:
+ Tower<G>? tmp_prev = prev;
+ Tower<G>? tmp_curr = curr;
+ if (!Tower.proceed<G> (range._set._cmp, ref tmp_prev, ref tmp_curr, level)) {
+ return false;
+ } else if (Tower.compare_data<G> (range._set._cmp, tmp_curr, range._end) >=
0) {
+ return false;
+ } else {
+ prev = (owned)tmp_prev;
+ curr = (owned)tmp_curr;
+ return true;
+ }
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public static bool inside<G> (Range<G> range, G val) {
+ switch (range._type) {
+ case RangeType.HEAD:
+ return range._set._cmp (val, range._end) < 0;
+ case RangeType.TAIL:
+ return range._set._cmp (val, range._start) >= 0;
+ case RangeType.BOUNDED:
+ return range._set._cmp (val, range._start) >= 0 && range._set._cmp (val,
range._end) < 0;
+ case RangeType.EMPTY:
+ return false;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public static bool beyond<G> (Range<G> range, Tower<G> tw) {
+ switch (range._type) {
+ case RangeType.EMPTY:
+ return true;
+ case RangeType.TAIL:
+ return false;
+ case RangeType.HEAD:
+ case RangeType.BOUNDED:
+ return Tower.compare_data<G> (range._set._cmp, tw, range._end) >= 0;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public static int cmp<G> (Range<G> range, G val) {
+ switch (range._type) {
+ case RangeType.HEAD:
+ return range._set._cmp (val, range._end) < 0 ? Position.INSIDE :
Position.AFTER;
+ case RangeType.TAIL:
+ return range._set._cmp (val, range._start) >= 0 ? Position.INSIDE :
Position.BEFORE;
+ case RangeType.BOUNDED:
+ return range._set._cmp (val, range._start) >= 0 ? (range._set._cmp (val,
range._end) < 0 ? Position.INSIDE : Position.AFTER) : Position.BEFORE;
+ case RangeType.EMPTY:
+ return Position.EMPTY;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ enum Position {
+ BEFORE = -1,
+ INSIDE = 0,
+ AFTER = 1,
+ EMPTY
+ }
+ }
+
+ public enum RangeType {
+ HEAD,
+ TAIL,
+ BOUNDED,
+ EMPTY
+ }
+
+ private class Tower<G> {
+ public inline Tower (G data, uint8 height) {
+ _nodes = new TowerNode<G>[height];
+ _data = data;
+ _height = 0;
+ AtomicPointer.set (&_nodes[0]._backlink, null); // FIXME: This should be memory
barrier
+ }
+
+ public inline Tower.head () {
+ _nodes = new TowerNode<G>[_MAX_HEIGHT];
+ _height = -1;
+#if DEBUG
+ _data = (G)"<<head>>";
+#endif
+ }
+
+ inline ~Tower () {
+ int height = get_height();
+ for (uint8 i = 0; i < height; i++) {
+ set_succ (null, State.NONE, i);
+ set_backlink (null, i);
+ }
+ _nodes = null;
+ }
+
+ public static inline bool search<G> (CompareDataFunc<G>? cmp, G key, ref Tower<G> prev, out
Tower<G>? next = null, uint8 to_level = 0, uint8 from_level = (uint8)_MAX_HEIGHT - 1) {
+ assert (from_level >= to_level);
+ bool res = false;
+ next = null;
+ for (int i = from_level; i >= to_level; i--) {
+ res = search_helper<G> (cmp, key, ref prev, out next, (uint8)i);
+ }
+ return res;
+ }
+
+ public static inline bool search_from_bookmark<G> (CompareDataFunc<G>? cmp, G key, ref
TowerIter<G> prev, out TowerIter<G> next = null, uint8 to_level = 0, uint8 from_level = (uint8)_MAX_HEIGHT -
1) {
+ assert (from_level >= to_level);
+ next = TowerIter<G>();
+ bool res = false;
+ for (int i = from_level; i >= to_level; i--) {
+ unowned Tower<G> tmp_prev = prev._iter[i]; // Should be treated as NULL-like
value
+ Tower<G> tmp_next;
+ res = search_helper<G> (cmp, key, ref prev._iter[i], out tmp_next, (uint8)i);
+ if (&next != null) {
+ next._iter[i] = (owned)tmp_next;
+ }
+ if (prev._iter[i] != tmp_prev) {
+ prev._iter[i] = prev._iter[i];
+ if (i > to_level && compare<G> (cmp, prev._iter[i - 1],
prev._iter[i]) <= 0) {
+ prev._iter[i - 1] = prev._iter[i];
+ }
+ }
+ }
+ return res;
+ }
+
+ private static inline bool search_helper<G> (CompareDataFunc<G>? cmp, G key, ref Tower<G>?
prev, out Tower<G>? next, uint8 level) {
+ next = prev.get_next (level);
+ while (next != null && compare_data<G> (cmp, next, key) < 0 && proceed<G> (cmp, ref
prev, ref next, level, true));
+ return next != null && cmp(key, next._data) == 0;
+ }
+
+ public static inline Tower<G>? insert<G> (CompareDataFunc<G>? cmp, ref TowerIter<G> prev, G
key, uint8 chosen_level) {
+ return insert_helper<G> (cmp, ref prev, key, chosen_level, chosen_level);
+ }
+
+ private static inline Tower<G>? insert_helper<G> (CompareDataFunc<G>? cmp, ref TowerIter<G>
prev, G key, uint8 chosen_level, uint8 level) {
+ Tower<G>? new_tower;
+ Tower<G>? next;
+ if (search_helper (cmp, key, ref prev._iter[level], out next, level)) {
+ return null;
+ }
+ if (level > 0) {
+ if (compare<G> (cmp, prev._iter[level], prev._iter[level - 1]) >= 0) {
+ prev._iter[level - 1] = prev._iter[level];
+ }
+ new_tower = insert_helper<G> (cmp, ref prev, key, chosen_level, level - 1);
+ } else {
+ new_tower = new Tower<G> (key, chosen_level + 1);
+ }
+ if (new_tower == null) {
+ return null;
+ }
+ while (true) {
+ State prev_state;
+ Tower<G>? prev_next = prev._iter[level].get_succ (out prev_state, level);
+ if (prev_state == State.FLAGGED) {
+ prev_next.help_flagged (prev._iter[level], level);
+ } else {
+ new_tower.set_succ (next, State.NONE, level);
+ bool result = prev._iter[level].compare_and_exchange (next,
State.NONE, new_tower, State.NONE, level);
+ if (result)
+ break;
+ prev_next = prev._iter[level].get_succ (out prev_state, level);
+ if (prev_state == State.FLAGGED) {
+ prev_next.help_flagged (prev._iter[level], level);
+ }
+ backtrace<G> (ref prev._iter[level], level);
+ }
+ if (search_helper (cmp, key, ref prev._iter[level], null, level)) {
+ return null;
+ }
+ }
+ GLib.AtomicInt.inc (ref new_tower._height);
+ if (new_tower.get_state (0) == State.MARKED) {
+ remove_level (cmp, ref prev._iter[level], new_tower, level);
+ return null;
+ }
+ return new_tower;
+ }
+
+ public static inline bool remove_key<G> (CompareDataFunc<G>? cmp, ref TowerIter<G> prev, G
key, uint8 from_level = (uint8)_MAX_HEIGHT - 1) {
+ for (int i = from_level; i >= 1; i--) {
+ Tower<G> next;
+ search_helper<G> (cmp, key, ref prev._iter[i], out next, (uint8)i);
+ if (compare<G> (cmp, prev._iter[i - 1], prev._iter[i]) < 0) {
+ prev._iter[i - 1] = prev._iter[i];
+ }
+ }
+ Tower<G>? curr;
+ if (search_helper<G> (cmp, key, ref prev._iter[0], out curr, 0)) {
+ return remove<G> (cmp, ref prev, curr);
+ } else {
+ return false;
+ }
+ }
+
+ public static inline bool remove<G> (CompareDataFunc<G>? cmp, ref TowerIter<G> prev, Tower<G>
curr) {
+ bool removed = remove_level (cmp, ref prev._iter[0], curr, 0);
+ for (int i = 1; i < _MAX_HEIGHT; i++) {
+ remove_level (cmp, ref prev._iter[i], curr, (uint8)i);
+ }
+ return removed;
+ }
+
+ private static inline bool remove_level (CompareDataFunc<G>? cmp, ref Tower<G> prev, Tower<G>
curr, uint8 level) {
+ bool status;
+ bool flagged = curr.try_flag (cmp, ref prev, out status, level);
+ if (status) {
+ curr.help_flagged (prev, level);
+ }
+ return flagged;
+ }
+
+ public static inline bool proceed<G> (CompareDataFunc<G>? cmp, ref Tower<G>? arg_prev, ref
Tower<G> arg_curr, uint8 level, bool force = false) {
+ Tower<G> curr = arg_curr;
+ Tower<G>? next = curr.get_next (level);
+ if (next != null) {
+ while (next != null && next.get_state (0) == State.MARKED) {
+ bool status;
+ next.try_flag (cmp, ref curr, out status, level);
+ if (status) {
+ next.help_flagged (curr, level);
+ }
+ next = curr.get_next (level);
+ }
+ }
+ bool success = next != null;
+ if (success || force) {
+ arg_prev = (owned)curr;
+ arg_curr = (owned)next;
+ }
+ return success;
+ }
+
+ public inline void help_marked (Tower<G> prev_tower, uint8 level) {
+ prev_tower.compare_and_exchange (this, State.FLAGGED, get_next (level), State.NONE,
level);
+ }
+
+ public inline void help_flagged (Tower<G> prev, uint8 level) {
+ set_backlink (prev, level);
+ if (get_state (level) != State.MARKED)
+ try_mark (level);
+ help_marked (prev, level);
+ }
+
+ public inline void try_mark (uint8 level) {
+ do {
+ Tower<G>? next_tower = get_next (level);
+ bool result = compare_and_exchange (next_tower, State.NONE, next_tower,
State.MARKED, level);
+ if (!result) {
+ State state;
+ next_tower = get_succ (out state, level);
+ if (state == State.FLAGGED)
+ help_flagged (next_tower, level);
+ }
+ } while (get_state (level) != State.MARKED);
+ }
+
+ public inline bool try_flag (CompareDataFunc<G>? cmp, ref Tower<G> prev_tower, out bool
status, uint8 level) {
+ while (true) {
+ if (prev_tower.compare_succ (this, State.FLAGGED, level)) {
+ status = true;
+ return false;
+ }
+ bool result = prev_tower.compare_and_exchange (this, State.NONE, this,
State.FLAGGED, level);
+ if (result) {
+ status = true;
+ return true;
+ }
+ State result_state;
+ Tower<G>? result_tower = prev_tower.get_succ (out result_state, level);
+ if (result_tower == this && result_state == State.FLAGGED) {
+ status = true;
+ return false;
+ }
+ backtrace<G> (ref prev_tower, level);
+ if (!search_helper (cmp, _data, ref prev_tower, null, level)) {
+ status = false;
+ return false;
+ }
+ }
+ }
+
+ public static inline void backtrace<G> (ref Tower<G>? curr, uint8 level) {
+ while (curr.get_state (level) == State.MARKED)
+ curr = curr.get_backlink (level);
+ }
+
+ public inline bool compare_and_exchange (Tower<G>? old_tower, State old_state, Tower<G>?
new_tower, State new_state, uint8 level) {
+ return HazardPointer.compare_and_exchange_pointer<Tower<G>?> (&_nodes[level]._succ,
old_tower, new_tower, 3, (size_t)old_state, (size_t)new_state);
+ }
+
+ public inline bool compare_succ (Tower<G>? next, State state, uint8 level) {
+ size_t cur = (size_t)AtomicPointer.get (&_nodes[level]._succ);
+ return cur == ((size_t)next | (size_t)state);
+ }
+
+ public inline Tower<G>? get_next (uint8 level) {
+ return get_succ (null, level);
+ }
+
+ public inline State get_state (uint8 level) {
+ return (State)((size_t)AtomicPointer.get (&_nodes[level]._succ) & 3);
+ }
+
+ public inline Tower<G>? get_succ (out State state, uint8 level) {
+ size_t rstate;
+ Tower<G>? succ = HazardPointer.get_pointer<Tower<G>> (&_nodes[level]._succ, 3, out
rstate);
+ state = (State)rstate;
+ return (owned)succ;
+ }
+
+ public inline void set_succ (Tower<G>? next, State state, uint8 level) {
+ HazardPointer.set_pointer<Tower<G>> (&_nodes[level]._succ, next, 3, (size_t)state);
+ }
+
+ public inline Tower<G>? get_backlink (uint8 level) {
+ return HazardPointer.get_pointer<Tower<G>> (&_nodes[level]._backlink);
+ }
+
+ public inline void set_backlink (Tower<G>? backlink, uint8 level) {
+ HazardPointer.compare_and_exchange_pointer<Tower<G>?> (&_nodes[level]._backlink,
null, backlink);
+ }
+
+ public inline int get_height () {
+ int height = GLib.AtomicInt.get (ref _height);
+ return height != -1 ? height : _MAX_HEIGHT;
+ }
+
+ public inline bool is_head () {
+ int height = GLib.AtomicInt.get (ref _height);
+ return height == -1;
+ }
+
+ public inline static int compare<G> (CompareDataFunc<G>? cmp, Tower<G> a, Tower<G> b) {
+ bool ah = GLib.AtomicInt.get (ref a._height) == -1;
+ bool bh = GLib.AtomicInt.get (ref b._height) == -1;
+ return ah ? (bh ? 0 : -1) : (bh ? 1 : cmp(a._data, b._data));
+ }
+
+ public inline static int compare_data<G> (CompareDataFunc<G>? cmp, Tower<G> a, G b) {
+ bool ah = GLib.AtomicInt.get (ref a._height) == -1;
+ return ah ? -1 : cmp(a._data, b);
+ }
+
+ [CCode (array_length = false)]
+ public TowerNode<G>[] _nodes;
+ public G _data;
+ public int _height;
+ }
+
+ private struct TowerNode<G> {
+ public Tower<G> *_succ;
+ public Tower<G> *_backlink;
+ }
+
+ private struct TowerIter<G> {
+ [CCode (array_length = false)]
+ public Tower<G>? _iter[31 /*_MAX_HEIGHT*/];
+ }
+
+
+ private enum State {
+ NONE = 0,
+ MARKED = 1,
+ FLAGGED = 2
+ }
+}
+
diff --git a/gee/functions.vala b/gee/functions.vala
index a805bc8..00c7ca3 100644
--- a/gee/functions.vala
+++ b/gee/functions.vala
@@ -66,7 +66,7 @@ namespace Vala {
return ((Hashable<Hashable>) a).equal_to ((Hashable) b);
};
} else if (t.is_a (typeof (Comparable))) {
- return (a, b) => {
+ return (a, b) => {
if (a == b)
return true;
else if (a == null || b == null)
@@ -148,5 +148,38 @@ namespace Vala {
};
}
}
+
+ [CCode (simple_generics = true)]
+ internal class EqualDataFuncClosure<G> {
+ public EqualDataFuncClosure(owned EqualDataFunc<G> func) {
+ this.func = (owned)func;
+ }
+ public EqualDataFunc<G> func;
+ public EqualDataFunc<G> clone_func () {
+ return (a, b) => {return func (a, b);};
+ }
+ }
+
+ [CCode (simple_generics = true)]
+ internal class HashDataFuncClosure<G> {
+ public HashDataFuncClosure(owned HashDataFunc<G> func) {
+ this.func = (owned)func;
+ }
+ public HashDataFunc<G> func;
+ public HashDataFunc<G> clone_func () {
+ return (a) => {return func (a);};
+ }
+ }
+
+ [CCode (simple_generics = true)]
+ internal class CompareDataFuncClosure<G> {
+ public CompareDataFuncClosure(owned CompareDataFunc<G> func) {
+ this.func = (owned)func;
+ }
+ public CompareDataFunc<G> func;
+ public CompareDataFunc<G> clone_func () {
+ return (a, b) => {return func (a, b);};
+ }
+ }
}
}
diff --git a/gee/future.vala b/gee/future.vala
new file mode 100644
index 0000000..23cc175
--- /dev/null
+++ b/gee/future.vala
@@ -0,0 +1,261 @@
+/* future.vala
+ *
+ * Copyright (C) 2013 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;
+
+/**
+ * Future is a value which might not yet be computed - for example it is calculated
+ * in different thread or depends on I/O value.
+ *
+ * All methods can be called from many threads as part of interface.
+ *
+ * Note: Statement that call does not block does not mean that it is lock-free.
+ * Internally the implementation is allowed to take mutex but it should guarantee
+ * that it is not for a long time (including blocking on anything else, I/O calls
+ * or callbacks).
+ *
+ * @see Promise
+ * @see Lazy
+ * @see task
+ * @see async_task
+ * @since 0.11.0
+ */
+[GenericAccessors]
+public interface Vala.Future<G> : Object {
+ /**
+ * The value associated with Future. If value is not ready getting value
+ * will block until value is ready.
+ *
+ * Returned value is always the same and it is alive at least as long
+ * as the future.
+ */
+ [CCode (ordering = 7)]
+ public virtual new G? value {
+ get {
+ try {
+ return wait ();
+ } catch (FutureError ex) {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Checks if value is ready. If it is calls to {@link wait} and
+ * {@link wait_until} will not block and value is returned immidiatly.
+ */
+ [CCode (ordering = 8)]
+ public abstract bool ready {get;}
+
+ /**
+ * Checks the exception that have been set. I.e. if the computation
+ * has thrown the exception it should be set here and the {@link wait},
+ * {@link wait_until} and {@link wait_async} should throw
+ * {@link FutureError.EXCEPTION}.
+ *
+ * @since 0.11.5
+ */
+ [CCode (ordering = 9)]
+ public abstract GLib.Error? exception {get;}
+
+ /**
+ * Waits until the value is ready.
+ *
+ * @return The {@link value} associated with future
+ * @see ready
+ * @see wait_until
+ * @see wait_async
+ */
+ [CCode (ordering = 0)]
+ public abstract unowned G wait () throws Vala.FutureError;
+
+ /**
+ * Waits until the value is ready or deadline have passed.
+ *
+ * @param end_time The time when the wait should finish
+ * @param value The {@link value} associated with future if the wait was successful
+ * @return ``true`` if the value was ready within deadline or ``false`` otherwise
+ * @see ready
+ * @see wait
+ * @see wait_async
+ */
+ [CCode (ordering = 1)]
+ public abstract bool wait_until (int64 end_time, out unowned G? value = null) throws Vala.FutureError;
+
+ /**
+ * Reschedules the callback until the {@link value} is available.
+ *
+ * @return The {@link value} associated with future
+ * @see ready
+ * @see wait
+ * @see wait_until
+ */
+ [CCode (ordering = 2)]
+ public abstract async unowned G wait_async () throws Vala.FutureError;
+ public delegate A MapFunc<A, G> (G value);
+
+ /**
+ * Maps a future value to another value by a function and returns the
+ * another value in future.
+ *
+ * Note: As time taken by function might not contribute to
+ * {@link wait_until} and the implementation is allowed to compute
+ * value eagerly by {@link wait_async} it is recommended to use
+ * {@link task} and {@link flat_map} for longer computation.
+ *
+ * @param func Function applied to {@link value}
+ * @return Value returned by function
+ *
+ * @see flat_map
+ * @see light_map
+ */
+ [CCode (ordering = 3)]
+ public virtual Future<A> map<A> (owned MapFunc<A, G> func) {
+ Promise<A> promise = new Promise<A> ();
+ wait_async.begin ((obj, res) => {
+ try {
+ promise.set_value (func (wait_async.end (res)));
+ } catch (Error ex) {
+ promise.set_exception ((owned)ex);
+ }
+ });
+ return promise.future;
+ }
+
+ public delegate unowned A LightMapFunc<A, G> (G value);
+
+ /**
+ * Maps a future value to another value by a function and returns the
+ * another value in future.
+ *
+ * Note: The function may be reevaluated at any time and it might
+ * be called lazily. Therefore it is recommended for it to be
+ * idempotent. If the function needs to be called eagerly or have
+ * side-effects it is recommended to use {@link map}.
+ *
+ * Note: As time taken by function does not contribute to
+ * {@link wait_until} and the implementation is allowed to compute
+ * value eagerly by {@link wait_async} it is recommended to use
+ * {@link task} and {@link flat_map} for longer computation.
+ *
+ * @param func Function applied to {@link value}
+ * @return Value returned by function
+ *
+ * @see flat_map
+ * @see map
+ * @since 0.11.4
+ */
+ [CCode (ordering = 10, cname = "gee_future_light_map_fixed", vfunc_name = "light_map_fixed")]
+ public virtual Future<A> light_map<A> (owned LightMapFunc<A, G> func) {
+ return new LightMapFuture<A, G> (this, func);
+ }
+
+ [CCode (ordering = 4, cname = "gee_future_light_map", vfunc_name = "light_map")]
+ public virtual Future<A> light_map_broken<A> (LightMapFunc<A, G> func) {
+ return light_map<A> (func);
+ }
+
+ [CCode (scope = "async")]
+ public delegate C ZipFunc<A, B, C>(A a, B b);
+
+ /**
+ * Combines values of two futures using a function returning the combined
+ * value in future (call does not block).
+ *
+ * Note: As time taken by function does not contribute to
+ * {@link wait_until} and the implementation is allowed to compute
+ * value eagerly by {@link wait_async} it is recommended to return a
+ * future from {@link task} and use {@link flat_map} for longer computation.
+ *
+ * @param zip_func Function applied to values
+ * @param second Second parameter
+ * @return A combine value
+ * @since 0.11.4
+ */
+ [CCode (ordering = 5)]
+ public virtual Future<B> zip<A, B> (owned ZipFunc<G, A, B> zip_func, Future<A> second) {
+ Promise<B> promise = new Promise<B> ();
+ do_zip.begin<G, A, B> ((owned) zip_func, this, second, promise, (obj, res) => {do_zip.end<G,
A, B> (res);});
+ return promise.future;
+ }
+
+ private static async void do_zip<A, B, C> (owned ZipFunc<A, B, C> zip_func, Future<A> first,
Future<B> second, Promise<C> result) {
+ try {
+ A left = yield first.wait_async ();
+ B right = yield second.wait_async ();
+ result.set_value (zip_func (left, right));
+ } catch (Error ex) {
+ result.set_exception ((owned)ex);
+ }
+ }
+
+ public delegate Vala.Future<A> FlatMapFunc<A, G>(G value);
+
+ /**
+ * Maps a future value to another future value which is returned (call does not block).
+ *
+ * Note: As time taken by function does not contribute to
+ * {@link wait_until} and the implementation is allowed to compute
+ * value eagerly by {@link wait_async} it is recommended to put the
+ * larger computation inside the returned future for example by
+ * {@link task}
+ *
+ * @param func Function applied to {@link value}
+ * @return Value of a future returned by function
+ *
+ * @see map
+ */
+ [CCode (ordering = 6)]
+ public virtual Vala.Future<A> flat_map<A>(owned FlatMapFunc<A, G> func) {
+ Promise<A> promise = new Promise<A> ();
+ do_flat_map.begin<G, A> ((owned)func, this, promise, (obj, res) => {do_flat_map.end<G, A>
(res);});
+ return promise.future;
+ }
+
+ private static async void do_flat_map<A, B> (owned FlatMapFunc<B, A> func, Future<A> future,
Promise<B> promise) {
+ try {
+ A input = yield future.wait_async ();
+ B output = yield func (input).wait_async ();
+ promise.set_value ((owned)output);
+ } catch (Error ex) {
+ promise.set_exception ((owned)ex);
+ }
+ }
+
+ internal struct SourceFuncArrayElement {
+ public SourceFuncArrayElement (owned SourceFunc func) {
+ this.func = (owned)func;
+ }
+ public SourceFunc func;
+ }
+}
+
+public errordomain Vala.FutureError {
+ /**
+ * The promise have been abandon - this indicates an error in program.
+ */
+ ABANDON_PROMISE,
+ /**
+ * Exception field has been set.
+ */
+ EXCEPTION
+}
diff --git a/gee/hashable.vala b/gee/hashable.vala
index 9b806f1..f89a035 100644
--- a/gee/hashable.vala
+++ b/gee/hashable.vala
@@ -29,15 +29,30 @@
public interface Vala.Hashable<G> : Object {
/**
* Computes hash for an objects. Two hashes of equal objects have to be
- * equal. Hash have to not change during lifetime of object.
+ * equal.
+ *
+ * Note: Hash //must not// change during lifetime of an object.
*
* @return hash of an object
*/
public abstract uint hash ();
/**
- * Compares this object with the specifed object.
+ * Compares this object with the specifed object. This defines the
+ * equivalence relation between them.
+ *
+ * In other words:
+ *
+ * * It must be reflexive: for all objects `a` it holds that
+ * `a.equal_to(a)`.
+ * * It must be symmetric: for all objects `a` and `b` if
+ * `a.equal_to(b)` then `b.equal_to(a)`.
+ * * It must be transitive: if `a.equal_to(b)` and `b.equal_to(c)` then
+ * `a.equal_to(c)`.
+ *
+ * Note: Relationship //must not// change during lifetime of an object.
*
+ * @param object Object this objest is compared with
* @return true if objects are equal
*/
public abstract bool equal_to (G object);
diff --git a/gee/hashmap.vala b/gee/hashmap.vala
index 158e787..ca6767a 100644
--- a/gee/hashmap.vala
+++ b/gee/hashmap.vala
@@ -3,6 +3,7 @@
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright (C) 1997-2000 GLib Team and others
* Copyright (C) 2007-2009 Jürg Billeter
+ * Copyright (C) 2009-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -97,23 +98,42 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
* The keys' hash function.
*/
[CCode (notify = false)]
- public HashDataFunc<K> key_hash_func { private set; get; }
+ public HashDataFunc<K> key_hash_func {
+ private set {}
+ get {
+ return _key_hash_func.func;
+ }
+ }
/**
* The keys' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<K> key_equal_func { private set; get; }
+ public EqualDataFunc<K> key_equal_func {
+ private set {}
+ get {
+ return _key_equal_func.func;
+ }
+ }
/**
* The values' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<V> value_equal_func { private set; get; }
+ public EqualDataFunc<V> value_equal_func {
+ private set {}
+ get {
+ return _value_equal_func.func;
+ }
+ }
private int _array_size;
private int _nnodes;
private Node<K,V>[] _nodes;
+ private Functions.HashDataFuncClosure<K> _key_hash_func;
+ private Functions.EqualDataFuncClosure<K> _key_equal_func;
+ private Functions.EqualDataFuncClosure<V> _value_equal_func;
+
private weak Set<K> _keys;
private weak Collection<V> _values;
@@ -145,9 +165,18 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
if (value_equal_func == null) {
value_equal_func = Functions.get_equal_func_for (typeof (V));
}
- this.key_hash_func = key_hash_func;
- this.key_equal_func = key_equal_func;
- this.value_equal_func = value_equal_func;
+ _key_hash_func = new Functions.HashDataFuncClosure<K> ((owned)key_hash_func);
+ _key_equal_func = new Functions.EqualDataFuncClosure<K> ((owned)key_equal_func);
+ _value_equal_func = new Functions.EqualDataFuncClosure<V> ((owned)value_equal_func);
+
+ _array_size = MIN_SIZE;
+ _nodes = new Node<K,V>[_array_size];
+ }
+
+ internal HashMap.with_closures (owned Functions.HashDataFuncClosure<K> key_hash_func, owned
Functions.EqualDataFuncClosure<K> key_equal_func, owned Functions.EqualDataFuncClosure<V> value_equal_func) {
+ _key_hash_func = key_hash_func;
+ _key_equal_func = key_equal_func;
+ _value_equal_func = value_equal_func;
_array_size = MIN_SIZE;
_nodes = new Node<K,V>[_array_size];
@@ -241,6 +270,14 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
return new MapIterator<K,V> (this);
}
+ internal Functions.HashDataFuncClosure<K> get_key_hash_func_closure () {
+ return _key_hash_func;
+ }
+
+ internal Functions.EqualDataFuncClosure<K> get_key_equal_func_closure () {
+ return _key_equal_func;
+ }
+
private inline bool unset_helper (K key, out V? value = null) {
Node<K,V>** node = lookup_node (key);
if (*node != null) {
@@ -304,6 +341,12 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
key_hash = hash;
entry = null;
}
+
+ ~Node () {
+ if (entry != null) {
+ entry.remove_weak_pointer ((void**) (&entry));
+ }
+ }
}
private class Entry<K,V> : Map.Entry<K,V> {
@@ -367,19 +410,6 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
public override bool contains (K key) {
return _map.has_key (key);
}
-
- public bool add_all (Collection<K> collection) {
- assert_not_reached ();
- }
-
- public bool remove_all (Collection<K> collection) {
- assert_not_reached ();
- }
-
- public bool retain_all (Collection<K> collection) {
- assert_not_reached ();
- }
-
}
private class ValueCollection<K,V> : AbstractCollection<V> {
@@ -422,18 +452,6 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
return false;
}
-
- public bool add_all (Collection<V> collection) {
- assert_not_reached ();
- }
-
- public bool remove_all (Collection<V> collection) {
- assert_not_reached ();
- }
-
- public bool retain_all (Collection<V> collection) {
- assert_not_reached ();
- }
}
private class EntrySet<K,V> : AbstractSet<Map.Entry<K, V>> {
@@ -470,34 +488,22 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
public override bool contains (Map.Entry<K, V> entry) {
return _map.has (entry.key, entry.value);
}
-
- public bool add_all (Collection<Map.Entry<K, V>> entries) {
- assert_not_reached ();
- }
-
- public bool remove_all (Collection<Map.Entry<K, V>> entries) {
- assert_not_reached ();
- }
-
- public bool retain_all (Collection<Map.Entry<K, V>> entries) {
- assert_not_reached ();
- }
}
private abstract class NodeIterator<K,V> : Object {
- protected HashMap<K,V> _map;
- protected int _index = -1;
- protected weak Node<K,V> _node;
- protected weak Node<K,V> _next;
-
- // concurrent modification protection
- protected int _stamp;
-
public NodeIterator (HashMap map) {
_map = map;
_stamp = _map._stamp;
}
+ public NodeIterator.from_iterator (NodeIterator<K,V> iter) {
+ _map = iter._map;
+ _index = iter._index;
+ _node = iter._node;
+ _next = iter._next;
+ _stamp = iter._stamp;
+ }
+
public bool next () {
assert (_stamp == _map._stamp);
if (!has_next ()) {
@@ -522,18 +528,24 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
return (_next != null);
}
-
+
public virtual bool read_only {
get {
return true;
}
}
-
+
public bool valid {
get {
return _node != null;
}
}
+
+ protected HashMap<K,V> _map;
+ protected int _index = -1;
+ protected weak Node<K,V> _node;
+ protected weak Node<K,V> _next;
+ protected int _stamp;
}
private class KeyIterator<K,V> : NodeIterator<K,V>, Traversable<K>, Iterator<K> {
@@ -541,6 +553,10 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
base (map);
}
+ public KeyIterator.from_iterator (KeyIterator<K,V> iter) {
+ base.from_iterator (iter);
+ }
+
public new K get () {
assert (_stamp == _map._stamp);
assert (_node != null);
@@ -575,6 +591,19 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
} while(true);
}
+
+ public Vala.Iterator<K>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<K>[0];
+ } else {
+ Vala.Iterator<K>[] result = new Vala.Iterator<K>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new KeyIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class MapIterator<K,V> : NodeIterator<K,V>, Vala.MapIterator<K,V> {
@@ -609,13 +638,13 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
_map.set (_node.key, value);
_stamp = _map._stamp;
}
-
+
public bool mutable {
get {
return true;
}
}
-
+
public override bool read_only {
get {
return false;
@@ -624,10 +653,14 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
private class ValueIterator<K,V> : NodeIterator<K,V>, Traversable<V>, Iterator<V> {
- public ValueIterator (HashMap map) {
+ public ValueIterator (HashMap<K,V> map) {
base (map);
}
+ public ValueIterator.from_iterator (ValueIterator<K,V> iter) {
+ base.from_iterator (iter);
+ }
+
public new V get () {
assert (_stamp == _map._stamp);
assert (_node != null);
@@ -662,13 +695,30 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
} while(true);
}
+
+ public Vala.Iterator<K>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<K>[0];
+ } else {
+ Vala.Iterator<K>[] result = new Vala.Iterator<K>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new ValueIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class EntryIterator<K,V> : NodeIterator<K,V>, Traversable<Map.Entry<K,V>>,
Iterator<Map.Entry<K,V>> {
- public EntryIterator (HashMap map) {
+ public EntryIterator (HashMap<K,V> map) {
base (map);
}
+ public EntryIterator.from_iterator (EntryIterator<K,V> iter) {
+ base.from_iterator (iter);
+ }
+
public new Map.Entry<K,V> get () {
assert (_stamp == _map._stamp);
assert (_node != null);
@@ -703,6 +753,19 @@ public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
}
} while(true);
}
+
+ public Iterator<Map.Entry<K,V>>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<Map.Entry<K,V>>[0];
+ } else {
+ Iterator<Map.Entry<K,V>>[] result = new Iterator<Map.Entry<K,V>>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new EntryIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
}
diff --git a/gee/hashmultimap.vala b/gee/hashmultimap.vala
index ca57fb8..46764ef 100644
--- a/gee/hashmultimap.vala
+++ b/gee/hashmultimap.vala
@@ -33,10 +33,20 @@ public class Vala.HashMultiMap<K,V> : AbstractMultiMap<K,V> {
}
[CCode (notify = false)]
- public HashDataFunc<V> value_hash_func { private set; get; }
+ public HashDataFunc<V> value_hash_func {
+ private set {}
+ get {
+ return _value_hash_func.func;
+ }
+ }
[CCode (notify = false)]
- public EqualDataFunc<V> value_equal_func { private set; get; }
+ public EqualDataFunc<V> value_equal_func {
+ private set {}
+ get {
+ return _value_equal_func.func;
+ }
+ }
/**
* Constructs a new, empty hash multimap.
@@ -51,26 +61,29 @@ public class Vala.HashMultiMap<K,V> : AbstractMultiMap<K,V> {
*/
public HashMultiMap (owned HashDataFunc<K>? key_hash_func = null, owned EqualDataFunc<K>?
key_equal_func = null,
owned HashDataFunc<V>? value_hash_func = null, owned EqualDataFunc<V>?
value_equal_func = null) {
- base (new HashMap<K, Set<V>> (key_hash_func, key_equal_func, Functions.get_equal_func_for
(typeof (Set))));
+ base (new HashMap<K, Set<V>> ((owned)key_hash_func, (owned)key_equal_func,
Functions.get_equal_func_for (typeof (Set))));
if (value_hash_func == null) {
value_hash_func = Functions.get_hash_func_for (typeof (V));
}
if (value_equal_func == null) {
value_equal_func = Functions.get_equal_func_for (typeof (V));
}
- this.value_hash_func = value_hash_func;
- this.value_equal_func = value_equal_func;
+ _value_hash_func = new Functions.HashDataFuncClosure<V> ((owned)value_hash_func);
+ _value_equal_func = new Functions.EqualDataFuncClosure<V> ((owned)value_equal_func);
}
protected override Collection<V> create_value_storage () {
- return new HashSet<V> (_value_hash_func, _value_equal_func);
+ return new HashSet<V>.with_closures (_value_hash_func, _value_equal_func);
}
protected override MultiSet<K> create_multi_key_set () {
- return new HashMultiSet<K> (key_hash_func, key_equal_func);
+ return new HashMultiSet<K>.with_closures (((HashMap<K, Set<V>>)
_storage_map).get_key_hash_func_closure (), ((HashMap<K, Set<V>>) _storage_map).get_key_equal_func_closure
());
}
- protected override EqualDataFunc get_value_equal_func () {
- return _value_equal_func;
+ protected override EqualDataFunc<V> get_value_equal_func () {
+ return _value_equal_func.clone_func ();
}
+
+ private Functions.HashDataFuncClosure<V> _value_hash_func;
+ private Functions.EqualDataFuncClosure<V> _value_equal_func;
}
diff --git a/gee/hashmultiset.vala b/gee/hashmultiset.vala
index 78b8500..34d9ae0 100644
--- a/gee/hashmultiset.vala
+++ b/gee/hashmultiset.vala
@@ -41,7 +41,35 @@ public class Vala.HashMultiSet<G> : AbstractMultiSet<G> {
* @param hash_func an optional element hash function
* @param equal_func an optional element equality testing function
*/
- public HashMultiSet (HashDataFunc<G>? hash_func = null, EqualDataFunc<G>? equal_func = null) {
+ [CCode (cname = "gee_hash_multi_set_new_fixed")]
+ public HashMultiSet (owned HashDataFunc<G>? hash_func = null, owned EqualDataFunc<G>? equal_func =
null) {
+ base (new HashMap<G, int> ((owned)hash_func, (owned)equal_func));
+ }
+
+ /**
+ * Constructs a new, empty hash multi set.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * Note: this function is only for backward ABI compatibility.
+ * It contains memory leak and SHOULD NOT BE USED.
+ *
+ *
+ * @param hash_func an optional element hash function
+ * @param equal_func an optional element equality testing function
+ */
+#if VALA_0_32
+ [Version (deprecated = true, deprecated_since = "0.13.3", replacement =
"gee_hash_multi_set_new_fixed")]
+#else
+ [Deprecated (since = "0.13.3", replacement = "gee_hash_multi_set_new_fixed")]
+#endif
+ [CCode (cname = "gee_hash_multi_set_new")]
+ public HashMultiSet.broken (HashDataFunc<G>? hash_func = null, EqualDataFunc<G>? equal_func = null) {
base (new HashMap<G, int> (hash_func, equal_func));
}
+
+ internal HashMultiSet.with_closures (owned Functions.HashDataFuncClosure<G> hash_func, owned
Functions.EqualDataFuncClosure<G> equal_func) {
+ base (new HashMap<G, int>.with_closures ((owned)hash_func, (owned)equal_func, new
Functions.EqualDataFuncClosure<int> (Functions.get_equal_func_for (typeof (int)))));
+ }
}
diff --git a/gee/hashset.vala b/gee/hashset.vala
index e4821d7..67bdd5a 100644
--- a/gee/hashset.vala
+++ b/gee/hashset.vala
@@ -3,6 +3,7 @@
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
* Copyright (C) 1997-2000 GLib Team and others
* Copyright (C) 2007-2009 Jürg Billeter
+ * Copyright (C) 2009-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +26,41 @@
using GLib;
namespace Vala {
+ /**
+ * A function producing a hash for an object. Two hashes of equal
+ * objects (as specified by corresponding {@link EqualDataFunc}) have to
+ * be equal.
+ *
+ * Note: Hash for a given object //must not// change during the lifetime
+ * of delegate.
+ *
+ * @param v Hashed value
+ * @return Hash for given value
+ *
+ * @see Hashable
+ */
public delegate uint HashDataFunc<T> (T v);
+ /**
+ * A function comparing two object defining equivalence relationship.
+ *
+ * In other words if `equal_to` is `EqualDataFunc` then:
+ *
+ * * It must be reflexive: for all objects `a` it holds that
+ * `equal_to(a, a)`.
+ * * It must be symmetric: for all objects `a` and `b` if
+ * `equal_to(a, b)` then `equal_to(b, a)`.
+ * * It must be transitive: if `equal_to(a, b)` and `equal_to(b, c)`
+ * then `equal_to(a, c)`
+ *
+ * Note: The relationship //must not// change during lifetime of the
+ * delegate.
+ *
+ * @param a First value
+ * @param b Second value
+ * @return Whether values are equal
+ *
+ * @see Hashable
+ */
public delegate bool EqualDataFunc<T> (T a, T b);
}
@@ -57,17 +92,29 @@ public class Vala.HashSet<G> : AbstractSet<G> {
* The elements' hash function.
*/
[CCode (notify = false)]
- public HashDataFunc<G> hash_func { private set; get; }
+ public HashDataFunc<G> hash_func {
+ private set {}
+ get {
+ return _hash_func.func;
+ }
+ }
/**
* The elements' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<G> equal_func { private set; get; }
+ public EqualDataFunc<G> equal_func {
+ private set {}
+ get {
+ return _equal_func.func;
+ }
+ }
private int _array_size;
private int _nnodes;
private Node<G>[] _nodes;
+ private Functions.HashDataFuncClosure<G> _hash_func;
+ private Functions.EqualDataFuncClosure<G> _equal_func;
// concurrent modification protection
private int _stamp = 0;
@@ -91,8 +138,15 @@ public class Vala.HashSet<G> : AbstractSet<G> {
if (equal_func == null) {
equal_func = Functions.get_equal_func_for (typeof (G));
}
- this.hash_func = hash_func;
- this.equal_func = equal_func;
+ _hash_func = new Functions.HashDataFuncClosure<G> ((owned)hash_func);
+ _equal_func = new Functions.EqualDataFuncClosure<G> ((owned)equal_func);
+ _array_size = MIN_SIZE;
+ _nodes = new Node<G>[_array_size];
+ }
+
+ internal HashSet.with_closures (owned Functions.HashDataFuncClosure<G> hash_func, owned
Functions.EqualDataFuncClosure<G> equal_func) {
+ _hash_func = hash_func;
+ _equal_func = equal_func;
_array_size = MIN_SIZE;
_nodes = new Node<G>[_array_size];
}
@@ -165,6 +219,20 @@ public class Vala.HashSet<G> : AbstractSet<G> {
resize ();
}
+ /**
+ * {@inheritDoc}
+ */
+ public override bool foreach (ForallFunc<G> f) {
+ for (int i = 0; i < _array_size; i++) {
+ for (unowned Node<G>? current = _nodes[i]; current != null; current = current.next) {
+ if (!f (current.key)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
private inline bool remove_helper (G key) {
Node<G>** node = lookup_node (key);
if (*node != null) {
@@ -223,19 +291,18 @@ public class Vala.HashSet<G> : AbstractSet<G> {
}
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
- private HashSet<G> _set;
- private int _index = -1;
- private weak Node<G> _node;
- private weak Node<G> _next;
-
- // concurrent modification protection
- private int _stamp = 0;
-
- public Iterator (HashSet set) {
+ public Iterator (HashSet<G> set) {
_set = set;
_stamp = _set._stamp;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _set = iter._set;
+ _index = iter._index;
+ _node = iter._node;
+ _next = iter._next;
+ }
+
public bool next () {
assert (_stamp == _set._stamp);
if (!has_next ()) {
@@ -326,6 +393,25 @@ public class Vala.HashSet<G> : AbstractSet<G> {
_next = null;
return true;
}
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[0] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected HashSet<G> _set;
+ protected int _index = -1;
+ protected weak Node<G> _node;
+ protected weak Node<G> _next;
+ protected int _stamp = 0;
}
}
diff --git a/gee/hazardpointer.vala b/gee/hazardpointer.vala
index a26fbeb..1fac2b5 100644
--- a/gee/hazardpointer.vala
+++ b/gee/hazardpointer.vala
@@ -165,8 +165,10 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
public static void set_pointer<G> (G **aptr, owned G? new_ptr, size_t mask = 0, size_t new_mask = 0) {
HazardPointer<G>? ptr = exchange_hazard_pointer<G> (aptr, new_ptr, mask, new_mask, null);
if (ptr != null) {
- DestroyNotify<G> notify = get_destroy_notify<G> ();
- ptr.release ((owned)notify);
+ DestroyNotify? notify = Utils.Free.get_destroy_notify<G> ();
+ if (notify != null) {
+ ptr.release ((owned)notify);
+ }
}
}
@@ -202,8 +204,8 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
void *old_rptr = (void *)((size_t)(old_ptr) | (mask & old_mask));
bool success = AtomicPointer.compare_and_exchange((void **)aptr, old_rptr, new_rptr);
if (success) {
- DestroyNotify<G> notify = get_destroy_notify<G> ();
- if (old_ptr != null) {
+ DestroyNotify? notify = Utils.Free.get_destroy_notify<G> ();
+ if (old_ptr != null && notify != null) {
Context.get_current_context ()->release_ptr (old_ptr, (owned)notify);
}
} else if (new_ptr != null) {
@@ -400,38 +402,37 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
* @param to_free List containing elements to free.
* @return Non-empty list of not freed elements or ``null`` if all elements have been
disposed.
*/
- internal ArrayList<FreeNode *>? perform (owned ArrayList<FreeNode *> to_free) {
+ internal bool perform (ref ArrayList<FreeNode *> to_free) {
switch (this.to_concrete ()) {
case TRY_FREE:
- return try_free (to_free) ? (owned) to_free : null;
+ return try_free (to_free);
case FREE:
while (try_free (to_free)) {
Thread.yield ();
}
- return null;
+ break;
case TRY_RELEASE:
ReleasePolicy.ensure_start ();
if (_queue_mutex.trylock ()) {
_queue.offer ((owned) to_free);
_queue_mutex.unlock ();
- return null;
+ return true;
} else {
- return (owned) to_free;
+ return false;
}
case RELEASE:
ReleasePolicy.ensure_start ();
_queue_mutex.lock ();
_queue.offer ((owned) to_free);
_queue_mutex.unlock ();
- return null;
+ return true;
default:
assert_not_reached ();
}
+ return false;
}
}
- public delegate void DestroyNotify (void *ptr);
-
/**
* Release policy determines what happens with object freed by Policy.TRY_RELEASE
* and Policy.RELEASE.
@@ -451,20 +452,26 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
private static void start (ReleasePolicy self) { // FIXME: Make it non-static [bug 659778]
switch (self) {
case HELPER_THREAD:
- try {
- new Thread<bool> ("<<libgee hazard pointer>>", () => {
- while (true) {
- Thread.yield ();
- attempt_free ();
+ new Thread<bool> ("<<libgee hazard pointer>>", () => {
+ Context ctx = new Context (Policy.TRY_FREE);
+ while (true) {
+ Thread.yield ();
+ pull_from_queue (ctx._to_free, ctx._to_free.is_empty);
+ ctx.try_free ();
+ if (ctx._to_free.is_empty) {
+ GLib.Thread.usleep (100000);
}
- });
- } catch (ThreadError error) {
- assert_not_reached ();
- }
+ }
+ });
break;
case MAIN_LOOP:
+ _global_to_free = new ArrayList<FreeNode *> ();
Idle.add (() => {
- attempt_free ();
+ Context ctx = new Context (Policy.TRY_FREE);
+ swap (ref _global_to_free, ref ctx._to_free);
+ pull_from_queue (ctx._to_free, false);
+ ctx.try_free ();
+ swap (ref _global_to_free, ref ctx._to_free);
return true;
}, Priority.LOW);
break;
@@ -473,6 +480,12 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
}
}
+ private static void swap<T>(ref T a, ref T b) {
+ T tmp = (owned)a;
+ a = (owned)b;
+ b = (owned)tmp;
+ }
+
/**
* Ensures that helper methods are started.
*/
@@ -485,21 +498,26 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
if ((policy & (1 << (sizeof(int) * 8 - 1))) == 0) {
_queue = new LinkedList<ArrayList<FreeNode *>> ();
// Hack to not lie about successfull setting policy
- policy = AtomicInt.exchange_and_add (ref release_policy, (int)(1 <<
(sizeof(int) * 8 - 1)));
+ policy = AtomicInt.add (ref release_policy, (int)(1 << (sizeof(int) *
8 - 1)));
start ((ReleasePolicy) policy);
}
_queue_mutex.unlock ();
}
}
- private static inline void attempt_free () {
- if (_queue_mutex.trylock ()) {
+ private static inline void pull_from_queue (Collection<FreeNode *> to_free, bool do_lock) {
+ bool locked = do_lock;
+ if (do_lock) {
+ _queue_mutex.lock ();
+ } else {
+ locked = _queue_mutex.trylock ();
+ }
+ if (locked) {
Collection<ArrayList<FreeNode *>> temp = new ArrayList<ArrayList<FreeNode *>>
();
_queue.drain (temp);
_queue_mutex.unlock ();
- temp.foreach ((x) => {_global_to_free.add_all (x); return true;});
+ temp.foreach ((x) => {to_free.add_all (x); return true;});
}
- try_free (_global_to_free);
}
}
@@ -547,15 +565,12 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
int size = _to_free.size;
bool clean_parent = false;
if (size > 0) {
- ArrayList<FreeNode *>? remaining;
- if (_parent == null || size >= THRESHOLD)
- remaining = _policy.perform ((owned) _to_free);
- else
- remaining = (owned) _to_free;
- if (remaining != null) {
- assert (_parent != null);
- _parent->_to_free.add_all (remaining);
- clean_parent = true;
+ if (_parent == null || size >= THRESHOLD) {
+ if (!_policy.perform (ref _to_free)) {
+ assert (_parent != null && _to_free != null);
+ _parent->_to_free.add_all (_to_free);
+ clean_parent = true;
+ }
}
}
#if DEBUG
@@ -621,10 +636,6 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
return _current_context.get ();
}
- private inline bool _should_free () {
- return (_parent == null && _to_free.size > 0) || _to_free.size >= THRESHOLD;
- }
-
internal Context *_parent;
internal ArrayList<FreeNode *> _to_free;
internal Policy? _policy;
@@ -706,14 +717,6 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
internal static ArrayList<FreeNode *> _global_to_free;
- internal static DestroyNotify get_destroy_notify<G> () {
- return (ptr) => {
- G *gptr = ptr;
- G obj = (owned)gptr;
- obj = null;
- };
- }
-
[Compact]
internal class FreeNode {
public void *pointer;
@@ -729,7 +732,7 @@ public class Vala.HazardPointer<G> { // FIXME: Make it a struct
AtomicPointer.set (&_hazard, null);
AtomicInt.set (ref _active, 1);
}
-
+
inline ~Node () {
delete _next;
}
diff --git a/gee/iterator.vala b/gee/iterator.vala
index 8064e96..79d7824 100644
--- a/gee/iterator.vala
+++ b/gee/iterator.vala
@@ -32,8 +32,13 @@
* item has been removed, until the next call to {@link next}.
*
* Please note that when the iterator is out of track, neither {@link get} nor
- * {@link remove} are defined and both will fail. After the next call to
+ * {@link remove} are defined and both might fail. After the next call to
* {@link next}, they will be defined again.
+ *
+ * Please also note that, unless specified otherwise, iterators before iteration
+ * started should behave as if after deletion of the first element. Whenever
+ * documentation states about the iterator 'out of track', 'invalid' or
+ * 'in-between elements' this refers to the same concept.
*/
public interface Vala.Iterator<G> : Object, Traversable<G> {
/**
diff --git a/gee/lazy.vala b/gee/lazy.vala
index ed1ac3c..8dc5720 100644
--- a/gee/lazy.vala
+++ b/gee/lazy.vala
@@ -26,6 +26,8 @@ namespace Vala {
/**
* Represents a lazy value. I.e. value that is computed on demand.
+ *
+ * This class is not thread-safe.
*/
public class Vala.Lazy<G> {
public Lazy (owned LazyFunc<G> func) {
@@ -55,6 +57,113 @@ public class Vala.Lazy<G> {
}
}
+ /**
+ * Provides a future for a lazy value.
+ *
+ * Note: The future can be requested only once and all access must be
+ * done through it.
+ */
+ public Vala.Future<G>? future {
+ owned get {
+ return new Future<G> (this);
+ }
+ }
+
private LazyFunc<G>? _func;
private G? _value;
+
+ private class Future<G> : Object, Vala.Future<G> {
+ public Future (Lazy<G> lazy) {
+ _lazy = lazy;
+ }
+
+ public bool ready {
+ get {
+ _mutex.lock ();
+ bool result = _lazy._func == null;
+ _mutex.unlock ();
+ return result;
+ }
+ }
+
+ public GLib.Error? exception {get {return null;}}
+
+ public unowned G wait () throws Vala.FutureError {
+ _mutex.lock ();
+ if (_lazy._func != null) {
+ if (_state == State.EVAL) {
+ _eval.wait (_mutex);
+ _mutex.unlock ();
+ } else {
+ do_eval ();
+ }
+ } else {
+ _mutex.unlock ();
+ }
+ return _lazy._value;
+ }
+
+ public unowned bool wait_until (int64 end_time, out unowned G? value = null) throws
Vala.FutureError {
+ _mutex.lock ();
+ if (_lazy._func != null) {
+ if (_state == State.EVAL) {
+ bool res = _eval.wait_until (_mutex, end_time);
+ _mutex.unlock ();
+ if (!res) {
+ value = null;
+ return false;
+ }
+ } else {
+ do_eval ();
+ }
+ } else {
+ _mutex.unlock ();
+ }
+ value = _lazy._value;
+ return true;
+ }
+
+ public async unowned G wait_async () throws Vala.FutureError {
+ _mutex.lock ();
+ if (_lazy._func != null) {
+ if (_state == State.EVAL) {
+ _when_done += SourceFuncArrayElement(wait_async.callback);
+ yield Vala.Utils.Async.yield_and_unlock (_mutex);
+ } else {
+ do_eval ();
+ }
+ } else {
+ _mutex.unlock ();
+ }
+ return _lazy.value;
+ }
+
+ private void do_eval () {
+ _state = State.EVAL;
+ _mutex.unlock ();
+
+ _lazy._value = _lazy._func ();
+
+ _mutex.lock ();
+ _lazy._func = null;
+ _state = State.UNLOCK;
+ _eval.broadcast ();
+ _mutex.unlock ();
+
+ Vala.Future.SourceFuncArrayElement<G>[] when_done = (owned)_when_done;
+ for (int i = 0; i < when_done.length; i++) {
+ when_done[i].func ();
+ }
+ }
+
+ private Mutex _mutex = Mutex ();
+ private Cond _eval = Cond ();
+ private Lazy<G> _lazy;
+ private State _state = State.UNLOCK;
+ private Vala.Future.SourceFuncArrayElement<G>[]? _when_done = new
Vala.Future.SourceFuncArrayElement<G>[0];
+ private enum State {
+ UNLOCK,
+ EVAL
+ }
+ }
}
diff --git a/gee/lightmapfuture.vala b/gee/lightmapfuture.vala
new file mode 100644
index 0000000..3bbcad2
--- /dev/null
+++ b/gee/lightmapfuture.vala
@@ -0,0 +1,62 @@
+/* lightmapfuture.vala
+ *
+ * Copyright (C) 2013 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>
+ */
+internal class Vala.LightMapFuture<A, G> : Object, Future<A> {
+ public LightMapFuture (Future<G> base_future, owned Future.LightMapFunc<A, G> func) {
+ _base = base_future;
+ _func = (owned)func;
+ }
+
+ public bool ready {
+ get {
+ return _base.ready;
+ }
+ }
+
+ public GLib.Error exception {
+ get {
+ return _base.exception;
+ }
+ }
+
+ public unowned A wait () throws Vala.FutureError {
+ return _func (_base.wait ());
+ }
+
+ public bool wait_until (int64 end_time, out unowned A? value = null) throws Vala.FutureError {
+ unowned G arg;
+ bool result;
+ value = null;
+ if ((result = _base.wait_until (end_time, out arg))) {
+ value = _func (arg);
+ }
+ return result;
+ }
+
+ public async unowned A wait_async () throws Vala.FutureError {
+ unowned G arg = yield _base.wait_async ();
+ return _func (arg);
+ }
+
+ private Future<G> _base;
+ private Future.LightMapFunc<A, G> _func;
+}
+
diff --git a/gee/linkedlist.vala b/gee/linkedlist.vala
index 16d82da..742e88b 100644
--- a/gee/linkedlist.vala
+++ b/gee/linkedlist.vala
@@ -4,6 +4,7 @@
* Copyright (C) 2005 David Waite
* Copyright (C) 2007-2008 Jürg Billeter
* Copyright (C) 2009 Mark Lee, Didier Villevalois
+ * Copyright (C) 2010-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,6 +25,8 @@
* Didier 'Ptitjes Villevalois <ptitjes free fr>
*/
+using Vala.Utils.Assume;
+
/**
* Doubly-linked list implementation of the {@link List} interface.
*
@@ -37,12 +40,18 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
private int _stamp = 0;
private Node<G>? _head = null;
private weak Node<G>? _tail = null;
+ private Functions.EqualDataFuncClosure<G> _equal_func;
/**
* The elements' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<G> equal_func { private set; get; }
+ public EqualDataFunc<G> equal_func {
+ private set {}
+ get {
+ return _equal_func.func;
+ }
+ }
/**
* Constructs a new, empty linked list.
@@ -56,7 +65,11 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
if (equal_func == null) {
equal_func = Functions.get_equal_func_for (typeof (G));
}
- this.equal_func = equal_func;
+ _equal_func = new Functions.EqualDataFuncClosure<G> ((owned)equal_func);
+ }
+
+ private LinkedList.with_closures (owned Functions.EqualDataFuncClosure<G> equal_func) {
+ _equal_func = equal_func;
}
~LinkedList () {
@@ -173,7 +186,9 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
assert (index < this._size);
unowned Node<G>? n = this._get_node_at (index);
+#if !DISABLE_INTERNAL_ASSERTS
assert (n != null);
+#endif
return n.data;
}
@@ -243,7 +258,9 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
assert (index < this._size);
unowned Node<G>? n = this._get_node_at (index);
+#if !DISABLE_INTERNAL_ASSERTS
assert (n != null);
+#endif
G element = n.data;
this._remove_node (n);
return element;
@@ -257,7 +274,7 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
return_val_if_fail (start >= 0, null);
return_val_if_fail (stop <= this._size, null);
- List<G> slice = new LinkedList<G> (this.equal_func);
+ List<G> slice = new LinkedList<G>.with_closures (_equal_func);
weak Node<G> n = this._get_node_at (start);
for (int i = start; i < stop; i++) {
slice.add (n.data);
@@ -430,188 +447,229 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
}
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G>, BidirIterator<G>,
ListIterator<G>, BidirListIterator<G> {
- private bool started = false;
- private bool removed = false;
- private unowned Node<G>? position;
- private int _stamp;
- private LinkedList<G> _list;
- private int _index;
-
public Iterator (LinkedList<G> list) {
this._list = list;
- this.position = null;
+ this._position = null;
this._index = -1;
this._stamp = list._stamp;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _removed = iter._removed;
+ _position = iter._position;
+ _stamp = iter._stamp;
+ _list = iter._list;
+ _index = iter._index;
+ }
+
public bool next () {
assert (this._stamp == this._list._stamp);
- if (this.removed) {
- if (this.position != null) {
- this.removed = false;
+ if (GLib.unlikely (_position == null)) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!_removed);
+#else
+ assume (!_removed);
+#endif
+ if (_list._head != null) {
+ _position = _list._head;
+ _index = 0;
return true;
} else {
return false;
}
- } else if (!this.started) {
- if (this._list._head != null) {
- this.started = true;
- this.position = this._list._head;
- this._index++;
- return true;
- } else {
- return false;
- }
- } else if (this.position != null) {
- if (this.position.next != null) {
- this.position = this.position.next;
- this._index++;
+ } else {
+ if (_position.next != null) {
+ _position = _position.next;
+ _index++;
+ _removed = false;
return true;
} else {
return false;
}
}
- return false;
}
public bool has_next () {
- assert (this._stamp == this._list._stamp);
+ assert (_stamp == _list._stamp);
- if (this.removed) {
- return this.position != null;
- } else if (!this.started) {
- return this._list._head != null;
- } else if (this.position != null) {
- return this.position.next != null;
+ if (GLib.unlikely (_position == null)) {
+ return _list._head != null;
+ } else {
+ return _position.next != null;
}
- return false;
}
public bool first () {
- assert (this._stamp == this._list._stamp);
- if (this._list.size == 0) {
+ assert (_stamp == _list._stamp);
+
+ if (_list.size == 0) {
return false;
}
- this.position = this._list._head;
- this.started = true;
- this._index = 0;
- this.removed = false;
- return this.position != null;
+ _position = _list._head;
+ _index = 0;
+ _removed = false;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_position != null);
+#endif
+ return true;
}
public new G get () {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
+ assert (_position != null && !_removed);
- return this.position.data;
+ return _position.data;
}
public void remove () {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
+ assert (_position != null && !_removed);
- unowned Node<G>? new_position = this.position.next;
- if (new_position == null) {
- started = false;
+ unowned Node<G>? new_position = _position.prev;
+ _list._remove_node (_position);
+ _position = new_position;
+ if (_position != null) {
+ _removed = true;
}
- _list._remove_node (this.position);
- this.position = new_position;
- this.removed = true;
- this._stamp = this._list._stamp;
+ _index--;
+ _stamp = _list._stamp;
}
public bool previous () {
- assert (this._stamp == this._list._stamp);
+ assert (_stamp == _list._stamp);
- if (!this.started) {
- this.position = null;
+ if (GLib.likely (_position != null)) {
+ if (GLib.unlikely (_removed)) {
+ _removed = false;
+ return true;
+ } else if (GLib.likely(_position.prev != null)) {
+ _position = _position.prev;
+ _index--;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
return false;
- } else if (this.position != null && this.position.prev != null) {
- this.position = this.position.prev;
- this._index--;
- return true;
}
- return false;
}
public bool has_previous () {
- assert (this._stamp == this._list._stamp);
+ assert (_stamp == _list._stamp);
- if (!this.started) {
+ if (GLib.likely (_position != null)) {
+ if (GLib.unlikely (_removed)) {
+ return true;
+ } else {
+ return _position.prev != null;
+ }
+ } else {
return false;
- } else if (this.position != null) {
- return this.position.prev != null;
}
- return false;
}
public bool last () {
- assert (this._stamp == this._list._stamp);
+ assert (_stamp == _list._stamp);
- if (this._list.size == 0) {
+ if (_list.size == 0) {
return false;
}
- this.position = this._list._tail;
- this.started = true;
- this._index = this._list._size - 1;
- return this.position != null;
+ _position = _list._tail;
+ _index = _list._size - 1;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_position != null);
+#endif
+ return true;
}
public new void set (G item) {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
+ assert (_position != null && !_removed);
- this.position.data = item;
+ _position.data = item;
}
public void insert (G item) {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
Node<G> n = new Node<G> (item);
- if (this.position.prev != null) {
- Node<G> position = (owned) this.position.prev.next;
- n.prev = position.prev;
- position.prev = n;
- n.next = (owned) position;
- weak Node<G> _n = n;
- _n.prev.next = (owned) n;
+ unowned Node<G> n_ref = n;
+ if (_position == null) {
+ Node<G>? position = (owned)_list._head;
+ if (position != null) {
+ position.prev = n;
+ n.next = (owned)position;
+ } else {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_list._tail == null);
+#endif
+ _list._tail = n;
+ }
+ if (_position == null) {
+ _position = n_ref;
+ }
+ _list._head = (owned)n;
} else {
- Node<G> position = (owned) this._list._head;
- position.prev = n;
- n.next = (owned) position;
- this._list._head = (owned) n;
+ if (_removed) {
+ if (_position.next != null) {
+ n.next = (owned)_position.next;
+ n.next.prev = n;
+ } else {
+ _list._tail = n;
+ }
+ n.prev = _position;
+ _position.next = (owned)n;
+ _position = n_ref;
+ } else {
+ n.prev = _position.prev;
+ _position.prev = n;
+ if (n.prev != null) {
+ n.next = (owned)n.prev.next;
+ n.prev.next = (owned)n;
+ } else {
+ n.next = (owned)_list._head;
+ _list._head = (owned)n;
+ }
+ }
}
- this._list._size++;
- this._index++;
+ _list._size++;
+ _index++;
_stamp = _list._stamp;
}
public void add (G item) {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
Node<G> n = new Node<G> (item);
- if (this.position.next != null) {
- this.position.next.prev = n;
- n.next = (owned) this.position.next;
+ unowned Node<G> n_ref = n;
+ if (_position == null) {
+ Node<G> position = (owned)_list._head;
+ position.prev = n;
+ n.next = (owned)position;
+ _list._head = (owned) n;
} else {
- this._list._tail = n;
+ if (_position.next != null) {
+ _position.next.prev = n;
+ n.next = (owned)_position.next;
+ } else {
+ _list._tail = n;
+ }
+ _position.next = (owned)n;
+ _position.next.prev = _position;
}
- this.position.next = (owned) n;
- this.position.next.prev = this.position;
- this.position = this.position.next;
- this._list._size++;
- this._index++;
+ _position = n_ref;
+ _removed = false;
+ _list._size++;
+ _index++;
_stamp = _list._stamp;
}
public int index () {
- assert (this._stamp == this._list._stamp);
- assert (this.position != null);
+ assert (_stamp == _list._stamp);
+ assert (_position != null && !_removed);
- return this._index;
+ return _index;
}
public bool read_only {
@@ -622,27 +680,47 @@ public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
public bool valid {
get {
- return !this.removed && this.position != null;
+ return !_removed && _position != null;
}
}
public bool foreach (ForallFunc<G> f) {
assert (_stamp == _list._stamp);
- if (!started) {
- position = _list._head;
- if (position != null)
- started = true;
+ if (_position == null) {
+ _position = _list._head;
+ }
+ if (_removed) {
+ _position = _position.next;
+ _removed = false;
}
- removed = false;
- while (position != null) {
- if (!f (position.data)) {
+ while (_position != null) {
+ if (!f (_position.data)) {
return false;
}
- position = position.next;
+ _position = _position.next;
}
- position = _list._tail;
+ _position = _list._tail;
return true;
}
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected bool _removed = false;
+ protected unowned Node<G>? _position;
+ protected int _stamp;
+ protected LinkedList<G> _list;
+ protected int _index;
}
private unowned Node<G>? _get_node_at (int index) {
diff --git a/gee/listiterator.vala b/gee/listiterator.vala
index a57a7df..e1f62f3 100644
--- a/gee/listiterator.vala
+++ b/gee/listiterator.vala
@@ -31,7 +31,10 @@ public interface Vala.ListIterator<G> : Vala.Iterator<G> {
/**
* Adds the specified item after the current item in the iteration. The
- * cursor is moved to point to the new added item.
+ * iterator is moved to the point of the new added item.
+ *
+ * Please note that if iterator points in-between elements the element
+ * is added after the current element and iterator point on it.
*/
public abstract void add (G item);
diff --git a/gee/map.vala b/gee/map.vala
index e48cb8a..bff8353 100644
--- a/gee/map.vala
+++ b/gee/map.vala
@@ -34,7 +34,7 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
* Specifies whether this map is empty.
*/
public virtual bool is_empty { get { return size == 0; } }
-
+
/**
* Specifies whether this collection can change - i.e. wheather {@link set},
* {@link remove} etc. are legal operations.
@@ -71,7 +71,7 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
public abstract V value { get; set; }
/**
- * ``true'' if the setting value is permitted.
+ * ``true`` if the setting value is permitted.
*/
public abstract bool read_only { get; }
}
@@ -91,10 +91,12 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
* @param key the key to locate in the map
*
* @return ``true`` if key is found, ``false`` otherwise
- *
- * @deprecated Use {@link has_key} method instead.
*/
- [Version (deprecated = true)]
+#if VALA_0_32
+ [Version (deprecated = true, replacement = "Map.has_key")]
+#else
+ [Deprecated (replacement = "Map.has_key")]
+#endif
public bool contains (K key) {
return has_key(key);
}
@@ -144,10 +146,12 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
* @param value the receiver variable for the removed value
*
* @return ``true`` if the map has been changed, ``false`` otherwise
- *
- * @deprecated Use {@link unset} method instead.
*/
- [Version (deprecated = true)]
+#if VALA_0_32
+ [Version (deprecated = true, replacement = "Map.unset")]
+#else
+ [Deprecated (replacement = "Map.unset")]
+#endif
public bool remove (K key, out V? value = null) {
return unset (key, out value);
}
@@ -187,7 +191,7 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
foreach (K key in map.keys) {
changed = changed | unset (key);
}
- return changed;
+ return changed;
}
/**
@@ -195,10 +199,12 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
* and this map.
*
* @param map the map which common items are deleted from this map
- *
- * @deprecated Use {@link unset_all} method instead.
*/
- [Version (deprecated = true)]
+#if VALA_0_32
+ [Version (deprecated = true, replacement = "Map.unset_all")]
+#else
+ [Deprecated (replacement = "Map.unset_all")]
+#endif
public bool remove_all (Map<K,V> map) {
return unset_all (map);
}
@@ -221,10 +227,12 @@ public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
* Returns ``true`` it this map contains all items as the input map.
*
* @param map the map which items will be compared with this map
- *
- * @deprecated Use {@link has_all} method instead.
*/
- [Version (deprecated = true)]
+#if VALA_0_32
+ [Version (deprecated = true, replacement = "Map.has_all")]
+#else
+ [Deprecated (replacement = "Map.has_all")]
+#endif
public bool contains_all (Map<K,V> map) {
return has_all (map);
}
diff --git a/gee/mapiterator.vala b/gee/mapiterator.vala
index 2ad5890..6d575ef 100644
--- a/gee/mapiterator.vala
+++ b/gee/mapiterator.vala
@@ -82,28 +82,28 @@ public interface Vala.MapIterator<K,V> : Object {
* {@link next}).
*/
public abstract void unset ();
-
+
/**
- * Determines wheather the call to {@link get_key}, {@link get_value} and
+ * Determines wheather the call to {@link get_key}, {@link get_value} and
* {@link set_value} is legal. It is false at the beginning and after
* {@link unset} call and true otherwise.
*/
public abstract bool valid { get; }
-
+
/**
* Determines wheather the call to {@link set_value} is legal assuming the
* iterator is valid. The value must not change in runtime hence the user
* of iterator may cache it.
*/
public abstract bool mutable { get; }
-
+
/**
* Determines wheather the call to {@link unset} is legal assuming the
* iterator is valid. The value must not change in runtime hence the user
* of iterator may cache it.
*/
public abstract bool read_only { get; }
-
+
/**
* Standard aggragation function.
*
@@ -121,9 +121,9 @@ public interface Vala.MapIterator<K,V> : Object {
seed = f (get_key (), get_value (), (owned) seed);
return (owned) seed;
}
-
+
/**
- * Apply function to each element returned by iterator.
+ * Apply function to each element returned by iterator.
*
* Operation moves the iterator to last element in iteration. If iterator
* points at some element it will be included in iteration.
diff --git a/gee/multimap.vala b/gee/multimap.vala
index 6c1748b..88bcb72 100644
--- a/gee/multimap.vala
+++ b/gee/multimap.vala
@@ -29,7 +29,7 @@ public interface Vala.MultiMap<K,V> : Object {
* The number of key/value pairs in this map.
*/
public abstract int size { get; }
-
+
/**
* Specifies whether this collection can change - i.e. wheather {@link set},
* {@link remove} etc. are legal operations.
@@ -124,4 +124,10 @@ public interface Vala.MultiMap<K,V> : Object {
* The type of the values in this multimap.
*/
public Type value_type { get { return typeof (V); } }
+
+ public virtual MultiMap<K, V> read_only_view {
+ owned get {
+ return new ReadOnlyMultiMap<K, V> (this);
+ }
+ }
}
diff --git a/gee/multiset.vala b/gee/multiset.vala
index 7b9f774..b984e17 100644
--- a/gee/multiset.vala
+++ b/gee/multiset.vala
@@ -33,4 +33,23 @@ public interface Vala.MultiSet<G> : Collection<G> {
* @return the number of occurences of the item in this multiset.
*/
public abstract int count (G item);
+
+ /**
+ * The read-only view of this set.
+ */
+ public virtual new MultiSet<G> read_only_view {
+ owned get {
+ return new ReadOnlyMultiSet<G> (this);
+ }
+ }
+
+ /**
+ * Returns an immutable empty set.
+ *
+ * @return an immutable empty set
+ */
+ public static Set<G> empty<G> () {
+ return new HashSet<G> ().read_only_view;
+ }
}
+
diff --git a/gee/priorityqueue.vala b/gee/priorityqueue.vala
index 04d0a00..ca90fef 100644
--- a/gee/priorityqueue.vala
+++ b/gee/priorityqueue.vala
@@ -1,7 +1,7 @@
/* priorityqueue.vala
*
* Copyright (C) 2009 Didier Villevalois
- * Copyright (C) 2012 Maciej Piechotka
+ * Copyright (C) 2012-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -46,7 +46,12 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
* The elements' comparator function.
*/
[CCode (notify = false)]
- public CompareDataFunc<G> compare_func { private set; get; }
+ public CompareDataFunc<G> compare_func {
+ private set {}
+ get {
+ return _compare_func;
+ }
+ }
private int _size = 0;
private int _stamp = 0;
@@ -55,14 +60,19 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
private Type2Node<G>? _lm_head = null;
private Type2Node<G>? _lm_tail = null;
private Type1Node<G>? _p = null;
+#if VALA_0_16
private Type1Node<G>?[] _a = new Type1Node<G>?[0];
+#else
+ private Type1Node<G>?[] _a = new Type1Node<G>[0];
+#endif
private NodePair<G>? _lp_head = null;
- private NodePair<G>? _lp_tail = null;
+ private unowned NodePair<G>? _lp_tail = null;
private bool[] _b = new bool[0];
private Type1Node<G>? _ll_head = null;
private Type1Node<G>? _ll_tail = null;
private unowned Node<G> _iter_head = null;
private unowned Node<G> _iter_tail = null;
+ private CompareDataFunc<G> _compare_func;
/**
* Constructs a new, empty priority queue.
@@ -76,7 +86,7 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
if (compare_func == null) {
compare_func = Functions.get_compare_func_for (typeof (G));
}
- this.compare_func = compare_func;
+ _compare_func = (owned)compare_func;
}
/**
@@ -343,7 +353,11 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
_lm_head = null;
_lm_tail = null;
_p = null;
+#if VALA_0_16
_a = new Type1Node<G>?[0];
+#else
+ _a = new Type1Node<G>[0];
+#endif
_lp_head = null;
_lp_tail = null;
_b = new bool[0];
@@ -360,6 +374,18 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
return new Iterator<G> (this);
}
+ /**
+ * {@inheritDoc}
+ */
+ public override bool foreach (ForallFunc<G> f) {
+ for (unowned Node<G>? current = _iter_head; current != null; current = current.iter_next) {
+ if (!f (current.data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private inline int _compare (Node<G> node1, Node<G> node2) {
// Assume there can't be two nodes pending drop
if (node1.pending_drop) {
@@ -434,7 +460,7 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
#if DEBUG
_dump ("After swap: %p(%s) %p(%s)".printf(node1, (string)node1.data, node2,
(string)node2.data));
- #endif
+ #endif
}
private inline void _move_data (Node<G> target, Node<G> source) {
@@ -525,7 +551,7 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
#endif
if (_lp_head != null) {
- NodePair<G> pair = _lp_head;
+ unowned NodePair<G> pair = _lp_head;
_link (pair.node1, pair.node2);
return true;
}
@@ -697,12 +723,12 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
node.brothers_next.pair = pair;
node.pair = pair;
if (_lp_head == null) {
- _lp_head = pair;
_lp_tail = pair;
+ _lp_head = (owned)pair;
} else {
pair.lp_prev = _lp_tail;
- _lp_tail.lp_next = pair;
- _lp_tail = pair;
+ _lp_tail.lp_next = (owned)pair;
+ _lp_tail = _lp_tail.lp_next;
}
// There is now an even number of child of such degree
_b[degree] = false;
@@ -820,20 +846,20 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
// Maintain LP
if (node.pair != null) {
- NodePair<G> pair = node.pair;
+ unowned 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;
}
+ if (pair.lp_prev != null) {
+ pair.lp_prev.lp_next = (owned)pair.lp_next;
+ } else {
+ _lp_head = (owned)pair.lp_next;
+ }
}
}
@@ -1101,11 +1127,12 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
#endif
}
+ [Compact]
private class NodePair<G> {
- public weak NodePair<G>? lp_prev = null;
+ public unowned NodePair<G>? lp_prev = null;
public NodePair<G>? lp_next = null;
- public Type1Node<G> node1 = null;
- public Type1Node<G> node2 = null;
+ public unowned Type1Node<G> node1 = null;
+ public unowned Type1Node<G> node2 = null;
public NodePair (Type1Node<G> node1, Type1Node<G> node2) {
this.node1 = node1;
@@ -1114,11 +1141,6 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
}
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
- private PriorityQueue<G> queue;
- private unowned Node<G>? position;
- private unowned Node<G>? previous;
- private int stamp;
-
public Iterator (PriorityQueue<G> queue) {
this.queue = queue;
this.position = null;
@@ -1126,6 +1148,13 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
this.stamp = queue._stamp;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ queue = iter.queue;
+ position = iter.position;
+ previous = iter.previous;
+ stamp = iter.stamp;
+ }
+
public bool next () {
unowned Node<G>? next = _get_next_node ();
if (next != null) {
@@ -1203,5 +1232,24 @@ public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
}
return true;
}
+
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected PriorityQueue<G> queue;
+ protected unowned Node<G>? position;
+ protected unowned Node<G>? previous;
+ protected int stamp;
}
}
diff --git a/gee/promise.vala b/gee/promise.vala
new file mode 100644
index 0000000..23d0840
--- /dev/null
+++ b/gee/promise.vala
@@ -0,0 +1,210 @@
+/* promise.vala
+ *
+ * Copyright (C) 2013 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;
+
+/**
+ * Promise allows to set a value with associated {@link Future}. Please note that
+ * value can be stored only once.
+ *
+ * Typically the producer will create promise and return {@link future} while
+ * keeping the promise to itself. Then when value is ready it can call {@link set_value}.
+ *
+ * @see Future
+ * @see task
+ * @since 0.11.0
+ */
+public class Vala.Promise<G> {
+ ~Promise () {
+ _future.abandon ();
+ }
+
+ /**
+ * {@link Future} value of this promise
+ */
+ public Vala.Future<G> future {
+ get {
+ return _future;
+ }
+ }
+
+ /**
+ * Sets the value of the future.
+ *
+ * @param value Value of future
+ */
+ public void set_value (owned G value) {
+ _future.set_value ((owned)value);
+ }
+
+ /**
+ * Sets the exception.
+ *
+ * @param exception Exception thrown
+ */
+ public void set_exception (owned GLib.Error exception) {
+ _future.set_exception ((owned)exception);
+ }
+
+ private class Future<G> : Object, Vala.Future<G> {
+ public bool ready {
+ get {
+ _mutex.lock ();
+ bool result = _state != State.INIT;
+ _mutex.unlock ();
+ return result;
+ }
+ }
+
+ public GLib.Error? exception {
+ get {
+ return _exception;
+ }
+ }
+
+ public unowned G wait () throws FutureError {
+ _mutex.lock ();
+ State state = _state;
+ if (_state == State.INIT) {
+ _set.wait (_mutex);
+ state = _state;
+ }
+ assert (state != State.INIT);
+ _mutex.unlock ();
+ switch (state) {
+ case State.ABANDON:
+ throw new FutureError.ABANDON_PROMISE ("Promise has been abandon");
+ case State.EXCEPTION:
+ throw new FutureError.EXCEPTION ("Exception has been thrown");
+ case State.READY:
+ return _value;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public bool wait_until (int64 end_time, out unowned G? value = null) throws FutureError {
+ _mutex.lock ();
+ State state = _state;
+ if (state == State.INIT) {
+ _set.wait_until (_mutex, end_time);
+ state = _state;
+ }
+ _mutex.unlock ();
+ switch (state) {
+ case State.INIT:
+ value = null;
+ return false;
+ case State.ABANDON:
+ throw new FutureError.ABANDON_PROMISE ("Promise has been abandon");
+ case State.EXCEPTION:
+ throw new FutureError.EXCEPTION ("Exception has been thrown");
+ case State.READY:
+ value = _value;
+ return true;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public async unowned G wait_async () throws Vala.FutureError {
+ _mutex.lock ();
+ State state = _state;
+ if (state == State.INIT) {
+ _when_done += SourceFuncArrayElement(wait_async.callback);
+ yield Vala.Utils.Async.yield_and_unlock (_mutex);
+ state = _state;
+ } else {
+ _mutex.unlock ();
+ }
+ assert (state != State.INIT);
+ switch (state) {
+ case State.ABANDON:
+ throw new FutureError.ABANDON_PROMISE ("Promise has been abandon");
+ case State.EXCEPTION:
+ throw new FutureError.EXCEPTION ("Exception has been thrown");
+ case State.READY:
+ return _value;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ internal void set_value (owned G value) {
+ _mutex.lock ();
+ assert (_state == State.INIT);
+ _state = State.READY;
+ _value = (owned)value;
+ _set.broadcast ();
+ _mutex.unlock ();
+ Vala.Future.SourceFuncArrayElement<G>[] when_done = (owned)_when_done;
+ for (int i = 0; i < when_done.length; i++) {
+ when_done[i].func ();
+ }
+ }
+
+ internal void set_exception (owned GLib.Error? exception) {
+ _mutex.lock ();
+ assert (_state == State.INIT);
+ _state = State.EXCEPTION;
+ _exception = (owned)exception;
+ _set.broadcast ();
+ _mutex.unlock ();
+ Vala.Future.SourceFuncArrayElement<G>[] when_done = (owned)_when_done;
+ for (int i = 0; i < when_done.length; i++) {
+ when_done[i].func ();
+ }
+ }
+
+ internal void abandon () {
+ _mutex.lock ();
+ if (_state != State.INIT) {
+ _mutex.unlock ();
+ return;
+ }
+ assert (_state == State.INIT);
+ _state = State.ABANDON;
+ _set.broadcast ();
+ _mutex.unlock ();
+ Vala.Future.SourceFuncArrayElement<G>[] when_done = (owned)_when_done;
+ for (int i = 0; i < when_done.length; i++) {
+ when_done[i].func ();
+ }
+ }
+
+ private Mutex _mutex = Mutex ();
+ private Cond _set = Cond ();
+ private State _state;
+ private G? _value;
+ private GLib.Error? _exception;
+ private Vala.Future.SourceFuncArrayElement<G>[]? _when_done = new
Vala.Future.SourceFuncArrayElement<G>[0];
+
+ private enum State {
+ INIT,
+ ABANDON,
+ EXCEPTION,
+ READY
+ }
+ }
+ private Future<G> _future = new Future<G>();
+}
+
diff --git a/gee/queue.vala b/gee/queue.vala
index df678d1..938d29e 100644
--- a/gee/queue.vala
+++ b/gee/queue.vala
@@ -52,12 +52,12 @@ public interface Vala.Queue<G> : Collection<G> {
public const int UNBOUNDED_CAPACITY = -1;
/**
- * The capacity of this queue (or ``null`` if capacity is not bound).
+ * The capacity of this queue (or ``UNBOUNDED_CAPACITY`` if capacity is not bound).
*/
public abstract int capacity { get; }
/**
- * The remaining capacity of this queue (or ``null`` if capacity is not
+ * The remaining capacity of this queue (or ``UNBOUNDED_CAPACITY`` if capacity is not
* bound).
*/
public abstract int remaining_capacity { get; }
diff --git a/gee/readonlycollection.vala b/gee/readonlycollection.vala
index f810f20..92138f0 100644
--- a/gee/readonlycollection.vala
+++ b/gee/readonlycollection.vala
@@ -1,6 +1,7 @@
/* readonlycollection.vala
*
* Copyright (C) 2007-2008 Jürg Billeter
+ * Copyright (C) 2010-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -46,7 +47,7 @@ internal class Vala.ReadOnlyCollection<G> : Object, Traversable<G>, Iterable<G>,
public bool is_empty {
get { return _collection.is_empty; }
}
-
+
/**
* {@inheritDoc}
*/
@@ -76,7 +77,7 @@ internal class Vala.ReadOnlyCollection<G> : Object, Traversable<G>, Iterable<G>,
/**
* {@inheritDoc}
*/
- public Vala.Iterator<A> stream<A> (owned StreamFunc<A> f) {
+ public Vala.Iterator<A> stream<A> (owned StreamFunc<G, A> f) {
return _collection.stream<A> ((owned)f);
}
@@ -214,7 +215,7 @@ internal class Vala.ReadOnlyCollection<G> : Object, Traversable<G>, Iterable<G>,
return _iter.foreach (f);
}
- public Vala.Iterator<A> stream<A> (owned StreamFunc<A, G> f) {
+ public Vala.Iterator<A> stream<A> (owned StreamFunc<G, A> f) {
return _iter.stream<A> ((owned)f);
}
@@ -225,6 +226,24 @@ internal class Vala.ReadOnlyCollection<G> : Object, Traversable<G>, Iterable<G>,
public Vala.Iterator<G> chop (int offset, int length = -1) {
return _iter.chop ( offset, length);
}
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] iters = _iter.tee (forks);
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ if (iters[0] == _iter) {
+ result[0] = this;
+ } else {
+ result[0] = new Iterator<G> (iters[0]);
+ }
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G> (iters[i]);
+ }
+ return result;
+ }
+ }
}
public virtual Collection<G> read_only_view {
diff --git a/gee/readonlymap.vala b/gee/readonlymap.vala
index c14ebbe..1307fd3 100644
--- a/gee/readonlymap.vala
+++ b/gee/readonlymap.vala
@@ -244,7 +244,7 @@ internal class Vala.ReadOnlyMap<K,V> : Object, Traversable<Map.Entry<K,V>>, Iter
return _map.chop (offset, length);
}
- protected class MapIterator<K,V> : Object, Vala.MapIterator<K,V> {
+ internal class MapIterator<K,V> : Object, Vala.MapIterator<K,V> {
protected Vala.MapIterator<K,V> _iter;
public MapIterator (Vala.MapIterator<K,V> iterator) {
@@ -274,19 +274,19 @@ internal class Vala.ReadOnlyMap<K,V> : Object, Traversable<Map.Entry<K,V>>, Iter
public void unset () {
assert_not_reached ();
}
-
+
public bool read_only {
get {
return true;
}
}
-
+
public bool mutable {
get {
return false;
}
}
-
+
public bool valid {
get {
return _iter.valid;
diff --git a/gee/readonlymultimap.vala b/gee/readonlymultimap.vala
new file mode 100644
index 0000000..a7d51bc
--- /dev/null
+++ b/gee/readonlymultimap.vala
@@ -0,0 +1,131 @@
+/* readonlymultimap.vala
+ *
+ * Copyright (C) 2013 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;
+
+/**
+ * Read-only view for {@link MultiMap} collections.
+ *
+ * This class decorates any class which implements the {@link MultiMap}
+ * interface by making it read only. Any method which normally modify data will
+ * throw an error.
+ *
+ * @see MultiMap
+ */
+internal class Vala.ReadOnlyMultiMap<K, V> : Object, MultiMap<K, V> {
+ /**
+ * Constructs a read-only multi-set that mirrors the content of the specified
+ * list.
+ *
+ * @param multiset the multi-set to decorate.
+ */
+ public ReadOnlyMultiMap (MultiMap<K, V> multimap) {
+ this._multimap = multimap;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size { get { return _multimap.size; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool read_only { get { return true; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<K> get_keys () {
+ return _multimap.get_keys ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MultiSet<K> get_all_keys () {
+ return _multimap.get_all_keys ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<V> get_values () {
+ return _multimap.get_values ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool contains (K key) {
+ return _multimap.contains (key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new Collection<V> get (K key) {
+ return _multimap.get (key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new void set (K key, V value) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool remove (K key, V value) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool remove_all (K key) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clear () {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MapIterator<K, V> map_iterator () {
+ return new ReadOnlyMap.MapIterator<K, V> (_multimap.map_iterator ());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new MultiMap<K, V> read_only_view { owned get { return this; } }
+
+ private MultiMap<K, V> _multimap;
+}
diff --git a/gee/readonlymultiset.vala b/gee/readonlymultiset.vala
new file mode 100644
index 0000000..f5cd2c1
--- /dev/null
+++ b/gee/readonlymultiset.vala
@@ -0,0 +1,57 @@
+/* readonlymultiset.vala
+ *
+ * Copyright (C) 2013 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;
+
+/**
+ * Read-only view for {@link MultiSet} collections.
+ *
+ * This class decorates any class which implements the {@link Collection}
+ * interface by making it read only. Any method which normally modify data will
+ * throw an error.
+ *
+ * @see MultiSet
+ */
+internal class Vala.ReadOnlyMultiSet<G> : Vala.ReadOnlyCollection<G>, MultiSet<G> {
+ /**
+ * Constructs a read-only multi-set that mirrors the content of the specified
+ * list.
+ *
+ * @param multiset the multi-set to decorate.
+ */
+ public ReadOnlyMultiSet (MultiSet<G> multiset) {
+ base (multiset);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int count (G item) {
+ return ((Vala.MultiSet<G>) _collection).count (item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new MultiSet<G> read_only_view { owned get { return this; } }
+}
+
diff --git a/gee/streamiterator.vala b/gee/streamiterator.vala
new file mode 100644
index 0000000..06d8c2b
--- /dev/null
+++ b/gee/streamiterator.vala
@@ -0,0 +1,183 @@
+/* streamiterator.vala
+ *
+ * Copyright (C) 2013 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>
+ */
+
+internal class Vala.StreamIterator<A, G> : GLib.Object, Traversable<A>, Iterator<A> {
+ public StreamIterator (Iterator<G> outer, owned StreamFunc<A, G> func) {
+ _outer = outer;
+ _func = (owned)func;
+ _current = null;
+ _need_next = true;
+ _finished = false;
+
+ _state = _func (Traversable.Stream.YIELD, null, out _current);
+ switch (_state) {
+ case Traversable.Stream.WAIT:
+ case Traversable.Stream.YIELD:
+ _need_next = !_outer.valid;
+ break;
+ case Traversable.Stream.CONTINUE:
+ if (_outer.valid) {
+ _state = _func (_state, new Lazy<G> (() => {
+ return _outer.get ();
+ }), out _current);
+ switch (_state) {
+ case Traversable.Stream.YIELD:
+ case Traversable.Stream.CONTINUE:
+ case Traversable.Stream.WAIT:
+ break;
+ case Traversable.Stream.END:
+ _finished = true;
+ return;
+ default:
+ assert_not_reached ();
+ }
+ }
+ break;
+ case Traversable.Stream.END:
+ _finished = true;
+ return;
+ }
+ }
+
+ public bool foreach (ForallFunc<A> f) {
+ Lazy<G>? current = null;
+ if (_current != null) {
+ if (!f (_current.value)) {
+ return false;
+ }
+ }
+ if (_next != null) {
+ current = (owned)_next;
+ if (!f (current.value)) {
+ return false;
+ }
+ } else if (_finished) {
+ return true;
+ }
+ unowned Iterator<G> outer = _outer;
+ unowned StreamFunc<A, G> func = _func;
+ Traversable.Stream state = _state;
+ bool need_next = _need_next;
+ bool result = true;
+ Lazy<A>? next_current;
+ Lazy<G>? outer_value = _outer_value;
+ while ((next_current = yield_next<A, G>(outer, func, ref state, ref need_next, ref
outer_value)) != null) {
+ current = (owned)next_current;
+ if (!f (current.value)) {
+ result = false;
+ break;
+ }
+ }
+ _state = state;
+ _need_next = need_next;
+ _finished = result;
+ _current = (owned)current;
+ _outer_value = (owned)outer_value;
+ return result;
+ }
+
+ public bool next () {
+ if (has_next ()) {
+ if (_current != null) {
+ _current.eval ();
+ }
+ _current = (owned)_next;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_next () {
+ if (_finished) {
+ return false;
+ }
+ if (_next != null) {
+ return true;
+ }
+ _next = yield_next<A, G> (_outer, _func, ref _state, ref _need_next, ref _outer_value);
+ _finished = _next == null;
+ return !_finished;
+ }
+
+ public new A get () {
+ assert (_current != null);
+ return _current.value;
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public bool valid { get { return _current != null; } }
+ public bool read_only { get { return true; } }
+
+ private static inline Lazy<A>? yield_next<A, G> (Iterator<G> outer, StreamFunc<A, G> func, ref
Traversable.Stream state, ref bool need_next, ref Lazy<G>? outer_value) {
+ Lazy<A>? value = null;
+ if (state != Traversable.Stream.CONTINUE)
+ state = func (state, null, out value);
+ while (true) {
+ switch (state) {
+ case Traversable.Stream.YIELD:
+ return value;
+ case Traversable.Stream.CONTINUE:
+ if (outer_value != null) {
+ outer_value.eval ();
+ }
+ if (need_next) {
+ if (!outer.has_next ()) {
+ state = func (Traversable.Stream.END, null, out value);
+ continue;
+ }
+ outer_value = new Lazy<G> (() => {
+ assert (outer.next ());
+ return outer.get ();
+ });
+ } else {
+ need_next = true;
+ outer_value = new Lazy<G> (() => {
+ return outer.get ();
+ });
+ }
+ state = func (state, outer_value, out value);
+ break;
+ case Traversable.Stream.WAIT:
+ state = func (state, null, out value);
+ break;
+ case Traversable.Stream.END:
+ return null;
+ default:
+ assert_not_reached ();
+ }
+ }
+ }
+
+ private Iterator<G> _outer;
+ private StreamFunc<A, G> _func;
+ private Lazy<G>? _outer_value;
+ private Lazy<A>? _current;
+ private Lazy<A>? _next;
+ private Traversable.Stream _state;
+ private bool _need_next;
+ private bool _finished;
+}
+
diff --git a/gee/task.vala b/gee/task.vala
new file mode 100644
index 0000000..d902519
--- /dev/null
+++ b/gee/task.vala
@@ -0,0 +1,97 @@
+/* task.vala
+ *
+ * Copyright (C) 2013 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>
+ */
+namespace Vala {
+ [CCode (scope = "async")]
+ public delegate G Task<G>();
+
+ /**
+ * Schedules a task to execute asynchroniously. Internally one
+ * of threads from pool will execute the task.
+ *
+ * Note: There is limited number of threads unless environment variable
+ * ``GEE_NUM_THREADS`` is set to -1. It is not adviced to call I/O or
+ * block inside the taks. If necessary it is possible to create a new one
+ * by anyther call.
+ *
+ * @param task Task to be executed
+ * @return Future value returned by task
+ * @see async_task
+ * @since 0.11.0
+ */
+ public Future<G> task<G>(owned Task<G> task) throws GLib.ThreadError {
+ TaskData<G> tdata = new TaskData<G>();
+ tdata.function = (owned)task;
+ tdata.promise = new Promise<G>();
+ Future<G> result = tdata.promise.future;
+ TaskData.get_async_pool ().add ((owned)tdata);
+ return result;
+ }
+
+ /**
+ * Continues the execution asynchroniously in helper thread. Internally
+ * one of threads from pool will execute the task.
+ *
+ * Note: There is limited number of threads unless environment variable
+ * ``GEE_NUM_THREADS`` is set to -1. It is not adviced to call I/O or
+ * block inside the taks. If necessary it is possible to create a new one
+ * by anyther call.
+ *
+ * @see task
+ * @since 0.11.0
+ */
+ public async void async_task() throws GLib.ThreadError {
+ task<bool>(async_task.callback);
+ }
+
+ [CCode (cheader_filename = "sys/sysinfo.h", cname = "get_nprocs")]
+ private extern static int get_nprocs ();
+
+ [Compact]
+ internal class TaskData<G> {
+ public Task<G> function;
+ public Promise<G> promise;
+ public void run() {
+ promise.set_value(function());
+ }
+ private static GLib.Once<ThreadPool<TaskData>> async_pool;
+ internal static unowned ThreadPool<TaskData> get_async_pool () {
+ return async_pool.once(() => {
+ int num_threads = get_nprocs ();
+ string? gee_num_threads_str = Environment.get_variable("GEE_NUM_THREADS");
+ if (gee_num_threads_str != null) {
+ int64 result;
+ if (int64.try_parse (gee_num_threads_str, out result)) {
+ num_threads = (int)result;
+ }
+ }
+ try {
+ return new ThreadPool<TaskData>.with_owned_data((tdata) => {
+ tdata.run();
+ }, num_threads, false);
+ } catch (ThreadError err) {
+ Process.abort ();
+ }
+ });
+ }
+ }
+}
+
diff --git a/gee/teeiterator.vala b/gee/teeiterator.vala
new file mode 100644
index 0000000..b2c30d8
--- /dev/null
+++ b/gee/teeiterator.vala
@@ -0,0 +1,116 @@
+/* teeiterator.vala
+ *
+ * Copyright (C) 2013 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>
+ */
+
+internal class Vala.TeeIterator<G> : Object, Traversable<G>, Iterator<G> {
+ internal TeeIterator (Node<G>? head, bool valid) {
+ _head = head;
+ _valid = valid;
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ Node<G> head = (owned)_head;
+ bool valid = _valid;
+ if (valid) {
+ if (!f (head._data.get ())) {
+ return false;
+ }
+ }
+ unowned Node<G>? next_head = head._next.value;
+ while (next_head != null) {
+ head = next_head;
+ valid = true;
+ if (!f (head._data.get ())) {
+ _head = (owned)head;
+ _valid = valid;
+ return false;
+ }
+ }
+ _head = (owned)head;
+ _valid = valid;
+ return true;
+ }
+
+ public Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<G>[0];
+ } else {
+ Iterator<G>[] result = new Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new TeeIterator<G> (_head, _valid);
+ }
+ return result;
+ }
+ }
+
+ public bool next () {
+ unowned Node<G>? next = _head._next.value;
+ if (next != null) {
+ _head = next;
+ _valid = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_next () {
+ return _head._next.get () != null;
+ }
+
+ public new G get () {
+ return _head._data.get ();
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public bool valid { get { return _valid; } }
+
+ public bool read_only { get { return true; } }
+
+ private Node<G> _head;
+ private bool _valid;
+
+ internal static Lazy<Node<G>?> create_nodes<G> (Iterator<G> iterator, Lazy<G> dependent) {
+ return new Lazy<Node<G>?>(() => {
+ dependent.eval ();
+ if (!iterator.next ())
+ return null;
+ Lazy<G> data = new Lazy<G> (() => {return iterator.get ();});
+ Lazy<Node<G>?> next = create_nodes<G> (iterator, data);
+ return new Node<G> ((owned)data, (owned)next);
+ });
+ }
+
+ internal class Node<G> {
+ public Node (owned Lazy<G> data, owned Lazy<Node<G>?> next) {
+ _data = (owned)data;
+ _next = (owned)next;
+ }
+ public Lazy<G> _data;
+ public Lazy<Node<G>?> _next;
+ }
+
+}
+
diff --git a/gee/timsort.vala b/gee/timsort.vala
index 5d1a862..4dca2ba 100644
--- a/gee/timsort.vala
+++ b/gee/timsort.vala
@@ -94,7 +94,7 @@ internal class Vala.TimSort<G> : Object {
private int size;
private Slice<G>[] pending;
private int minimum_gallop;
- private CompareDataFunc<G> compare;
+ private unowned CompareDataFunc<G> compare;
private void do_sort () {
if (size < 2) {
@@ -278,7 +278,7 @@ internal class Vala.TimSort<G> : Object {
#endif
Slice<G> a = (owned) pending[index];
Slice<G> b = (owned) pending[index + 1];
-
+
assert (a.length > 0);
assert (b.length > 0);
assert (a.index + a.length == b.index);
@@ -648,7 +648,7 @@ internal class Vala.TimSort<G> : Object {
this.index = index;
this.length = length;
}
-
+
~Slice () {
if (new_list != null)
free (new_list);
diff --git a/gee/traversable.vala b/gee/traversable.vala
index 5589622..769ef02 100644
--- a/gee/traversable.vala
+++ b/gee/traversable.vala
@@ -59,9 +59,12 @@ public interface Vala.Traversable<G> : Object {
* to last element in iteration or the first element that returned ''false''.
* If iterator points at some element it will be included in iteration.
*
+ * @param f function applied to every element of the collection
+ *
* @return ''false'' if the argument returned ''false'' at last invocation and
* ''true'' otherwise.
*/
+ [CCode (ordering = 0)]
public new abstract bool foreach (ForallFunc<G> f);
/**
@@ -84,13 +87,17 @@ public interface Vala.Traversable<G> : Object {
* 1. {@link Stream.CONTINUE}. It means that the function needs to be
* called with next element or with {@link Stream.END} if it is
* end of stream). If the state element was Stream.END during the
- * current iteration function ''must not'' return {@link Stream.CONTINUE}
- * 1. Stream.END. It means that the last argument was yielded.
+ * current iteration function ''must not'' return {@link Stream.CONTINUE}.
+ * 1. {@link Stream.WAIT}. Simply denotes that iterator should skip an element.
+ * Usually the function is called once again with {@link Stream.WAIT} as
+ * state however it do affect the initial validity of iterator.
+ * 1. {@link Stream.END}. It means that the last argument was yielded.
*
* If the function yields the value immediately then the returning iterator
* is {@link Iterator.valid} and points to this value as well as in case when the
* parent iterator is {@link Iterator.valid} and function yields
- * after consuming 1 input. In other case returned iterator is invalid.
+ * after consuming 1 input. In other case returned iterator is invalid including
+ * when the first value returned is {@link Stream.WAIT}.
*
* Note: In {@link Iterator} implementation: if iterator is
* {@link Iterator.valid} the current value should be fed
@@ -102,64 +109,13 @@ public interface Vala.Traversable<G> : Object {
* @param f function generating stream
* @return iterator containing values yielded by stream
*/
+ [CCode (ordering = 1)]
public virtual Iterator<A> stream<A> (owned StreamFunc<G, A> f) {
- Iterator<G>? self;
- Iterable<G>? iself;
+ unowned Iterator<G>? self;
+ unowned Iterable<G>? iself;
// Yes - I've heard of polimorphism ;) but I don't want users to need to implement the method.
if ((self = this as Iterator<G>) != null) {
- Traversable.Stream str;
- Lazy<A>? initial = null;
- bool need_next = true;
- str = f (Stream.YIELD, null, out initial);
- switch (str) {
- case Stream.CONTINUE:
- if (self.valid) {
- str = f (Stream.CONTINUE, new Lazy<G> (() => {return self.get ();}),
out initial);
- switch (str) {
- case Stream.YIELD:
- case Stream.CONTINUE:
- break;
- case Stream.END:
- return Iterator.unfold<A> (() => {return null;});
- default:
- assert_not_reached ();
- }
- }
- break;
- case Stream.YIELD:
- if (self.valid)
- need_next = false;
- break;
- case Stream.END:
- return Iterator.unfold<A> (() => {return null;});
- default:
- assert_not_reached ();
- }
- return Iterator.unfold<A> (() => {
- Lazy<A>? val = null;
- if (str != Stream.CONTINUE)
- str = f (Traversable.Stream.YIELD, null, out val);
- while (str == Stream.CONTINUE) {
- if (need_next) {
- if (!self.next ()) {
- str = f (Traversable.Stream.END, null, out val);
- assert (str != Traversable.Stream.CONTINUE);
- break;
- }
- } else {
- need_next = true;
- }
- str = f (Stream.CONTINUE, new Lazy<G> (() => {return self.get ();}),
out val);
- }
- switch (str) {
- case Stream.YIELD:
- return val;
- case Stream.END:
- return null;
- default:
- assert_not_reached ();
- }
- }, initial);
+ return new StreamIterator<A, G> (self, (owned)f);
} else if ((iself = this as Iterable<G>) != null) {
return iself.iterator().stream<A> ((owned) f);
} else {
@@ -181,6 +137,7 @@ public interface Vala.Traversable<G> : Object {
* as well.
*
*/
+ [CCode (ordering = 2)]
public virtual A fold<A> (FoldFunc<A, G> f, owned A seed)
{
this.foreach ((item) => {seed = f ((owned) item, (owned) seed); return true; });
@@ -205,6 +162,7 @@ public interface Vala.Traversable<G> : Object {
* @param f Mapping function
* @return Iterator listing mapped value
*/
+ [CCode (ordering = 3)]
public virtual Iterator<A> map<A> (MapFunc<A, G> f) {
return stream<A>((state, item, out val) => {
switch (state) {
@@ -245,6 +203,7 @@ public interface Vala.Traversable<G> : Object {
* @param seed original seed value
* @return Iterator containing values of subsequent values of seed
*/
+ [CCode (ordering = 4)]
public virtual Iterator<A> scan<A> (FoldFunc<A, G> f, owned A seed) {
bool seed_emitted = false;
return stream<A>((state, item, out val) => {
@@ -286,9 +245,10 @@ public interface Vala.Traversable<G> : Object {
* iterator is {@link Iterator.valid} and value it is pointing on
* fullfills the predicate.
*
- * @param f Folding function
+ * @param pred predicate to check should the value be retained
* @return Iterator containing values of subsequent values of seed
*/
+ [CCode (ordering = 5)]
public virtual Iterator<G> filter (owned Predicate<G> pred) {
return stream<G> ((state, item, out val) => {
switch (state) {
@@ -329,6 +289,7 @@ public interface Vala.Traversable<G> : Object {
* @param length maximum number of elements iterator may return. Negative
* value means that the number is unbounded
*/
+ [CCode (ordering = 6)]
public virtual Iterator<G> chop (int offset, int length = -1) {
assert (offset >= 0);
return stream<G> ((state, item, out val) => {
@@ -363,17 +324,138 @@ public interface Vala.Traversable<G> : Object {
});
}
-
/**
* The type of the elements in this collection.
*/
+ [CCode (ordering = 7)]
public virtual Type element_type { get { return typeof (G); } }
+ /**
+ * A fused concatinate and map. The function is applied to each element
+ * of iteration and the resulting values are concatinated.
+ *
+ * The iterator is lazy evaluated but value is force-evaluated when
+ * iterator is moved to next value.
+ *
+ * Note: Default implementation uses {@link stream}.
+ *
+ * Note: In {@link Iterator} implementation if the parent iterator is
+ * {@link Iterator.valid} and function returns a valid iterator the
+ * resulting iterator is also valid. Using the parent iterator is not
+ * allowed before the inner iterator {@link Iterator.next}
+ * return false and then it points on its last element.
+ *
+ * @since 0.11.1
+ * @param f mapping function
+ * @return Iterator over returned values
+ */
+ [CCode (ordering = 8)]
+ public virtual Iterator<A> flat_map<A>(owned FlatMapFunc<A, G> f) {
+ Iterator<A>? current = null;
+ return stream<A> ((state, item, out val) => {
+ switch (state) {
+ case Stream.YIELD:
+ if (current == null || !current.next ()) {
+ val = null;
+ return Stream.CONTINUE;
+ } else {
+ val = new Lazy<A> (() => {return current.get ();});
+ return Stream.YIELD;
+ }
+ case Stream.CONTINUE:
+ current = f (item.get ());
+ if (current.valid) {
+ val = new Lazy<A> (() => {return current.get ();});
+ return Stream.YIELD;
+ } else {
+ val = null;
+ return Stream.WAIT;
+ }
+ case Stream.WAIT:
+ if (current.next()) {
+ val = new Lazy<A> (() => {return current.get ();});
+ return Stream.YIELD;
+ } else {
+ val = null;
+ return Stream.CONTINUE;
+ }
+ case Stream.END:
+ val = null;
+ return Stream.END;
+ default:
+ assert_not_reached ();
+ }
+ });
+ }
+
+ /**
+ * Splits the traversable into multiple ones, caching the result if needed.
+ *
+ * Note: In {@link Iterator} implementation using the parent iterator is
+ * not allowed. However if any of the forked iterators {@link next}
+ * return false then it is treated as if the parent iterator
+ * {@link next} returned false.
+ *
+ * Note: The returned arrey might contain parent iterator if it is allowed
+ * by implementation. For example the iteration over collection does
+ * not need to generate and cache the results.
+ * In such case it is recommended to return the value as the first element
+ * of the array. This allows the consumer to check just the first element
+ * if it can perform optimizations for such case. However it //must// not
+ * depend on the order (that's for optimization only).
+ *
+ * Note: The resulting iterators does not need to be thread safe.
+ *
+ * @param forks Number of iterators in array
+ * @return An array with created iterators
+ * @since 0.11.5
+ */
+ [CCode (ordering = 9)]
+ public virtual Iterator<G>[] tee (uint forks) {
+ unowned Iterator<G>? self;
+ unowned Iterable<G>? iself;
+ // Yes - I've heard of polimorphism ;) but I don't want users to need to implement the method.
+ if ((self = this as Iterator<G>) != null) {
+ if (forks == 0) {
+ return new Iterator<G>[0];
+ } else if (forks == 1) {
+ return new Iterator<G>[1]{self};
+ } else {
+ Iterator<G>[] result = new Iterator<G>[forks];
+ Lazy<G>? data;
+ bool is_valid = self.valid;
+ if (is_valid) {
+ data = new Lazy<G>(() => {return self.get ();});
+ } else {
+ data = new Lazy<G>.from_value (null);
+ }
+ var head = new TeeIterator.Node<G> (data, TeeIterator.create_nodes<G> (self,
data));
+ for (uint i = 0; i < forks; i++) {
+ result[i] = new TeeIterator<G> (head, is_valid);
+ }
+ return result;
+ }
+ } else if ((iself = this as Iterable<G>) != null) {
+ var result = new Iterator<G>[forks];
+ for (uint i = 0; i < forks; i++) {
+ result[i] = iself.iterator ();
+ }
+ return result;
+ } else {
+ assert_not_reached ();
+ }
+ }
+
public enum Stream {
YIELD,
CONTINUE,
- END
+ END,
+ WAIT
}
+}
+namespace Vala {
+ // Placed here to workaround bug #703710
+ public delegate Iterator<A> FlatMapFunc<A, G>(owned G g);
}
diff --git a/gee/treemap.vala b/gee/treemap.vala
index bba4809..7d32de8 100644
--- a/gee/treemap.vala
+++ b/gee/treemap.vala
@@ -1,6 +1,6 @@
/* treemap.vala
*
- * Copyright (C) 2009-2011 Maciej Piechotka
+ * Copyright (C) 2009-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -38,7 +38,7 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
public override int size {
get { return _size; }
}
-
+
public override bool read_only {
get { return false; }
}
@@ -92,19 +92,31 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
* The keys' comparator function.
*/
[CCode (notify = false)]
- public CompareDataFunc<K> key_compare_func { private set; get; }
+ public CompareDataFunc<K> key_compare_func {
+ private set {}
+ get {
+ return _key_compare_func.func;
+ }
+ }
/**
* The values' equality testing function.
*/
[CCode (notify = false)]
- public EqualDataFunc<V> value_equal_func { private set; get; }
+ public EqualDataFunc<V> value_equal_func {
+ private set {}
+ get {
+ return _value_equal_func.func;
+ }
+ }
private int _size = 0;
private weak SortedSet<K> _keys;
private weak Collection<V> _values;
private weak SortedSet<Map.Entry<K,V>> _entries;
+ private Functions.CompareDataFuncClosure<K> _key_compare_func;
+ private Functions.EqualDataFuncClosure<V> _value_equal_func;
/**
* Constructs a new, empty tree map sorted according to the specified
@@ -123,8 +135,13 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
if (value_equal_func == null) {
value_equal_func = Functions.get_equal_func_for (typeof (V));
}
- this.key_compare_func = key_compare_func;
- this.value_equal_func = value_equal_func;
+ _key_compare_func = new Functions.CompareDataFuncClosure<K> ((owned)key_compare_func);
+ _value_equal_func = new Functions.EqualDataFuncClosure<V> ((owned)value_equal_func);
+ }
+
+ internal TreeMap.with_closures (owned Functions.CompareDataFuncClosure<K> key_compare_func, owned
Functions.EqualDataFuncClosure<V> value_equal_func) {
+ _key_compare_func = key_compare_func;
+ _value_equal_func = value_equal_func;
}
~TreeMap () {
@@ -442,14 +459,14 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
return entries;
}
}
-
+
/**
* {@inheritDoc}
*/
public override Vala.MapIterator<K,V> map_iterator () {
return new MapIterator<K,V> (this);
}
-
+
/**
* {@inheritDoc}
*/
@@ -457,6 +474,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
return new MapIterator<K,V> (this);
}
+ internal Functions.CompareDataFuncClosure<K> get_key_compare_func_closure () {
+ return _key_compare_func;
+ }
+
[Compact]
private class Node<K, V> {
public enum Color {
@@ -486,6 +507,12 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
}
+ ~Node () {
+ if (entry != null) {
+ entry.remove_weak_pointer ((void**) (&entry));
+ }
+ }
+
public void flip () {
color = color.flip ();
if (left != null) {
@@ -788,8 +815,8 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
}
- private weak SortedSet<Entry<K,V>>? _entries;
- public override Set<Entry<K,V>> entries {
+ private weak SortedSet<Map.Entry<K,V>>? _entries;
+ public override Set<Map.Entry<K,V>> entries {
owned get {
var entries = _entries;
if (_entries == null) {
@@ -833,11 +860,11 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
for (var iterator = map_iterator (); iterator.next ();)
iterator.unset ();
}
-
+
public override Vala.MapIterator<K,V> map_iterator () {
return new SubMapIterator<K,V> (map, range);
}
-
+
public override BidirMapIterator<K,V> bidir_map_iterator () {
return new SubMapIterator<K,V> (map, range);
}
@@ -866,7 +893,7 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
}
- public override SortedSet<K> ascending_entries {
+ public override SortedSet<Map.Entry<K, V>> ascending_entries {
owned get {
var entries = _entries;
if (_entries == null) {
@@ -1241,7 +1268,7 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
return new SubEntrySet<K,V> (_map, new Range<K,V>.tail (_map, after.key));
}
- public override SortedSet<K> sub_set (Map.Entry<K, V> after, Map.Entry<K, V> before) {
+ public override SortedSet<Map.Entry<K, V>> 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));
}
@@ -1322,7 +1349,7 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
return range.in_range(entry.key) && map.has (entry.key, entry.value);
}
- public override BidirIterator<K> bidir_iterator () {
+ public override BidirIterator<Map.Entry<K, V>> bidir_iterator () {
return new SubEntryIterator<K,V> (map, range);
}
@@ -1338,15 +1365,15 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
return Entry.entry_for<K,V> (_last);
}
- public override SortedSet<K> head_set (Map.Entry<K,V> before) {
+ public override SortedSet<Map.Entry<K, V>> head_set (Map.Entry<K,V> before) {
return new SubEntrySet<K,V> (map, range.cut_tail (before.key));
}
- public override SortedSet<K> tail_set (Map.Entry<K,V> after) {
+ public override SortedSet<Map.Entry<K, V>> tail_set (Map.Entry<K,V> after) {
return new SubEntrySet<K,V> (map, range.cut_head (after.key));
}
- public override SortedSet<K> sub_set (Map.Entry<K,V> after, Map.Entry<K,V> before) {
+ public override SortedSet<Map.Entry<K, V>> sub_set (Map.Entry<K,V> after, Map.Entry<K,V>
before) {
return new SubEntrySet<K,V> (map, range.cut (after.key, before.key));
}
@@ -1415,6 +1442,15 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
this.current = current;
}
+ public NodeIterator.from_iterator (NodeIterator<K, V> iter) {
+ _map = iter._map;
+ stamp = iter.stamp;
+ started = iter.started;
+ current = iter.current;
+ _next = iter._next;
+ _prev = iter._prev;
+ }
+
public bool next () {
assert (stamp == _map.stamp);
if (current != null) {
@@ -1539,6 +1575,12 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
this.iterator = new NodeIterator<K,V>.pointing (_map, node);
}
+ public SubNodeIterator.from_iterator (SubNodeIterator<K,V> iter) {
+ _map = iter._map;
+ range = iter.range;
+ iterator = new NodeIterator<K,V>.from_iterator (iter.iterator);
+ }
+
public bool next () {
if (iterator != null) {
weak Node<K,V>? node= iterator.safe_next_get ();
@@ -1637,6 +1679,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, current);
}
+ public KeyIterator.from_iterator (KeyIterator<K, V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new K get () {
assert (stamp == _map.stamp);
assert (current != null);
@@ -1666,6 +1712,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<K>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<K>[0];
+ } else {
+ Vala.Iterator<K>[] result = new Vala.Iterator<K>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new KeyIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class SubKeyIterator<K,V> : SubNodeIterator<K,V>, Traversable<K>, Vala.Iterator<K>,
BidirIterator<K> {
@@ -1677,6 +1736,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, range, node);
}
+ public SubKeyIterator.from_iterator (SubKeyIterator<K, V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new K get () {
assert (valid);
return iterator.current.key;
@@ -1695,6 +1758,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<K>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<K>[0];
+ } else {
+ Vala.Iterator<K>[] result = new Vala.Iterator<K>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new SubKeyIterator<K,V>.from_iterator(this);
+ }
+ return result;
+ }
+ }
}
private class ValueIterator<K,V> : NodeIterator<K,V>, Traversable<V>, Vala.Iterator<V>,
Vala.BidirIterator<V> {
@@ -1706,6 +1782,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, current);
}
+ public ValueIterator.from_iterator (ValueIterator<K,V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new V get () {
assert (stamp == _map.stamp);
assert (valid);
@@ -1735,6 +1815,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<V>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<V>[0];
+ } else {
+ Vala.Iterator<V>[] result = new Vala.Iterator<V>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new ValueIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class SubValueIterator<K,V> : SubNodeIterator<K,V>, Traversable<V>, Vala.Iterator<V>,
BidirIterator<V> {
@@ -1746,6 +1839,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, range, node);
}
+ public SubValueIterator.from_iterator (SubValueIterator<K,V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new V get () {
assert (valid);
return iterator.current.value;
@@ -1764,6 +1861,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<V>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<V>[0];
+ } else {
+ Vala.Iterator<V>[] result = new Vala.Iterator<V>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new SubValueIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class EntryIterator<K,V> : NodeIterator<K,V>, Traversable<Map.Entry<K, V>>,
Vala.Iterator<Map.Entry<K,V>>, Vala.BidirIterator<Map.Entry<K,V>> {
@@ -1775,6 +1885,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, node);
}
+ public EntryIterator.from_iterator (EntryIterator<K,V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new Map.Entry<K,V> get () {
assert (stamp == _map.stamp);
assert (valid);
@@ -1808,6 +1922,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<Map.Entry<K,V>>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<Map.Entry<K,V>>[0];
+ } else {
+ Vala.Iterator<Map.Entry<K,V>>[] result = new
Vala.Iterator<Map.Entry<K,V>>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new EntryIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class SubEntryIterator<K,V> : SubNodeIterator<K,V>, Traversable<Map.Entry<K, V>>,
Vala.Iterator<Map.Entry<K,V>>, Vala.BidirIterator<Map.Entry<K,V>> {
@@ -1819,6 +1946,10 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
base.pointing (map, range, node);
}
+ public SubEntryIterator.from_iterator (SubEntryIterator<K,V> iterator) {
+ base.from_iterator (iterator);
+ }
+
public new Map.Entry<K,V> get () {
assert (iterator != null);
return Entry.entry_for<K,V> (iterator.current);
@@ -1841,6 +1972,19 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
}
return true;
}
+
+ public Vala.Iterator<Map.Entry<K,V>>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Iterator<Map.Entry<K,V>>[0];
+ } else {
+ Vala.Iterator<Map.Entry<K,V>>[] result = new
Vala.Iterator<Map.Entry<K,V>>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new SubEntryIterator<K,V>.from_iterator (this);
+ }
+ return result;
+ }
+ }
}
private class MapIterator<K,V> : NodeIterator<K,V>, Vala.MapIterator<K,V>, BidirMapIterator<K,V> {
@@ -1865,13 +2009,13 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
assert (valid);
current.value = value;
}
-
+
public override bool read_only {
get {
return false;
}
}
-
+
public bool mutable {
get {
return true;
@@ -1898,13 +2042,13 @@ public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
assert (valid);
iterator.current.value = value;
}
-
+
public override bool read_only {
get {
return false;
}
}
-
+
public bool mutable {
get {
return true;
diff --git a/gee/treemultimap.vala b/gee/treemultimap.vala
index 452dd97..97d2915 100644
--- a/gee/treemultimap.vala
+++ b/gee/treemultimap.vala
@@ -30,7 +30,12 @@ public class Vala.TreeMultiMap<K,V> : AbstractMultiMap<K,V> {
}
[CCode (notify = false)]
- public CompareDataFunc<V> value_compare_func { private set; get; }
+ public CompareDataFunc<V> value_compare_func {
+ private set {}
+ get {
+ return _value_compare_func.func;
+ }
+ }
/**
* Constructs a new, empty tree multimap.
@@ -42,22 +47,24 @@ public class Vala.TreeMultiMap<K,V> : AbstractMultiMap<K,V> {
* @param value_compare_func an optional value comparator function
*/
public TreeMultiMap (owned CompareDataFunc<K>? key_compare_func = null, owned CompareDataFunc<V>?
value_compare_func = null) {
- base (new TreeMap<K, Set<V>> (key_compare_func, Functions.get_equal_func_for (typeof (Set))));
+ base (new TreeMap<K, Set<V>> ((owned)key_compare_func, Functions.get_equal_func_for (typeof
(Set))));
if (value_compare_func == null) {
value_compare_func = Functions.get_compare_func_for (typeof (V));
}
- this.value_compare_func = value_compare_func;
+ _value_compare_func = new Functions.CompareDataFuncClosure<V> ((owned)value_compare_func);
}
protected override Collection<V> create_value_storage () {
- return new TreeSet<V> (_value_compare_func);
+ return new TreeSet<V>.with_closures (_value_compare_func);
}
protected override MultiSet<K> create_multi_key_set () {
- return new TreeMultiSet<K> (key_compare_func);
+ return new TreeMultiSet<K>.with_closures (((TreeMap<K, Set<V>>)
_storage_map).get_key_compare_func_closure ());
}
protected override EqualDataFunc<V> get_value_equal_func () {
return Functions.get_equal_func_for (typeof (V));
}
+
+ private Functions.CompareDataFuncClosure<V> _value_compare_func;
}
diff --git a/gee/treemultiset.vala b/gee/treemultiset.vala
index 992d96d..00cb640 100644
--- a/gee/treemultiset.vala
+++ b/gee/treemultiset.vala
@@ -38,6 +38,10 @@ public class Vala.TreeMultiSet<G> : AbstractMultiSet<G> {
* @param compare_func an optional element comparator function
*/
public TreeMultiSet (owned CompareDataFunc<G>? compare_func = null) {
- base (new TreeMap<G, int> (compare_func));
+ base (new TreeMap<G, int> ((owned)compare_func));
+ }
+
+ internal TreeMultiSet.with_closures (owned Functions.CompareDataFuncClosure<G> compare_func) {
+ base (new TreeMap<G, int>.with_closures ((owned)compare_func, new
Functions.EqualDataFuncClosure<int> (Functions.get_equal_func_for (typeof (int)))));
}
}
diff --git a/gee/treeset.vala b/gee/treeset.vala
index 0ea02aa..084c0e5 100644
--- a/gee/treeset.vala
+++ b/gee/treeset.vala
@@ -1,6 +1,6 @@
/* treeset.vala
*
- * Copyright (C) 2009-2011 Maciej Piechotka
+ * Copyright (C) 2009-2014 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -39,7 +39,7 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
public override int size {
get {return _size;}
}
-
+
/**
* {@inheritDoc}
*/
@@ -51,7 +51,12 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
* The elements' comparator function.
*/
[CCode (notify = false)]
- public CompareDataFunc<G> compare_func { private set; get; }
+ public CompareDataFunc<G> compare_func {
+ private set {}
+ get {
+ return _compare_func.func;
+ }
+ }
private int _size = 0;
@@ -68,7 +73,11 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
if (compare_func == null) {
compare_func = Functions.get_compare_func_for (typeof (G));
}
- this.compare_func = compare_func;
+ _compare_func = new Functions.CompareDataFuncClosure<G> ((owned)compare_func);
+ }
+
+ internal TreeSet.with_closures (owned Functions.CompareDataFuncClosure<G> compare_func) {
+ _compare_func = (owned)compare_func;
}
~TreeSet () {
@@ -345,6 +354,18 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
/**
* {@inheritDoc}
*/
+ public override bool foreach (ForallFunc<G> f) {
+ for (unowned Node<G> node = _first; node != null; node = node.next) {
+ if (!f (node.key)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public override Vala.Iterator<G> iterator () {
return new Iterator<G> (this);
}
@@ -578,11 +599,6 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
}
private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G>, BidirIterator<G> {
- private TreeSet<G> _set;
-
- // concurrent modification protection
- private int stamp;
-
public Iterator (TreeSet<G> set) {
_set = set;
stamp = _set.stamp;
@@ -595,6 +611,15 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
this.started = true;
}
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _set = iter._set;
+ stamp = iter.stamp;
+ _current = iter._current;
+ _next = iter._next;
+ _prev = iter._prev;
+ started = iter.started;
+ }
+
public bool next () {
assert (stamp == _set.stamp);
if (_current != null) {
@@ -752,10 +777,25 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
return true;
}
- private weak Node<G>? _current = null;
- private weak Node<G>? _next = null;
- private weak Node<G>? _prev = null;
- private bool started = false;
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected TreeSet<G> _set;
+ protected int stamp;
+ protected weak Node<G>? _current = null;
+ protected weak Node<G>? _next = null;
+ protected weak Node<G>? _prev = null;
+ protected bool started = false;
}
private inline G min (G a, G b) {
@@ -1040,8 +1080,8 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
return h != null && range.in_range (h) ? h : null;
}
- private new TreeSet<G> set;
- private Range<G> range;
+ protected new TreeSet<G> set;
+ protected Range<G> range;
}
private class SubIterator<G> : Object, Traversable<G>, Vala.Iterator<G>, BidirIterator<G> {
@@ -1056,6 +1096,12 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
this.iterator = new Iterator<G>.pointing (set, node);
}
+ public SubIterator.from_iterator (SubIterator<G> iter) {
+ set = iter.set;
+ range = iter.range;
+ iterator = new Iterator<G>.from_iterator (iter.iterator);
+ }
+
public bool next () {
if (iterator != null) {
G next;
@@ -1150,13 +1196,27 @@ public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
return true;
}
- private new TreeSet<G> set;
- private Range<G> range;
- private Iterator<G>? iterator = null;
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new SubIterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ protected new TreeSet<G> set;
+ protected Range<G> range;
+ protected Iterator<G>? iterator = null;
}
private Node<G>? root = null;
private weak Node<G>? _first = null;
private weak Node<G>? _last = null;
private int stamp = 0;
+ private Functions.CompareDataFuncClosure<G> _compare_func;
}
diff --git a/gee/unrolledlinkedlist.vala b/gee/unrolledlinkedlist.vala
new file mode 100644
index 0000000..a316207
--- /dev/null
+++ b/gee/unrolledlinkedlist.vala
@@ -0,0 +1,1152 @@
+/* unrolledlinkedlist.vala
+ *
+ * Copyright (C) 2013-2014 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 Vala.Utils.Assume;
+
+/**
+ * Unrolled doubly-linked list implementation of the {@link List} interface.
+ *
+ * The unrolled doubly-linked list combines the advantages and disadvantages
+ * of the {@link ArrayList} and {@link LinkedList} and is usually suitable when
+ * modifications and read operations are balanced.
+ *
+ * Please note that in our benchmarks the speed of most operations (insertion,
+ * deletion, sequential read) was on par or better then {@link ArrayList} and
+ * {@link LinkedList} except the prepending operation.
+ *
+ * @see ArrayList
+ * @see LinkedList
+ */
+public class Vala.UnrolledLinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
+ /**
+ * The elements' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<G> equal_func {
+ private set {}
+ get {
+ return _equal_func.func;
+ }
+ }
+
+ /**
+ * Constructs a new, empty linked list.
+ *
+ * If not provided, the function parameter is requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param equal_func an optional element equality testing function
+ */
+ public UnrolledLinkedList (owned EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
+ _equal_func = new Functions.EqualDataFuncClosure<G> ((owned)equal_func);
+ }
+
+ private UnrolledLinkedList.with_closures (owned Functions.EqualDataFuncClosure<G> equal_func) {
+ _equal_func = equal_func;
+ }
+
+ ~UnrolledLinkedList () {
+ this.clear ();
+ }
+
+ public override bool foreach (ForallFunc<G> f) {
+#if DUMP
+ stdout.printf ("FOREACH BEGIN %p\n", this);
+ dump ();
+ try {
+#endif
+ for (unowned Node<G>? node = _head; node != null; node = node._next) {
+ for (int pos = 0; pos < node._size; pos++) {
+ if (! f(node._data[pos])) {
+ return false;
+ }
+ }
+ }
+ return true;
+#if DUMP
+ } finally {
+ dump();
+ stdout.printf ("FOREACH END\n");
+ }
+#endif
+ }
+
+ public override int size { get {return _size;} }
+ public override bool read_only { get {return false;} }
+
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ public override bool contains (G item) {
+ return find_node (item) != null;
+ }
+
+ public override bool add (G item) {
+#if DUMP
+ stdout.printf ("ADD BEGIN %p (%s)\n", item, (string)item);
+ dump ();
+#endif
+ if (_tail == null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_head == null);
+#else
+ assume (_head == null);
+#endif
+ _tail = _head = new Node<G>();
+ }
+ add_to_node (_tail, item, _tail._size);
+#if DUMP
+ dump ();
+ stdout.printf ("ADD END\n");
+#endif
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return true;
+ }
+ public override bool remove (G item) {
+ int pos;
+ unowned Node<G>? node = find_node (item, out pos);
+ if (node != null) {
+ remove_from_node (node, pos);
+ }
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return node != null;
+ }
+
+ public override void clear () {
+ for (Node<G>? node = (owned)_head; node != null; node = (owned)node._next) {
+ for (uint pos = 0; pos < node._size; pos++) {
+ node._data[pos] = null;
+ }
+ }
+ _head = null;
+ _tail = null;
+ _stamp++;
+ _size = 0;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ }
+
+ public override ListIterator<G> list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ public override G? get (int index) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+
+ int pos;
+ unowned Node<G>? node = find_node_by_idx (index, out pos);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node != null);
+#endif
+ return node._data[pos];
+ }
+
+ public override void set (int index, G item) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+ int pos;
+ unowned Node<G>? node = find_node_by_idx (index, out pos);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node != null);
+#endif
+ node._data[pos] = item;
+ }
+
+ public override int index_of (G item) {
+ int idx;
+ if (find_node (item, null, out idx) != null) {
+ return idx;
+ } else {
+ return -1;
+ }
+ }
+
+ public override void insert (int index, G item) {
+#if DUMP
+ stdout.printf ("INSERT BEGIN %p (%s)\n", item, (string)item);
+ dump ();
+#endif
+ assert (index >= 0);
+ assert (index <= this._size);
+
+ if (index != this._size) {
+ int pos;
+ unowned Node<G>? node = find_node_by_idx (index, out pos);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node != null);
+#endif
+ add_to_node (node, item, pos);
+ } else {
+ if (index == 0) {
+
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_head == null && _tail == null);
+#else
+ assume (_head == null && _tail == null);
+#endif
+ _tail = _head = new Node<G>();
+ }
+ add_to_node (_tail, item, _tail._size);
+ }
+#if DUMP
+ dump ();
+ stdout.printf ("INSERT END\n");
+#endif
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ }
+
+ public override G remove_at (int index) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+ int pos;
+ unowned Node<G>? node = find_node_by_idx (index, out pos);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node != null);
+#endif
+ return remove_from_node (node, pos);
+ }
+
+ public override List<G>? slice (int start, int stop) {
+ assert (0 <= start && start <= stop && stop <= _size);
+
+ UnrolledLinkedList<G> slice = new UnrolledLinkedList<G>.with_closures (_equal_func);
+ slice._size = stop - start;
+ unowned Node<G>? copy = slice._head = new Node<G> ();
+
+ int orig_pos;
+ unowned Node<G>? orig = find_node_by_idx (start, out orig_pos);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (orig != null);
+#endif
+
+ int i = 0;
+ while (true) {
+ int j = 0;
+ while (j < NODE_SIZE && i < stop - start) {
+ copy._data[j] = orig._data[orig_pos];
+ i++;
+ j++;
+ orig_pos++;
+ if (unlikely (orig_pos == orig._size)) {
+ orig = orig._next;
+ orig_pos = 0;
+ }
+
+ }
+ copy._size = j;
+ if (unlikely (!(i < stop - start))) {
+ break;
+ }
+ copy._next = new Node<G> ();
+ copy._next._prev = copy;
+ copy = copy._next;
+ }
+ slice._tail = copy;
+#if CONSISTENCY_CHECKS
+ slice.check ();
+#endif
+ return slice;
+ }
+
+ public override BidirListIterator<G> bidir_list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ public int capacity { get { return Queue.UNBOUNDED_CAPACITY; } }
+
+ public int remaining_capacity { get { return Queue.UNBOUNDED_CAPACITY; } }
+
+ public bool is_full { get { return false; } }
+
+ public bool offer (G element) {
+ if (_tail == null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_head == null);
+#else
+ assume (_head == null);
+#endif
+ _tail = _head = new Node<G>();
+ }
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_head != null && _tail != null);
+#else
+ assume (_head != null && _tail != null);
+#endif
+ add_to_node (_tail, element, _tail._size);
+ return true;
+ }
+
+ public G? peek () {
+ if (_head != null) {
+ return _head._data[0];
+ } else {
+ return null;
+ }
+ }
+
+ public G? poll () {
+ if (_head != null) {
+ return remove_from_node (_head, 0);
+ } else {
+ return null;
+ }
+ }
+
+ public int drain (Collection<G> recipient, int amount = -1) {
+ int drained = 0;
+ if (amount < 0) {
+ for (Node<G>? node = (owned)_head; node != null; node = (owned)node._next) {
+ for (int i = 0; i < node._size; i++) {
+ G data = (owned)node._data[i];
+ recipient.add (data);
+ }
+ }
+ drained = _size;
+ _tail = null;
+ _size = 0;
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ } else {
+ Node<G>? node;
+ for (node = (owned)_head; node != null; node = (owned)node._next) {
+ if (likely (node._size <= amount)) {
+ for (int i = 0; i < node._size; i++) {
+ G data = (owned)node._data[i];
+ recipient.add (data);
+ }
+ amount -= node._size;
+ drained += node._size;
+ _size -= node._size;
+ } else {
+ for (int i = 0; i < amount; i++) {
+ G data = (owned)node._data[i];
+ recipient.add (data);
+ }
+ Memory.move(node._data, &node._data[amount], sizeof(G) * (node._size
- amount));
+ drained += amount;
+ _size -= amount;
+ node._size -= amount;
+ unowned Node<G>? n = node;
+ _head = (owned)node;
+ if (likely (n._next != null) && unlikely (n._size + n._next._size <
MERGE_THRESHOLD)) {
+ merge_with_next (node);
+ }
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ }
+ }
+ _tail = null;
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ }
+ }
+
+ public bool offer_head (G element) {
+ if (_head == null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_tail == null);
+#else
+ assume (_tail == null);
+#endif
+ _tail = _head = new Node<G>();
+ }
+ add_to_node (_head, element, 0);
+ return true;
+ }
+
+ public G? peek_head () {
+ return peek ();
+ }
+
+ public G? poll_head () {
+ return poll ();
+ }
+
+ public int drain_head (Collection<G> recipient, int amount = -1) {
+ return drain (recipient, amount);
+ }
+
+ public bool offer_tail (G element) {
+ return offer (element);
+ }
+
+ public G? peek_tail () {
+ if (_tail != null) {
+ return _tail._data[_tail._size - 1];
+ } else {
+ return null;
+ }
+ }
+
+ public G? poll_tail () {
+ if (_head != null) {
+ return remove_from_node (_tail, _tail._size - 1);
+ } else {
+ return null;
+ }
+ }
+
+ public int drain_tail (Collection<G> recipient, int amount = -1) {
+ int drained = 0;
+ if (amount < 0) {
+ for (unowned Node<G>? node = _tail; node != null; node = node._prev) {
+ for (int i = node._size; i-- > 0;) {
+ G data = (owned)node._data[i];
+ recipient.add (data);
+ }
+ node._next = null;
+ }
+ drained = _size;
+ _head = null;
+ _tail = null;
+ _size = 0;
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ } else {
+ for (unowned Node<G>? node = _tail; node != null;) {
+ if (node._size <= amount) {
+ for (int i = node._size; i-- > 0;) {
+ G data = (owned)node._data[i];
+ recipient.add (data);
+ }
+ amount -= node._size;
+ drained += node._size;
+ _size -= node._size;
+ node = node._prev;
+ if (node != null) {
+ node._next = null;
+ }
+ } else {
+ for (int i = 0; i < amount; i++) {
+ G data = (owned)node._data[node._size - i - 1];
+ recipient.add (data);
+ }
+ drained += amount;
+ _size -= amount;
+ node._size -= amount;
+ _tail = node;
+ if (likely (node._prev != null) && unlikely (node._size +
node._prev._size < MERGE_THRESHOLD)) {
+ merge_with_next (node._prev);
+ }
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ }
+ }
+ _head = null;
+ _tail = null;
+ _stamp++;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return drained;
+ }
+ }
+
+ private unowned Node<G>? find_node (G item, out int pos = null, out int idx = null) {
+ idx = 0;
+ for (unowned Node<G>? node = _head; node != null; node = node._next) {
+ for (pos = 0; pos < node._size; pos++, idx++) {
+ if (this.equal_func (item, node._data[pos])) {
+ return node;
+ }
+ }
+ }
+ pos = -1;
+ return null;
+ }
+
+ private unowned Node<G>? find_node_by_idx (int idx, out int? pos = null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= idx && idx < _size);
+#else
+ assume (0 <= idx && idx < _size);
+#endif
+ if (idx <= size/2) {
+ for (unowned Node<G>? node = _head; node != null; node = node._next) {
+ if (idx < node._size) {
+ pos = idx;
+ return node;
+ }
+ idx -= node._size;
+ }
+ }
+ else {
+ int start_of_node = _size;
+ int count = 0;
+ for (unowned Node<G>? node = _tail; node != null; node = node._prev) {
+ start_of_node -= node._size;
+ count += node._size;
+ if (idx >= start_of_node) {
+ pos = idx - start_of_node;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= pos && pos < node._size);
+#else
+ assume (0 <= pos && pos < node._size);
+#endif
+ return node;
+ }
+ }
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (start_of_node == 0);
+#endif
+ }
+#if !DISABLE_INTERNAL_ASSERTS
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ assert_not_reached ();
+#else
+ assume (false);
+ pos = -1;
+ return null;
+#endif
+ }
+
+ private void add_to_node (Node<G> node, G item, int pos, out unowned Node<G>? new_node = null, out
int new_pos = null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= pos && pos <= node._size && node._size <= NODE_SIZE);
+#else
+ assume (0 <= pos && pos <= node._size && node._size <= NODE_SIZE);
+#endif
+ if (node._size == NODE_SIZE) {
+ Node<G> next = new Node<G> ();
+ next._next = (owned)node._next;
+ next._prev = node;
+ if (GLib.unlikely (next._next == null)) {
+ _tail = next;
+ } else {
+ next._next._prev = next;
+ }
+ Memory.copy(next._data, &node._data[SPLIT_POS], sizeof(G) * (NODE_SIZE - SPLIT_POS));
+ node._size = SPLIT_POS;
+ next._size = NODE_SIZE - SPLIT_POS;
+ node._next = (owned)next;
+ if (pos > SPLIT_POS) {
+ node = node._next;
+ pos = pos - SPLIT_POS;
+ }
+ }
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= pos && pos <= node._size && node._size < NODE_SIZE);
+#else
+ assume (0 <= pos && pos <= node._size && node._size < NODE_SIZE);
+#endif
+ Memory.move(&node._data[pos + 1], &node._data[pos], sizeof(G) * (node._size - pos));
+ Memory.set(&node._data[pos], 0, sizeof(G));
+ node._data[pos] = item;
+ node._size++;
+ _size++;
+ _stamp++;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node._size <= NODE_SIZE);
+#else
+ assume (node._size <= NODE_SIZE);
+#endif
+ new_node = node;
+ new_pos = pos;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ }
+
+ private G remove_from_node (Node<G> node, int pos, out unowned Node<G>? new_node = null, out int
new_pos = null) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert ((0 <= pos && pos <= node._size) && pos <= NODE_SIZE);
+#else
+ assume ((0 <= pos && pos <= node._size) && pos <= NODE_SIZE);
+#endif
+ G item = (owned)node._data[pos];
+ Memory.move(&node._data[pos], &node._data[pos + 1], sizeof(G) * (node._size - (pos + 1)));
+ node._size--;
+ _size--;
+ _stamp++;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node._size >= 0);
+ assert (_size >= 0);
+#else
+ assume (node._size >= 0);
+ assume (_size >= 0);
+#endif
+ if (unlikely (node._size == 0)) {
+ new_node = node._prev;
+ if (likely (node._prev != null)) {
+ new_pos = node._prev._size - 1;
+ } else {
+ new_pos = -1;
+ }
+ delete_node (node);
+ } else if (likely (node._prev != null) && unlikely (node._size + node._prev._size <
MERGE_THRESHOLD)) {
+ new_node = node._prev;
+ new_pos = node._prev._size + pos - 1;
+ merge_with_next (node._prev);
+ } else if (likely (node._next != null) && unlikely (node._size + node._next._size <
MERGE_THRESHOLD)) {
+ merge_with_next (node);
+ new_node = node;
+ new_pos = pos - 1;
+ } else {
+ if (pos != 0) {
+ new_node = node;
+ new_pos = pos - 1;
+ } else {
+ new_node = node._prev;
+ if (likely (node._prev != null)) {
+ new_pos = node._prev._size - 1;
+ } else {
+ new_pos = -1;
+ }
+ }
+ }
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ return item;
+ }
+
+ private void merge_with_next (Node<G>? node) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node._next != null);
+ assert (node._size + node._next._size <= NODE_SIZE);
+#else
+ assume (node._next != null);
+ assume (node._size + node._next._size <= NODE_SIZE);
+#endif
+ unowned Node<G> next = node._next;
+ Memory.copy(&node._data[node._size], next._data, sizeof(G) * next._size);
+ node._size += next._size;
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (node._size <= NODE_SIZE);
+#else
+ assume (node._size <= NODE_SIZE);
+#endif
+ delete_node (next);
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ }
+
+ private void delete_node (Node<G>? node) {
+ if (likely (node._next != null)) {
+ node._next._prev = node._prev;
+ } else {
+ _tail = node._prev;
+ }
+ if (GLib.likely (node._prev != null)) {
+ node._prev._next = (owned)node._next;
+ } else {
+ _head = (owned)node._next;
+ }
+ }
+
+#if DUMP
+ private void dump () {
+ stdout.printf ("UnrolledLinkedList %p\n Size %d\n", this, _size);
+ for (unowned Node<G>? node = _head; node != null; node = node._next) {
+ stdout.printf (" Node %p\n Prev %p\n Next %p\n", node, node._prev, node._next);
+ for (int i = 0; i < node._size; i++) {
+ stdout.printf (" %d: %p (\"%s\")\n", i, node._data[i],
(string)node._data[i]);
+ }
+ }
+ }
+#endif
+#if CONSISTENCY_CHECKS
+ private void check () {
+ int size = 0;
+ for (unowned Node<G>? node = _head; node != null; node = node._next) {
+ size += node._size;
+ }
+ assert (size == _size);
+ size = 0;
+ for (unowned Node<G>? node = _tail; node != null; node = node._prev) {
+ size += node._size;
+ }
+ assert (size == _size);
+ }
+#endif
+
+ private int _size = 0;
+ private int _stamp = 0;
+ private Node<G>? _head = null;
+ private unowned Node<G>? _tail = null;
+ private Functions.EqualDataFuncClosure<G> _equal_func;
+ private const int NODE_SIZE = 29; // Chosen for node to be multiply cache line (4 on 64 bit and 2 on
32 bit)
+ private const int SPLIT_POS = (NODE_SIZE - 1)/2 + 1;
+ private const int MERGE_THRESHOLD = (NODE_SIZE * 4)/5;
+
+ private class Iterator<G> : Object, Vala.Traversable<G>, Vala.Iterator<G>, ListIterator<G>,
BidirIterator<G>, BidirListIterator<G> {
+ public Iterator (UnrolledLinkedList<G> list) {
+ this._list = list;
+ this._stamp = list._stamp;
+ }
+
+ public Iterator.from_iterator (Iterator<G> iter) {
+ _list = iter._list;
+ _stamp = iter._stamp;
+ _current = iter._current;
+ _pos = iter._pos;
+ _deleted = iter._deleted;
+ _index = iter._index;
+ }
+
+ public new bool foreach (ForallFunc<G> f) {
+#if DUMP
+ stdout.printf ("FOREACH BEGIN [%p -> %p %d]\n", this, _current, _pos);
+ _list.dump ();
+ try {
+#endif
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ unowned Node<G>? current = _current;
+ unowned Node<G>? prev = null;
+ int pos = _pos;
+ int prev_pos = -1;
+ int index = _index;
+ int prev_index = -1;
+ bool deleted = _deleted;
+ if (current == null) {
+ current = _list._head;
+ pos = 0;
+ deleted = false;
+ index = 0;
+ if (unlikely (current == null)) {
+ return true;
+ }
+ } else if (unlikely (deleted)) {
+ if (unlikely(_current._size == _pos + 1)) {
+ if (unlikely (_current._next != null)) {
+ return true;
+ }
+ prev = current;
+ current = _current._next;
+ prev_pos = pos;
+ pos = 0;
+ deleted = false;
+ prev_index = index++;
+ } else {
+ prev = current;
+ prev_pos = pos++;
+ deleted = false;
+ prev_index = index++;
+ }
+ }
+ for (; current != null; prev = current, current = current._next, pos = 0) {
+ int size = current._size;
+ for (; pos < size; prev = current, prev_pos = pos++, prev_index = index++) {
+ deleted = false;
+ if (!f (current._data[pos])) {
+ _current = current;
+ _pos = pos;
+ _deleted = deleted;
+ _index = index;
+ return false;
+ }
+ }
+ }
+ _current = prev;
+ _pos = prev_pos;
+ _deleted = deleted;
+ _index = prev_index;
+ return true;
+#if DUMP
+ } finally {
+ _list.dump ();
+ stdout.printf ("FOREACH END [%p -> %p %d]\n", this, _current, _pos);
+ }
+#endif
+ }
+
+ public Vala.Iterator<G>[] tee (uint forks) {
+ if (forks == 0) {
+ return new Vala.Iterator<G>[0];
+ } else {
+ Vala.Iterator<G>[] result = new Vala.Iterator<G>[forks];
+ result[0] = this;
+ for (uint i = 1; i < forks; i++) {
+ result[i] = new Iterator<G>.from_iterator (this);
+ }
+ return result;
+ }
+ }
+
+ public bool next () {
+#if DUMP
+ stdout.printf ("NEXT BEGIN [%p -> %p %d]\n", this, _current, _pos);
+ _list.dump ();
+ try {
+#endif
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ if (unlikely (_current == null)) {
+ _current = _list._head;
+ if (_current != null) {
+ _pos = 0;
+ _deleted = false;
+ _index = 0;
+ }
+ return _current != null;
+ } else if (unlikely(_current._size == _pos + 1)) {
+ if (likely (_current._next != null)) {
+ _current = _current._next;
+ _pos = 0;
+ _deleted = false;
+ _index++;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ _pos++;
+ _deleted = false;
+ _index++;
+ return true;
+ }
+#if DUMP
+ } finally {
+ _list.dump ();
+ stdout.printf ("NEXT END [%p -> %p %d]\n", this, _current, _pos);
+ }
+#endif
+ }
+
+ public bool has_next () {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ if (unlikely (_current == null)) {
+ return _list._head != null;
+ } else if (unlikely(_current._size == _pos + 1)) {
+ return _current._next != null;
+ } else {
+ return true;
+ }
+ }
+
+ public new G get () {
+ assert (_list._stamp == _stamp);
+ assert (_current != null && !_deleted);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= _pos && _pos < _current._size);
+#else
+ assume (0 <= _pos && _pos < _current._size);
+#endif
+ return _current._data[_pos];
+ }
+
+ public void remove () {
+#if DUMP
+ stdout.printf ("REMOVE BEGIN [%p -> %p %d]\n", this, _current, _pos);
+ _list.dump ();
+#endif
+ assert (_list._stamp == _stamp);
+ assert (_current != null && !_deleted);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= _pos && _pos <= _current._size);
+#else
+ assume (0 <= _pos && _pos <= _current._size);
+#endif
+ _list.remove_from_node (_current, _pos, out _current, out _pos);
+ _deleted = true;
+ _index--;
+ _stamp++;
+#if DUMP
+ _list.dump ();
+ stdout.printf ("REMOVE END [%p -> %p %d]\n", this, _current, _pos);
+#endif
+ }
+
+ public bool valid {
+ get {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ return _current != null && !_deleted;
+ }
+ }
+
+ public bool read_only { get { return false; } }
+
+ public bool previous () {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ if (unlikely (_deleted)) {
+ _deleted = false;
+ return _current != null;
+ } else if (unlikely (_current == null)) {
+ return false;
+ } else if (unlikely (_pos == 0)) {
+ if (likely (_current._prev != null)) {
+ _current = _current._prev;
+ _pos = _current._size - 1;
+ _index--;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ _pos--;
+ _index--;
+ return true;
+ }
+ }
+
+ public bool has_previous () {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ if (unlikely (_deleted)) {
+ return _current != null;
+ } else if (unlikely (_current == null)) {
+ return false;
+ } else if (unlikely (_pos == 0)) {
+ return _current._prev != null;
+ } else {
+ return true;
+ }
+ }
+
+ public bool first () {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ _current = _list._head;
+ _deleted = false;
+ if (_current != null) {
+ _pos = 0;
+ } else {
+ _pos = -1;
+ }
+ _index = 0;
+ return _current != null;
+ }
+
+ public bool last () {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ _current = _list._tail;
+ _deleted = false;
+ if (_current != null) {
+ _pos = _current._size - 1;
+ } else {
+ _pos = -1;
+ }
+ _index = _list._size - 1;
+ return _current != null;
+ }
+
+ public new void set (G item) {
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ _current._data[_pos] = item;
+ _list._stamp++;
+ _stamp++;
+ }
+
+ public void add (G item) {
+#if DUMP
+ stdout.printf ("ADD BEGIN %p (%s) [%p -> %p %d]\n", item, (string)item, this,
_current, _pos);
+ _list.dump ();
+#endif
+ assert (_list._stamp == _stamp);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (!(_current == null) || _pos == -1);
+ assert (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#else
+ assume (!(_current == null) || _pos == -1);
+ assume (!(_current != null) || (0 <= _pos && _pos <= _current._size));
+#endif
+ if (likely (_current != null)) {
+ _list.add_to_node (_current, item, _pos + 1, out _current, out _pos);
+ } else {
+ if (likely (_list._head != null)) {
+ _current = _list._head;
+ } else {
+ _current = _list._tail = _list._head = new Node<G>();
+ }
+ _list.add_to_node (_current, item, 0);
+ _pos = 0;
+ }
+ _stamp++;
+ _index++;
+ _deleted = false;
+#if DUMP
+ _list.dump ();
+ stdout.printf ("ADD END [%p -> %p %d]\n", this, _current, _pos);
+#endif
+ }
+
+ public int index () {
+ assert (_list._stamp == _stamp);
+ assert (_current != null);
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (0 <= _pos && _pos <= _current._size);
+#else
+ assume (0 <= _pos && _pos <= _current._size);
+#endif
+ return _index;
+ }
+
+ public void insert (G item) {
+#if DUMP
+ stdout.printf ("INSERT BEGIN %p (%s) [%p -> %p %d]\n", item, (string)item, this,
_current, _pos);
+ _list.dump ();
+#endif
+ assert (_list._stamp == _stamp);
+
+ if (unlikely (_deleted)) {
+ if (unlikely (_current == null)) {
+ if (likely (_list._head != null)) {
+ _current = _list._head;
+ _pos = -1;
+ } else {
+ _current = _list._tail = _list._head = new Node<G>();
+ _pos = -1;
+ }
+ }
+ _list.add_to_node (_current, item, _pos + 1, out _current, out _pos);
+ if (unlikely (_pos == 0)) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_current._prev != null);
+#endif
+ _current = _current._prev;
+ _pos = _current._prev._size - 1;
+ } else {
+ _pos--;
+ }
+ } else {
+ _list.add_to_node (_current, item, _pos, out _current, out _pos);
+ if (unlikely (_pos + 1 == _current._size)) {
+#if !DISABLE_INTERNAL_ASSERTS
+ assert (_current._next != null);
+#endif
+ _current = _current._next;
+ _pos = 0;
+ } else {
+ _pos++;
+ }
+ }
+ _stamp++;
+ _index++;
+#if DUMP
+ _list.dump ();
+ stdout.printf ("INSERT END [%p -> %p %d]\n", this, _current, _pos);
+#endif
+ }
+
+ private UnrolledLinkedList<G>? _list;
+ private int _stamp;
+ private unowned Node<G>? _current = null;
+ private int _pos = -1;
+ private bool _deleted = false;
+ private int _index = -1;
+ }
+
+ [Compact]
+ private class Node<G> {
+ public unowned Node<G>? _prev = null;
+ public Node<G>? _next = null;
+ public int _size = 0;
+ public G _data[29 /* NODE_SIZE */];
+ }
+}
+
diff --git a/gee/utils/assume.h b/gee/utils/assume.h
new file mode 100644
index 0000000..3ec100b
--- /dev/null
+++ b/gee/utils/assume.h
@@ -0,0 +1,33 @@
+/* assume.h
+ *
+ * Copyright (C) 2013 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>
+ */
+#ifndef VALA_UTILS_ASSUME
+#define VALA_UTILS_ASSUME
+
+#if __GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ >= 40500
+#define vala_utils_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
+#elif defined(_MSC_VER)
+#define vala_utils_assume(cond) __assume(cond)
+#else
+#define vala_utils_assume(cond) NULL
+#endif
+
+#endif
diff --git a/gee/utils/async.h b/gee/utils/async.h
new file mode 100644
index 0000000..9aa3a5a
--- /dev/null
+++ b/gee/utils/async.h
@@ -0,0 +1,31 @@
+/* async.h
+ *
+ * Copyright (C) 2013 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>
+ */
+#ifndef VALA_UTILS_ASYNC
+#define VALA_UTILS_ASYNC
+
+#include <glib.h>
+
+#define vala_utils_async_yield_and_unlock(mutex, callback, user_data) g_mutex_unlock (mutex)
+#define vala_utils_async_yield_and_unlock_finish(arg) do {} while (0)
+
+#endif
+
diff --git a/gee/utils/free.h b/gee/utils/free.h
new file mode 100644
index 0000000..586d212
--- /dev/null
+++ b/gee/utils/free.h
@@ -0,0 +1,30 @@
+/* free.h
+ *
+ * Copyright (C) 2013 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>
+ */
+#ifndef VALA_UTILS_ASYNC
+#define VALA_UTILS_ASYNC
+
+#include <glib.h>
+
+#define vala_utils_free_get_destroy_notify(type, dup, destroy) (destroy)
+
+#endif
+
diff --git a/gee/utils/misc.h b/gee/utils/misc.h
new file mode 100644
index 0000000..7ebb312
--- /dev/null
+++ b/gee/utils/misc.h
@@ -0,0 +1,30 @@
+/* async.h
+ *
+ * Copyright (C) 2013 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>
+ */
+#ifndef VALA_UTILS_MISC
+#define VALA_UTILS_MISC
+
+#include <glib.h>
+
+#define vala_utils_misc_unused(par) (void)par
+
+#endif
+
diff --git a/gee/utils/utils.vapi b/gee/utils/utils.vapi
new file mode 100644
index 0000000..85346a4
--- /dev/null
+++ b/gee/utils/utils.vapi
@@ -0,0 +1,20 @@
+namespace Vala {
+ namespace Utils {
+ namespace Assume {
+ [CCode (cheader_filename = "assume.h", cname = "vala_utils_assume")]
+ public void assume (bool cond);
+ }
+ namespace Async {
+ [CCode (cheader_filename = "async.h")]
+ public async void yield_and_unlock (GLib.Mutex mutex);
+ }
+ namespace Free {
+ [CCode (cheader_filename = "free.h")]
+ public GLib.DestroyNotify? get_destroy_notify<G> ();
+ }
+ namespace Misc {
+ [CCode (cheader_filename = "misc.h", simple_generics = true)]
+ public void unused<G> (G unused);
+ }
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]