[vala/wip/gee: 40/44] Update internal gee from libgee 0.8.8+d531caa9
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/gee: 40/44] Update internal gee from libgee 0.8.8+d531caa9
- Date: Mon, 10 Oct 2016 20:25:19 +0000 (UTC)
commit 05a9da8d5f9335d4a04b6f673eaf96c57be33ea5
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Mon Aug 25 13:24:07 2014 +0200
Update internal gee from libgee 0.8.8+d531caa9
Based on patch by Maciej Piechotka
https://bugzilla.gnome.org/show_bug.cgi?id=704754
ccode/valaccodefile.vala | 4 +-
codegen/valaccodebasemodule.vala | 22 +-
codegen/valaccodedelegatemodule.vala | 8 +-
codegen/valaccodemethodcallmodule.vala | 8 +-
codegen/valaccodemethodmodule.vala | 22 +-
codegen/valagasyncmodule.vala | 36 +-
codegen/valagdbusclientmodule.vala | 8 +-
codegen/valagirwriter.vala | 18 +-
codegen/valagtkmodule.vala | 12 +-
codegen/valagtypemodule.vala | 6 +-
gee/Makefile.am | 54 +-
gee/abstractbidirlist.vala | 46 +
gee/abstractbidirsortedmap.vala | 53 +
gee/abstractbidirsortedset.vala | 53 +
gee/abstractcollection.vala | 89 ++
gee/abstractlist.vala | 85 ++
gee/abstractmap.vala | 131 +++
gee/abstractmultimap.vala | 311 ++++++
gee/abstractmultiset.vala | 180 +++
gee/abstractqueue.vala | 55 +
gee/abstractset.vala | 50 +
gee/abstractsortedmap.vala | 65 ++
gee/abstractsortedset.vala | 98 ++
gee/arraylist.vala | 298 +++++-
gee/arrayqueue.vala | 342 ++++++
gee/bidiriterator.vala | 55 +
gee/bidirlist.vala | 35 +
gee/bidirlistiterator.vala | 30 +
gee/bidirmapiterator.vala | 56 +
gee/bidirsortedmap.vala | 45 +
gee/bidirsortedset.vala | 46 +
gee/collection.vala | 241 ++++-
gee/comparable.vala | 37 +
gee/concurrentlist.vala | 587 ++++++++++
gee/deque.vala | 123 ++
gee/functions.vala | 152 +++
gee/hashable.vala | 44 +
gee/hashmap.vala | 618 ++++++++---
gee/hashmultimap.vala | 76 ++
gee/hashmultiset.vala | 47 +
gee/hashset.vala | 221 +++-
gee/hazardpointer.vala | 775 +++++++++++++
gee/iterable.vala | 12 +-
gee/iterator.vala | 86 ++-
gee/lazy.vala | 60 +
gee/linkedlist.vala | 690 ++++++++++++
gee/list.vala | 90 ++-
gee/listiterator.vala | 44 +
gee/map.vala | 197 +++-
gee/mapiterator.vala | 111 ++-
gee/multimap.vala | 127 +++
gee/multiset.vala | 36 +
gee/priorityqueue.vala | 1207 ++++++++++++++++++++
gee/queue.vala | 115 ++
gee/readonlybidirlist.vala | 73 ++
gee/readonlybidirsortedmap.vala | 80 ++
gee/readonlybidirsortedset.vala | 71 ++
gee/readonlycollection.vala | 235 ++++
gee/readonlylist.vala | 149 +++
gee/readonlymap.vala | 297 +++++
gee/readonlyset.vala | 50 +
gee/readonlysortedmap.vala | 90 ++
gee/readonlysortedset.vala | 123 ++
gee/set.vala | 19 +-
gee/sortedmap.vala | 66 ++
gee/sortedset.vala | 137 +++
gee/timsort.vala | 713 ++++++++++++
gee/traversable.vala | 379 +++++++
gee/treemap.vala | 1914 ++++++++++++++++++++++++++++++++
gee/treemultimap.vala | 63 ++
gee/treemultiset.vala | 43 +
gee/treeset.vala | 1162 +++++++++++++++++++
gee/unfolditerator.vala | 102 ++
vala/valaattribute.vala | 4 +-
vala/valacodecontext.vala | 4 +-
vala/valacodenode.vala | 2 +-
vala/valacodewriter.vala | 2 +-
vala/valaflowanalyzer.vala | 2 +-
vala/valagirparser.vala | 18 +-
vala/valamarkupreader.vala | 6 +-
vala/valascope.vala | 4 +-
vala/valaswitchstatement.vala | 2 +-
vala/valausedattr.vala | 6 +-
vapigen/valagidlparser.vala | 26 +-
vapigen/valavapicheck.vala | 2 +-
85 files changed, 13457 insertions(+), 404 deletions(-)
---
diff --git a/ccode/valaccodefile.vala b/ccode/valaccodefile.vala
index 128cd39..0b256e5 100644
--- a/ccode/valaccodefile.vala
+++ b/ccode/valaccodefile.vala
@@ -24,8 +24,8 @@
public class Vala.CCodeFile {
public bool is_header { get; set; }
- Set<string> declarations = new HashSet<string> (str_hash, str_equal);
- Set<string> includes = new HashSet<string> (str_hash, str_equal);
+ Set<string> declarations = new HashSet<string> ();
+ Set<string> includes = new HashSet<string> ();
CCodeFragment comments = new CCodeFragment ();
CCodeFragment include_directives = new CCodeFragment ();
CCodeFragment type_declaration = new CCodeFragment ();
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 32f461a..4645955 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -38,8 +38,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
public int next_temp_var_id;
public bool current_method_inner_error;
public bool current_method_return;
- public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash,
str_equal);
- public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash,
str_equal);
+ public Map<string,string> variable_name_map = new HashMap<string,string> ();
+ public Map<string,int> closure_variable_count_map = new HashMap<string,int> ();
public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
public EmitContext (Symbol? symbol = null) {
@@ -341,7 +341,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
public static int ccode_attribute_cache_index = CodeNode.get_attribute_cache_index ();
public CCodeBaseModule () {
- predefined_marshal_set = new HashSet<string> (str_hash, str_equal);
+ predefined_marshal_set = new HashSet<string> ();
predefined_marshal_set.add ("VOID:VOID");
predefined_marshal_set.add ("VOID:BOOLEAN");
predefined_marshal_set.add ("VOID:CHAR");
@@ -361,7 +361,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
predefined_marshal_set.add ("VOID:UINT,POINTER");
predefined_marshal_set.add ("BOOLEAN:FLAGS");
- reserved_identifiers = new HashSet<string> (str_hash, str_equal);
+ reserved_identifiers = new HashSet<string> ();
// C99 keywords
reserved_identifiers.add ("_Bool");
@@ -712,7 +712,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
public override void visit_source_file (SourceFile source_file) {
cfile = new CCodeFile ();
- user_marshal_set = new HashSet<string> (str_hash, str_equal);
+ user_marshal_set = new HashSet<string> ();
next_regex_id = 0;
@@ -723,7 +723,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
requires_array_length = false;
requires_clear_mutex = false;
- wrappers = new HashSet<string> (str_hash, str_equal);
+ wrappers = new HashSet<string> ();
generated_external_symbols = new HashSet<Symbol> ();
header_file.add_include ("glib.h");
@@ -2269,7 +2269,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
return "result";
}
// compiler-internal variable
- if (!variable_name_map.contains (name)) {
+ if (!variable_name_map.has_key (name)) {
variable_name_map.set (name, "_tmp%d_".printf (next_temp_var_id));
next_temp_var_id++;
}
@@ -4566,7 +4566,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
generate_type_declaration (expr.type_reference, cfile);
- var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var in_arg_map = new HashMap<int,CCodeExpression> ();
var out_arg_map = in_arg_map;
if (m != null && m.coroutine) {
@@ -4578,7 +4578,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
creation_call = finish_call;
// output arguments used separately
- out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ out_arg_map = new HashMap<int,CCodeExpression> ();
// pass GAsyncResult stored in closure to finish function
out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new
CCodeIdentifier ("_data_"), "_res_"));
}
@@ -4712,7 +4712,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
last_pos = -1;
while (true) {
min_pos = -1;
- foreach (int pos in out_arg_map.get_keys ()) {
+ foreach (int pos in out_arg_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
@@ -4729,7 +4729,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
last_pos = -1;
while (true) {
min_pos = -1;
- foreach (int pos in in_arg_map.get_keys ()) {
+ foreach (int pos in in_arg_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index f97420f..e278360 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -207,7 +207,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
push_function (function);
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
if (d.has_target) {
var cparam = new CCodeParameter ("self", "gpointer");
@@ -268,7 +268,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
int min_pos;
while (true) {
min_pos = -1;
- foreach (int pos in cparam_map.get_keys ()) {
+ foreach (int pos in cparam_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
@@ -283,7 +283,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
// definition
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var carg_map = new HashMap<int,CCodeExpression> ();
int i = 0;
if (m.binding == MemberBinding.INSTANCE || m.closure) {
@@ -392,7 +392,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
last_pos = -1;
while (true) {
min_pos = -1;
- foreach (int pos in carg_map.get_keys ()) {
+ foreach (int pos in carg_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 8e923ea..e1a4cae 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -78,7 +78,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
deleg = ((DelegateType) itype).delegate_symbol;
}
- var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var in_arg_map = new HashMap<int,CCodeExpression> ();
var out_arg_map = in_arg_map;
if (m != null && m.coroutine) {
@@ -120,7 +120,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
ccall = finish_call;
// output arguments used separately
- out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ out_arg_map = new HashMap<int,CCodeExpression> ();
// pass GAsyncResult stored in closure to finish function
out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new
CCodeIdentifier ("_data_"), "_res_"));
}
@@ -657,7 +657,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
last_pos = -1;
while (true) {
min_pos = -1;
- foreach (int pos in out_arg_map.get_keys ()) {
+ foreach (int pos in out_arg_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
@@ -674,7 +674,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
last_pos = -1;
while (true) {
min_pos = -1;
- foreach (int pos in in_arg_map.get_keys ()) {
+ foreach (int pos in in_arg_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index d147eb1..2bc181d 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -173,8 +173,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
function.modifiers |= CCodeModifiers.DEPRECATED;
}
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
var cl = m.parent_symbol as Class;
@@ -198,7 +198,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
function.modifiers |= CCodeModifiers.INTERNAL;
}
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
bool etv_tmp = ellipses_to_valist;
ellipses_to_valist = false;
generate_cparameters (m, decl_space, cparam_map, function);
@@ -210,7 +210,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
// _constructv function
function = new CCodeFunction (get_ccode_constructv_name ((CreationMethod) m));
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, function);
decl_space.add_function_declaration (function);
@@ -416,7 +416,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
function.modifiers |= CCodeModifiers.INLINE;
}
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, cfile, cparam_map, function);
@@ -815,8 +815,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
* emitter! */
m.signal_reference == null) {
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
generate_vfunc (m, creturn_type, cparam_map, carg_map);
}
@@ -1015,7 +1015,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
int min_pos;
while (true) {
min_pos = -1;
- foreach (int pos in cparam_map.get_keys ()) {
+ foreach (int pos in cparam_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
@@ -1193,8 +1193,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
vfunc.modifiers |= CCodeModifiers.INTERNAL;
}
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
push_function (vfunc);
@@ -1214,7 +1214,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
if (m.is_variadic ()) {
int last_pos = -1;
int second_last_pos = -1;
- foreach (int pos in cparam_map.get_keys ()) {
+ foreach (int pos in cparam_map.keys) {
if (pos > last_pos) {
second_last_pos = last_pos;
last_pos = pos;
diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala
index 928e67b..63469f1 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -155,7 +155,7 @@ public class Vala.GAsyncModule : GtkModule {
var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void");
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
@@ -304,8 +304,8 @@ public class Vala.GAsyncModule : GtkModule {
var cl = m.parent_symbol as Class;
var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
if (m.is_private_symbol ()) {
asyncfunc.modifiers |= CCodeModifiers.STATIC;
@@ -321,8 +321,8 @@ public class Vala.GAsyncModule : GtkModule {
}
var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
+ carg_map = new HashMap<int,CCodeExpression> ();
if (m.is_private_symbol ()) {
finishfunc.modifiers |= CCodeModifiers.STATIC;
@@ -347,7 +347,7 @@ public class Vala.GAsyncModule : GtkModule {
function.modifiers |= CCodeModifiers.INTERNAL;
}
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, function, null, null, null,
1);
decl_space.add_function_declaration (function);
@@ -360,7 +360,7 @@ public class Vala.GAsyncModule : GtkModule {
function.modifiers |= CCodeModifiers.INTERNAL;
}
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, function, null, null, null,
2);
decl_space.add_function_declaration (function);
@@ -406,12 +406,12 @@ public class Vala.GAsyncModule : GtkModule {
if (m.is_abstract || m.is_virtual) {
// generate virtual function wrappers
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
+ carg_map = new HashMap<int,CCodeExpression> ();
generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
}
} else {
@@ -437,8 +437,8 @@ public class Vala.GAsyncModule : GtkModule {
if (current_type_symbol is Class && !current_class.is_compact &&
!current_class.is_abstract) {
var vfunc = new CCodeFunction (get_ccode_name (m));
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
+ var carg_map = new HashMap<int,CCodeExpression> ();
push_function (vfunc);
@@ -459,8 +459,8 @@ public class Vala.GAsyncModule : GtkModule {
vfunc = new CCodeFunction (get_ccode_finish_name (m));
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
+ carg_map = new HashMap<int,CCodeExpression> ();
push_function (vfunc);
@@ -489,7 +489,7 @@ public class Vala.GAsyncModule : GtkModule {
var finishfunc = new CCodeFunction (get_ccode_finish_real_name (m));
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
@@ -637,7 +637,7 @@ public class Vala.GAsyncModule : GtkModule {
// add vfunc field to the type struct
var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator,
null, null, 1);
@@ -647,7 +647,7 @@ public class Vala.GAsyncModule : GtkModule {
// add vfunc field to the type struct
vdeclarator = new CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m));
- cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator,
null, null, 2);
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index 7ec2387..b12c958 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -48,7 +48,7 @@ public class Vala.GDBusClientModule : GDBusModule {
var func = new CCodeFunction (get_ccode_name (method));
func.modifiers = CCodeModifiers.STATIC;
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (method, cfile, cparam_map, func);
@@ -861,7 +861,7 @@ public class Vala.GDBusClientModule : GDBusModule {
var function = new CCodeFunction (proxy_name);
function.modifiers = CCodeModifiers.STATIC;
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, cfile, cparam_map, function);
@@ -885,7 +885,7 @@ public class Vala.GDBusClientModule : GDBusModule {
var function = new CCodeFunction (proxy_name, "void");
function.modifiers = CCodeModifiers.STATIC;
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
@@ -910,7 +910,7 @@ public class Vala.GDBusClientModule : GDBusModule {
var function = new CCodeFunction (proxy_name);
function.modifiers = CCodeModifiers.STATIC;
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
diff --git a/codegen/valagirwriter.vala b/codegen/valagirwriter.vala
index 3f4d15d..205c933 100644
--- a/codegen/valagirwriter.vala
+++ b/codegen/valagirwriter.vala
@@ -102,10 +102,10 @@ public class Vala.GIRWriter : CodeVisitor {
StringBuilder buffer = new StringBuilder();
FileStream stream;
- Vala.HashSet<Namespace> unannotated_namespaces = new Vala.HashSet<Namespace>();
- Vala.HashSet<Namespace> our_namespaces = new Vala.HashSet<Namespace>();
- Vala.ArrayList<Vala.Symbol> hierarchy = new Vala.ArrayList<Vala.Symbol>();
- Vala.ArrayList<Vala.CodeNode> deferred = new Vala.ArrayList<Vala.CodeNode>();
+ HashSet<Namespace> unannotated_namespaces = new HashSet<Namespace>();
+ HashSet<Namespace> our_namespaces = new HashSet<Namespace>();
+ ArrayList<Vala.Symbol> hierarchy = new ArrayList<Vala.Symbol>();
+ ArrayList<Vala.CodeNode> deferred = new ArrayList<Vala.CodeNode>();
int indent;
@@ -123,7 +123,7 @@ public class Vala.GIRWriter : CodeVisitor {
}
}
- private ArrayList<GIRNamespace?> externals = new ArrayList<GIRNamespace?> ((EqualFunc<GIRNamespace>)
GIRNamespace.equal);
+ private ArrayList<GIRNamespace?> externals = new ArrayList<GIRNamespace?> ((a, b) => { return a.equal
(b); });
public void write_includes() {
foreach (var i in externals) {
@@ -214,11 +214,11 @@ public class Vala.GIRWriter : CodeVisitor {
private void write_c_includes (Namespace ns) {
// Collect C header filenames
- Set<string> header_filenames = new HashSet<string> (str_hash, str_equal);
+ Set<string> header_filenames = new HashSet<string> ();
foreach (string c_header_filename in CCodeBaseModule.get_ccode_header_filenames (ns).split
(",")) {
header_filenames.add (c_header_filename);
}
- foreach (Symbol symbol in ns.scope.get_symbol_table ().get_values ()) {
+ foreach (Symbol symbol in ns.scope.get_symbol_table ().values) {
foreach (string c_header_filename in CCodeBaseModule.get_ccode_header_filenames
(symbol).split (",")) {
header_filenames.add (c_header_filename);
}
@@ -621,7 +621,7 @@ public class Vala.GIRWriter : CodeVisitor {
private void visit_deferred () {
var nodes = this.deferred;
- this.deferred = new Vala.ArrayList<Vala.CodeNode>();
+ this.deferred = new ArrayList<Vala.CodeNode>();
foreach (var node in nodes) {
node.accept (this);
@@ -1361,7 +1361,7 @@ public class Vala.GIRWriter : CodeVisitor {
private void write_annotations (CodeNode node) {
foreach (Attribute attr in node.attributes) {
string name = camel_case_to_canonical (attr.name);
- foreach (string arg_name in attr.args.get_keys ()) {
+ foreach (string arg_name in attr.args.keys) {
string value = attr.args.get (arg_name);
if (value.has_prefix ("\"")) {
// eval string
diff --git a/codegen/valagtkmodule.vala b/codegen/valagtkmodule.vala
index 07c022e..6799ee9 100644
--- a/codegen/valagtkmodule.vala
+++ b/codegen/valagtkmodule.vala
@@ -28,9 +28,9 @@ public class Vala.GtkModule : GSignalModule {
/* GResource name to real file name mapping */
private HashMap<string, string> gresource_to_file_map = null;
/* GtkBuilder xml handler to Vala signal mapping */
- private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>(str_hash,
str_equal);
+ private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>();
/* GtkBuilder xml child to Vala class mapping */
- private HashMap<string, Class> current_child_to_class_map = new HashMap<string, Class>(str_hash,
str_equal);
+ private HashMap<string, Class> current_child_to_class_map = new HashMap<string, Class>();
/* Required custom application-specific gtype classes to be ref'd before initializing the template */
private HashSet<Class> current_required_app_classes = new HashSet<Class>();
@@ -39,7 +39,7 @@ public class Vala.GtkModule : GSignalModule {
if (cclass_to_vala_map != null) {
return;
}
- cclass_to_vala_map = new HashMap<string, Class>(str_hash, str_equal);
+ cclass_to_vala_map = new HashMap<string, Class>();
recurse_cclass_to_vala_map (context.root);
}
@@ -59,7 +59,7 @@ public class Vala.GtkModule : GSignalModule {
if (gresource_to_file_map != null) {
return;
}
- gresource_to_file_map = new HashMap<string, string>(str_hash, str_equal);
+ gresource_to_file_map = new HashMap<string, string>();
foreach (var gresource in context.gresources) {
if (!FileUtils.test (gresource, FileTest.EXISTS)) {
Report.error (null, "GResources file `%s' does not exist".printf (gresource));
@@ -107,8 +107,8 @@ public class Vala.GtkModule : GSignalModule {
Report.error (node.source_reference, "UI resource not found: `%s'. Please make sure
to specify the proper GResources xml files with --gresources.".printf (ui_resource));
return;
}
- current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
- current_child_to_class_map = new HashMap<string, Class>(str_hash, str_equal);
+ current_handler_to_signal_map = new HashMap<string, Signal>();
+ current_child_to_class_map = new HashMap<string, Class>();
MarkupReader reader = new MarkupReader (ui_file);
Class current_class = null;
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index b732886..0e8ff0d 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -392,7 +392,7 @@ public class Vala.GTypeModule : GErrorModule {
// add vfunc field to the type struct
var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator);
@@ -1492,7 +1492,7 @@ public class Vala.GTypeModule : GErrorModule {
string cast_args = get_ccode_name (base_type) + "*";
var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var cparam_map = new HashMap<int,CCodeParameter> ();
generate_cparameters (m, cfile, cparam_map, new CCodeFunction ("fake"), vdeclarator);
@@ -1501,7 +1501,7 @@ public class Vala.GTypeModule : GErrorModule {
int min_pos;
while (true) {
min_pos = -1;
- foreach (int pos in cparam_map.get_keys ()) {
+ foreach (int pos in cparam_map.keys) {
if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
min_pos = pos;
}
diff --git a/gee/Makefile.am b/gee/Makefile.am
index db4e75b..e57a70c 100644
--- a/gee/Makefile.am
+++ b/gee/Makefile.am
@@ -14,16 +14,68 @@ noinst_LTLIBRARIES = \
$(NULL)
libgee_la_VALASOURCES = \
+ abstractbidirlist.vala \
+ abstractbidirsortedmap.vala \
+ abstractbidirsortedset.vala \
+ abstractcollection.vala \
+ abstractlist.vala \
+ abstractmap.vala \
+ abstractmultimap.vala \
+ abstractmultiset.vala \
+ abstractqueue.vala \
+ abstractset.vala \
+ abstractsortedmap.vala \
+ abstractsortedset.vala \
arraylist.vala \
+ arrayqueue.vala \
+ bidiriterator.vala \
+ bidirlistiterator.vala \
+ bidirlist.vala \
+ bidirmapiterator.vala \
+ bidirsortedmap.vala \
+ bidirsortedset.vala \
collection.vala \
+ comparable.vala \
+ concurrentlist.vala \
+ deque.vala \
+ functions.vala \
+ hashable.vala \
hashmap.vala \
+ hashmultimap.vala \
+ hashmultiset.vala \
hashset.vala \
+ hazardpointer.vala \
iterable.vala \
- mapiterator.vala \
iterator.vala \
+ lazy.vala \
+ linkedlist.vala \
+ listiterator.vala \
list.vala \
+ mapiterator.vala \
map.vala \
+ multimap.vala \
+ multiset.vala \
+ priorityqueue.vala \
+ queue.vala \
+ readonlybidirlist.vala \
+ readonlybidirsortedmap.vala \
+ readonlybidirsortedset.vala \
+ readonlycollection.vala \
+ readonlylist.vala \
+ readonlymap.vala \
+ readonlyset.vala \
+ readonlysortedmap.vala \
+ readonlysortedset.vala \
set.vala \
+ sortedmap.vala \
+ sortedset.vala \
+ timsort.vala \
+ traversable.vala \
+ treemap.vala \
+ treemultimap.vala \
+ treemultiset.vala \
+ treeset.vala \
+ unfolditerator.vala \
$(NULL)
libgee_la_SOURCES = \
diff --git a/gee/abstractbidirlist.vala b/gee/abstractbidirlist.vala
new file mode 100644
index 0000000..41040f5
--- /dev/null
+++ b/gee/abstractbidirlist.vala
@@ -0,0 +1,46 @@
+/* bidirlistiterator.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+public abstract class Vala.AbstractBidirList<G> : AbstractList<G>, BidirList<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract BidirListIterator<G> bidir_list_iterator ();
+
+ private weak BidirList<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new BidirList<G> read_only_view {
+ owned get {
+ BidirList<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyBidirList<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
+
diff --git a/gee/abstractbidirsortedmap.vala b/gee/abstractbidirsortedmap.vala
new file mode 100644
index 0000000..2290c17
--- /dev/null
+++ b/gee/abstractbidirsortedmap.vala
@@ -0,0 +1,53 @@
+/* abstractbidirsortedmap.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+/**
+ * Skeletal implementation of the {@link BidirSortedSet} interface.
+ *
+ * Contains common code shared by all set implementations.
+ *
+ * @see TreeSet
+ */
+public abstract class Vala.AbstractBidirSortedMap<K,V> : Vala.AbstractSortedMap<K,V>, BidirSortedMap<K,V> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract BidirMapIterator<K,V> bidir_map_iterator ();
+
+ private weak BidirSortedMap<K,V> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new BidirSortedMap<K,V> read_only_view {
+ owned get {
+ BidirSortedMap<K,V> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyBidirSortedMap<K,V> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
+
diff --git a/gee/abstractbidirsortedset.vala b/gee/abstractbidirsortedset.vala
new file mode 100644
index 0000000..219664a
--- /dev/null
+++ b/gee/abstractbidirsortedset.vala
@@ -0,0 +1,53 @@
+/* abstractbidirsortedset.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+/**
+ * Skeletal implementation of the {@link BidirSortedSet} interface.
+ *
+ * Contains common code shared by all set implementations.
+ *
+ * @see TreeSet
+ */
+public abstract class Vala.AbstractBidirSortedSet<G> : Vala.AbstractSortedSet<G>, BidirSortedSet<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract BidirIterator<G> bidir_iterator ();
+
+ private weak BidirSortedSet<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new BidirSortedSet<G> read_only_view {
+ owned get {
+ BidirSortedSet<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyBidirSortedSet<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
+
diff --git a/gee/abstractcollection.vala b/gee/abstractcollection.vala
new file mode 100644
index 0000000..a2421ce
--- /dev/null
+++ b/gee/abstractcollection.vala
@@ -0,0 +1,89 @@
+/* abstractcollection.vala
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes' Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link Collection} interface.
+ *
+ * Contains common code shared by all collection implementations.
+ *
+ * @see AbstractList
+ * @see AbstractSet
+ * @see AbstractMultiSet
+ */
+public abstract class Vala.AbstractCollection<G> : Object, Traversable<G>, Iterable<G>, Collection<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract int size { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool read_only { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool contains (G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool add (G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool remove (G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void clear ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Iterator<G> iterator ();
+
+ public virtual bool foreach (ForallFunc<G> f) {
+ return iterator ().foreach (f);
+ }
+
+ private weak Collection<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual Collection<G> read_only_view {
+ owned get {
+ Collection<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyCollection<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
diff --git a/gee/abstractlist.vala b/gee/abstractlist.vala
new file mode 100644
index 0000000..581ad7f
--- /dev/null
+++ b/gee/abstractlist.vala
@@ -0,0 +1,85 @@
+/* abstractlist.vala
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes' Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link List} interface.
+ *
+ * Contains common code shared by all list implementations.
+ *
+ * @see ArrayList
+ * @see LinkedList
+ */
+public abstract class Vala.AbstractList<G> : Vala.AbstractCollection<G>, List<G> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract ListIterator<G> list_iterator ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract new G? get (int index);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract new void set (int index, G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract int index_of (G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void insert (int index, G item);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G remove_at (int index);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract List<G>? slice (int start, int stop);
+
+ private weak List<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new List<G> read_only_view {
+ owned get {
+ List<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyList<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
diff --git a/gee/abstractmap.vala b/gee/abstractmap.vala
new file mode 100644
index 0000000..bc24604
--- /dev/null
+++ b/gee/abstractmap.vala
@@ -0,0 +1,131 @@
+/* abstractmap.vala
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ * Tomaž Vajngerl <quikee gmail com>
+ */
+
+/**
+ * Skeletal implementation of the {@link Map} interface.
+ *
+ * Contains common code shared by all map implementations.
+ *
+ * @see HashMap
+ * @see TreeMap
+ */
+public abstract class Vala.AbstractMap<K,V> : Object, Traversable<Map.Entry<K,V>>, Iterable<Map.Entry<K,V>>,
Map<K,V> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract int size { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool read_only { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Set<K> keys { owned get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Collection<V> values { owned get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Set<Map.Entry<K,V>> entries { owned get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool has_key (K key);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool has (K key, V value);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract new V? get (K key);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract new void set (K key, V value);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool unset (K key, out V? value = null);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract MapIterator<K,V> map_iterator ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void clear ();
+
+ private weak Map<K,V> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual Map<K,V> read_only_view {
+ owned get {
+ Map<K,V> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlyMap<K,V> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Map.Entry<K,V>> iterator () {
+ return entries.iterator ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual bool foreach (ForallFunc<Map.Entry<K,V>> f) {
+ return iterator ().foreach (f);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual Iterator<A> stream<A> (owned StreamFunc<Map.Entry<K,V>, A> f) {
+ return iterator ().stream<A> ((owned) f);
+ }
+}
diff --git a/gee/abstractmultimap.vala b/gee/abstractmultimap.vala
new file mode 100644
index 0000000..9c96c70
--- /dev/null
+++ b/gee/abstractmultimap.vala
@@ -0,0 +1,311 @@
+/* abstractmultimap.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link MultiMap} interface.
+ *
+ * @see HashMultiMap
+ * @see TreeMultiMap
+ */
+public abstract class Vala.AbstractMultiMap<K,V> : Object, MultiMap<K,V> {
+ public int size {
+ get { return _nitems; }
+ }
+
+ public bool read_only {
+ get { return false; }
+ }
+
+ protected Map<K, Collection<V>> _storage_map;
+ private int _nitems = 0;
+
+ public AbstractMultiMap (Map<K, Collection<V>> storage_map) {
+ this._storage_map = storage_map;
+ }
+
+ public Set<K> get_keys () {
+ return _storage_map.keys;
+ }
+
+ public MultiSet<K> get_all_keys () {
+ return new AllKeys<K, V> (this);
+ }
+
+ public Collection<V> get_values () {
+ return new Values<K, V> (this);
+ }
+
+ public bool contains (K key) {
+ return _storage_map.has_key (key);
+ }
+
+ public new Collection<V> get (K key) {
+ Collection<V>? col = _storage_map.get (key);
+ return col != null ? col.read_only_view : Set.empty<V> ();
+ }
+
+ public new void set (K key, V value) {
+ if (_storage_map.has_key (key)) {
+ if (_storage_map.get (key).add (value)) {
+ _nitems++;
+ }
+ } else {
+ var s = create_value_storage ();
+ s.add (value);
+ _storage_map.set (key, s);
+ _nitems++;
+ }
+ }
+
+ public bool remove (K key, V value) {
+ if (_storage_map.has_key (key)) {
+ var values = _storage_map.get (key);
+ if (values.contains (value)) {
+ values.remove (value);
+ _nitems--;
+ if (values.size == 0) {
+ _storage_map.unset (key);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool remove_all (K key) {
+ if (_storage_map.has_key (key)) {
+ int size = _storage_map.get (key).size;
+ if (_storage_map.unset (key)) {
+ _nitems -= size;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void clear () {
+ _storage_map.clear ();
+ _nitems = 0;
+ }
+
+ public Vala.MapIterator<K, V> map_iterator () {
+ return new MapIterator<K, V> (_storage_map.map_iterator ());
+ }
+
+ protected abstract Collection<V> create_value_storage ();
+
+ protected abstract MultiSet<K> create_multi_key_set ();
+
+ protected abstract EqualDataFunc<V> get_value_equal_func ();
+
+ private class AllKeys<K, V> : AbstractCollection<K>, MultiSet<K> {
+ protected AbstractMultiMap<K, V> _multi_map;
+
+ public AllKeys (AbstractMultiMap<K, V> multi_map) {
+ _multi_map = multi_map;
+ }
+
+ public override Vala.Iterator<K> iterator () {
+ return new KeyIterator<K, V> (_multi_map._storage_map.map_iterator ());
+ }
+
+ public override int size { get { return _multi_map.size; } }
+
+ public override bool read_only { get { return true; } }
+
+ public override bool contains (K key) {
+ return _multi_map._storage_map.has_key (key);
+ }
+
+ public override bool add (K key) {
+ assert_not_reached ();
+ }
+
+ public override bool remove (K item) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public int count (K item) {
+ Collection<V>? collection = _multi_map._storage_map.get (item);
+ return collection != null ? collection.size : 0;
+ }
+ }
+
+ private class Values<K, V> : AbstractCollection<V> {
+ protected AbstractMultiMap<K, V> _multi_map;
+
+ public Values (AbstractMultiMap<K, V> multi_map) {
+ _multi_map = multi_map;
+ }
+
+ public override Vala.Iterator<K> iterator () {
+ return new ValueIterator<K, V> (_multi_map._storage_map.map_iterator ());
+ }
+
+ public override int size { get { return _multi_map.size; } }
+
+ public override bool read_only { get { return true; } }
+
+ public override bool contains (V value) {
+ foreach (var col in _multi_map._storage_map.values) {
+ if (col.contains (value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override bool add (V key) {
+ assert_not_reached ();
+ }
+
+ public override bool remove (V item) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+ }
+
+ private class MappingIterator<K, V> : Object {
+ protected Vala.MapIterator<K, Collection<V>> outer;
+ protected Iterator<V>? inner = null;
+
+ public MappingIterator (Vala.MapIterator<K, Collection<V>>? outer) {
+ this.outer = outer;
+ }
+
+ public bool next () {
+ if (inner != null && inner.next ()) {
+ return true;
+ } else if (outer.next ()) {
+ inner = outer.get_value ().iterator ();
+ assert (inner.next ());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_next () {
+ return inner.has_next () || outer.has_next ();
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public virtual bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public void unset () {
+ inner.remove ();
+ if (outer.get_value ().is_empty) {
+ outer.unset ();
+ }
+ }
+
+ public bool valid {
+ get {
+ return inner != null && inner.valid;
+ }
+ }
+ }
+
+ private class KeyIterator<K, V> : MappingIterator<K, V>, Traversable<K>, Iterator<K> {
+ public KeyIterator (Vala.MapIterator<K, Collection<V>>? outer) {
+ base (outer);
+ }
+
+ public new K get () {
+ assert (valid);
+ return outer.get_key ();
+ }
+
+ public bool foreach (ForallFunc<K> f) {
+ if (inner != null && outer.valid) {
+ K key = outer.get_key ();
+ if (!inner.foreach ((v) => {return f (key);})) {
+ return false;
+ }
+ outer.next ();
+ }
+ return outer.foreach ((key, col) => {
+ return col.foreach ((v) => {return f (key);});
+ });
+ }
+ }
+
+ private class ValueIterator<K, V> : MappingIterator<K, V>, Traversable<V>, Iterator<V> {
+ public ValueIterator (Vala.MapIterator<K, Collection<V>>? outer) {
+ base (outer);
+ }
+
+ public new V get () {
+ assert (valid);
+ return inner.get ();
+ }
+
+ public bool foreach (ForallFunc<V> f) {
+ if (inner != null && outer.valid) {
+ if (!inner.foreach (f)) {
+ return false;
+ }
+ outer.next ();
+ }
+ return outer.foreach ((key, col) => {
+ return col.foreach (f);
+ });
+ }
+ }
+
+ private class MapIterator<K, V> : MappingIterator<K, V>, Vala.MapIterator<K, V> {
+ public MapIterator (Vala.MapIterator<K, Collection<V>>? outer) {
+ base (outer);
+ }
+
+ public K get_key () {
+ assert (valid);
+ return outer.get_key ();
+ }
+
+ public V get_value () {
+ assert (valid);
+ return inner.get ();
+ }
+
+ public void set_value (V value) {
+ assert_not_reached ();
+ }
+
+ public bool mutable { get { return false; } }
+ }
+}
diff --git a/gee/abstractmultiset.vala b/gee/abstractmultiset.vala
new file mode 100644
index 0000000..4d2f781
--- /dev/null
+++ b/gee/abstractmultiset.vala
@@ -0,0 +1,180 @@
+/* abstractmultiset.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link MultiSet} interface.
+ *
+ * @see HashMultiSet
+ * @see TreeMultiSet
+ */
+public abstract class Vala.AbstractMultiSet<G> : AbstractCollection<G>, MultiSet<G> {
+ public override int size {
+ get { return _nitems; }
+ }
+
+ public override bool read_only {
+ get { return false; }
+ }
+
+ protected Map<G, int> _storage_map;
+ private int _nitems = 0;
+
+ /**
+ * Constructs a new, empty abstract multi set.
+ */
+ public AbstractMultiSet (Map<G, int> storage_map) {
+ this._storage_map = storage_map;
+ }
+
+ public int count (G item) {
+ int result = 0;
+ if (_storage_map.has_key (item)) {
+ result = _storage_map.get (item);
+ }
+ return result;
+ }
+
+ public override bool contains (G item) {
+ return _storage_map.has_key (item);
+ }
+
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ public override bool add (G item) {
+ if (_storage_map.has_key (item)) {
+ int current_count = _storage_map.get (item);
+ _storage_map.set (item, current_count + 1);
+ } else {
+ _storage_map.set (item, 1);
+ }
+ _nitems++;
+ return true;
+ }
+
+ public override bool remove (G item) {
+ if (_nitems > 0 && _storage_map.has_key (item)) {
+ int current_count = _storage_map.get (item);
+ if (current_count <= 1) {
+ _storage_map.unset (item);
+ } else {
+ _storage_map.set (item, current_count - 1);
+ }
+ _nitems--;
+ return true;
+ }
+ return false;
+ }
+
+ public override void clear () {
+ _storage_map.clear ();
+ _nitems = 0;
+ }
+
+ private class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
+ private AbstractMultiSet<G> _set;
+
+ private MapIterator<G, int> _iter;
+ private int _pending = 0;
+ private bool _removed = false;
+
+ public Iterator (AbstractMultiSet<G> set) {
+ _set = set;
+ _iter = _set._storage_map.map_iterator ();
+ }
+
+ public bool next () {
+ _removed = false;
+ if (_pending == 0) {
+ if (_iter.next ()) {
+ _pending = _iter.get_value () - 1;
+ return true;
+ }
+ } else {
+ _pending--;
+ return true;
+ }
+ return false;
+ }
+
+ public bool has_next () {
+ return _pending > 0 || _iter.has_next ();
+ }
+
+ public new G get () {
+ assert (! _removed);
+ return _iter.get_key ();
+ }
+
+ public void remove () {
+ assert (! _removed);
+ _iter.set_value (_pending = _iter.get_value () - 1);
+ if (_pending == 0) {
+ _iter.unset ();
+ }
+ _set._nitems--;
+ _removed = true;
+ }
+
+ public bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool valid {
+ get {
+ return ! _removed && _iter.valid;
+ }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ if (_iter.valid) {
+ if (!_removed) {
+ if (!f(_iter.get_key())) {
+ return false;
+ }
+ }
+ for(int i = _pending - 1; i >= 0; --i) {
+ if (!f(_iter.get_key())) {
+ _pending = i;
+ return false;
+ }
+ }
+ }
+ while(_iter.next()) {
+ for(int i = _iter.get_value() - 1; i >= 0; --i) {
+ if (!f(_iter.get_key())) {
+ _removed = false;
+ _pending = i;
+ return false;
+ }
+ }
+ }
+ _removed = false;
+ _pending = 0;
+ return true;
+ }
+ }
+}
diff --git a/gee/abstractqueue.vala b/gee/abstractqueue.vala
new file mode 100644
index 0000000..e364378
--- /dev/null
+++ b/gee/abstractqueue.vala
@@ -0,0 +1,55 @@
+/* abstractqueue.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link Queue} interface.
+ *
+ * Contains common code shared by all queue implementations.
+ *
+ * @see PriorityQueue
+ */
+public abstract class Vala.AbstractQueue<G> : Vala.AbstractCollection<G>, Queue<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract int capacity { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract int remaining_capacity { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract bool is_full { get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? peek ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? poll ();
+}
diff --git a/gee/abstractset.vala b/gee/abstractset.vala
new file mode 100644
index 0000000..71effc5
--- /dev/null
+++ b/gee/abstractset.vala
@@ -0,0 +1,50 @@
+/* abstractset.vala
+ *
+ * Copyright (C) 2007 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ * Julien Peeters <contact julienpeeters fr>
+ */
+
+/**
+ * Skeletal implementation of the {@link Set} interface.
+ *
+ * Contains common code shared by all set implementations.
+ *
+ * @see HashSet
+ * @see TreeSet
+ */
+public abstract class Vala.AbstractSet<G> : Vala.AbstractCollection<G>, Set<G> {
+
+ private weak Set<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new Set<G> read_only_view {
+ owned get {
+ Set<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlySet<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
diff --git a/gee/abstractsortedmap.vala b/gee/abstractsortedmap.vala
new file mode 100644
index 0000000..876a4c3
--- /dev/null
+++ b/gee/abstractsortedmap.vala
@@ -0,0 +1,65 @@
+/* readonlysortedmap.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+public abstract class Vala.AbstractSortedMap<K, V> : AbstractMap<K,V>, SortedMap<K,V> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedMap<K,V> head_map (K before);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedMap<K,V> tail_map (K after);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedMap<K,V> sub_map (K before, K after);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedSet<K> ascending_keys { owned get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedSet<Map.Entry<K,V>> ascending_entries { owned get; }
+
+ private weak SortedMap<K,V> _read_only_view;
+ /**
+ * The read-only view this map.
+ */
+ public new SortedMap<K,V> read_only_view {
+ owned get {
+ SortedMap<K,V> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlySortedMap<K,V> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
+
diff --git a/gee/abstractsortedset.vala b/gee/abstractsortedset.vala
new file mode 100644
index 0000000..03f02f3
--- /dev/null
+++ b/gee/abstractsortedset.vala
@@ -0,0 +1,98 @@
+/* abstractsortedset.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * Skeletal implementation of the {@link SortedSet} interface.
+ *
+ * Contains common code shared by all set implementations.
+ *
+ * @see TreeSet
+ */
+public abstract class Vala.AbstractSortedSet<G> : Vala.AbstractSet<G>, SortedSet<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G first ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G last ();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Iterator<G>? iterator_at (G element);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? lower (G element);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? higher (G element);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? floor (G element);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract G? ceil (G element);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedSet<G> head_set (G before);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedSet<G> tail_set (G after);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract SortedSet<G> sub_set (G from, G to);
+
+ private weak SortedSet<G> _read_only_view;
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new SortedSet<G> read_only_view {
+ owned get {
+ SortedSet<G> instance = _read_only_view;
+ if (_read_only_view == null) {
+ instance = new ReadOnlySortedSet<G> (this);
+ _read_only_view = instance;
+ instance.add_weak_pointer ((void**) (&_read_only_view));
+ }
+ return instance;
+ }
+ }
+}
+
diff --git a/gee/arraylist.vala b/gee/arraylist.vala
index fe398e4..4bcb3e0 100644
--- a/gee/arraylist.vala
+++ b/gee/arraylist.vala
@@ -3,6 +3,7 @@
* Copyright (C) 2004-2005 Novell, Inc
* Copyright (C) 2005 David Waite
* Copyright (C) 2007-2008 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,66 +21,139 @@
*
* Author:
* Jürg Billeter <j bitron ch>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
*/
using GLib;
/**
- * Arrays of arbitrary elements which grow automatically as elements are added.
+ * Resizable array implementation of the {@link List} interface.
+ *
+ * The storage array grows automatically when needed.
+ *
+ * This implementation is pretty good for rarely modified data. Because they are
+ * stored in an array this structure does not fit for highly mutable data. For an
+ * alternative implementation see {@link LinkedList}.
+ *
+ * @see LinkedList
*/
-public class Vala.ArrayList<G> : List<G> {
+public class Vala.ArrayList<G> : AbstractBidirList<G> {
+ /**
+ * {@inheritDoc}
+ */
public override int size {
get { return _size; }
}
- public EqualFunc<G> equal_func {
- set { _equal_func = value; }
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
}
- private G[] _items = new G[4];
- private int _size;
- private EqualFunc<G> _equal_func;
+ /**
+ * The elements' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<G> equal_func { private set; get; }
+
+ internal G[] _items = new G[4];
+ internal int _size;
// concurrent modification protection
private int _stamp = 0;
- public ArrayList (EqualFunc<G> equal_func = GLib.direct_equal) {
+ /**
+ * Constructs a new, empty array 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 ArrayList (owned EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
this.equal_func = equal_func;
}
- public override Type get_element_type () {
- return typeof (G);
+ /**
+ * {@inheritDoc}
+ */
+ public override bool foreach(ForallFunc<G> f) {
+ for (int i = 0; i < _size; i++) {
+ if (!f (_items[i])) {
+ return false;
+ }
+ }
+ return true;
}
+ /**
+ * {@inheritDoc}
+ */
public override Vala.Iterator<G> iterator () {
return new Iterator<G> (this);
}
+ /**
+ * {@inheritDoc}
+ */
+ public override ListIterator<G> list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override BidirListIterator<G> bidir_list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public override bool contains (G item) {
return (index_of (item) != -1);
}
+ /**
+ * {@inheritDoc}
+ */
public override int index_of (G item) {
for (int index = 0; index < _size; index++) {
- if (_equal_func (_items[index], item)) {
+ if (equal_func (_items[index], item)) {
return index;
}
}
return -1;
}
- public override G? get (int index) {
- assert (index >= 0 && index < _size);
+ /**
+ * {@inheritDoc}
+ */
+ public override G get (int index) {
+ assert (index >= 0);
+ assert (index < _size);
return _items[index];
}
+ /**
+ * {@inheritDoc}
+ */
public override void set (int index, G item) {
- assert (index >= 0 && index < _size);
+ assert (index >= 0);
+ assert (index < _size);
_items[index] = item;
}
+ /**
+ * {@inheritDoc}
+ */
public override bool add (G item) {
if (_size == _items.length) {
grow_if_needed (1);
@@ -89,8 +163,12 @@ public class Vala.ArrayList<G> : List<G> {
return true;
}
+ /**
+ * {@inheritDoc}
+ */
public override void insert (int index, G item) {
- assert (index >= 0 && index <= _size);
+ assert (index >= 0);
+ assert (index <= _size);
if (_size == _items.length) {
grow_if_needed (1);
@@ -100,9 +178,12 @@ public class Vala.ArrayList<G> : List<G> {
_stamp++;
}
+ /**
+ * {@inheritDoc}
+ */
public override bool remove (G item) {
for (int index = 0; index < _size; index++) {
- if (_equal_func (_items[index], item)) {
+ if (equal_func (_items[index], item)) {
remove_at (index);
return true;
}
@@ -110,16 +191,25 @@ public class Vala.ArrayList<G> : List<G> {
return false;
}
- public override void remove_at (int index) {
- assert (index >= 0 && index < _size);
+ /**
+ * {@inheritDoc}
+ */
+ public override G remove_at (int index) {
+ assert (index >= 0);
+ assert (index < _size);
+ G item = _items[index];
_items[index] = null;
shift (index + 1, -1);
_stamp++;
+ return item;
}
+ /**
+ * {@inheritDoc}
+ */
public override void clear () {
for (int index = 0; index < _size; index++) {
_items[index] = null;
@@ -128,8 +218,40 @@ public class Vala.ArrayList<G> : List<G> {
_stamp++;
}
+ /**
+ * {@inheritDoc}
+ */
+ public override List<G>? slice (int start, int stop) {
+ return_val_if_fail (start <= stop, null);
+ return_val_if_fail (start >= 0, null);
+ return_val_if_fail (stop <= _size, null);
+
+ var slice = new ArrayList<G> (this.equal_func);
+ for (int i = start; i < stop; i++) {
+ slice.add (this[i]);
+ }
+
+ return slice;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool add_all (Collection<G> collection) {
+ if (collection.is_empty) {
+ return false;
+ }
+
+ grow_if_needed (collection.size);
+ collection.foreach ((item) => {_items[_size++] = item; return true;});
+ _stamp++;
+ return true;
+ }
+
private void shift (int start, int delta) {
- assert (start >= 0 && start <= _size && start >= -delta);
+ assert (start >= 0);
+ assert (start <= _size);
+ assert (start >= -delta);
_items.move (start, start + delta, _size - start);
@@ -152,40 +274,144 @@ public class Vala.ArrayList<G> : List<G> {
_items.resize (value);
}
- private class Iterator<G> : Vala.Iterator<G> {
- public ArrayList<G> list {
- set {
- _list = value;
- _stamp = _list._stamp;
- }
- }
-
+ 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
- public int _stamp = 0;
+ private int _stamp = 0;
public Iterator (ArrayList list) {
- this.list = list;
+ _list = list;
+ _stamp = _list._stamp;
}
- public override bool next () {
+ public bool next () {
assert (_stamp == _list._stamp);
- if (_index < _list._size) {
+ if (_index + 1 < _list._size) {
_index++;
+ _removed = false;
+ return true;
+ }
+ return false;
+ }
+
+ public bool has_next () {
+ assert (_stamp == _list._stamp);
+ return (_index + 1 < _list._size);
+ }
+
+ public bool first () {
+ assert (_stamp == _list._stamp);
+ if (_list.size == 0) {
+ return false;
+ }
+ _index = 0;
+ _removed = false;
+ return true;
+ }
+
+ public new G get () {
+ assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ assert (! _removed);
+ return _list._items[_index];
+ }
+
+ public void remove () {
+ assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ assert (! _removed);
+ _list.remove_at (_index);
+ _index--;
+ _removed = true;
+ _stamp = _list._stamp;
+ }
+
+ public bool previous () {
+ assert (_stamp == _list._stamp);
+ if (_index > 0) {
+ _index--;
+ return true;
}
- return (_index < _list._size);
+ return false;
+ }
+
+ public bool has_previous () {
+ assert (_stamp == _list._stamp);
+ return (_index - 1 >= 0);
+ }
+
+ public bool last () {
+ assert (_stamp == _list._stamp);
+ if (_list.size == 0) {
+ return false;
+ }
+ _index = _list._size - 1;
+ return true;
+ }
+
+ public new void set (G item) {
+ assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ _list._items[_index] = item;
+ _stamp = ++_list._stamp;
+ }
+
+ public void insert (G item) {
+ assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ _list.insert (_index, item);
+ _index++;
+ _stamp = _list._stamp;
}
- public override G? get () {
+ public void add (G item) {
assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ _list.insert (_index + 1, item);
+ _index++;
+ _stamp = _list._stamp;
+ }
+
+ public int index () {
+ assert (_stamp == _list._stamp);
+ assert (_index >= 0);
+ assert (_index < _list._size);
+ return _index;
+ }
- if (_index < 0 || _index >= _list._size) {
- return null;
+ public bool read_only {
+ get {
+ return false;
}
+ }
- return _list.get (_index);
+ public bool valid {
+ get {
+ return _index >= 0 && _index < _list._size && ! _removed;
+ }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ assert (_stamp == _list._stamp);
+ if (_index < 0 || _removed) {
+ _index++;
+ }
+ while (_index < _list._size) {
+ if (!f (_list._items[_index])) {
+ return false;
+ }
+ _index++;
+ }
+ _index = _list._size - 1;
+ return true;
}
}
}
diff --git a/gee/arrayqueue.vala b/gee/arrayqueue.vala
new file mode 100644
index 0000000..9eac3e6
--- /dev/null
+++ b/gee/arrayqueue.vala
@@ -0,0 +1,342 @@
+/* arrayqueue.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+/**
+ * Resizable array implementation of the {@link Deque} interface.
+ *
+ * The storage array grows automatically when needed.
+ *
+ * This implementation is pretty good for lookups at the end or random.
+ * Because they are stored in an array this structure does not fit for deleting
+ * arbitrary elements. For an alternative implementation see {@link LinkedList}.
+ *
+ * @see LinkedList
+ */
+public class Vala.ArrayQueue<G> : Vala.AbstractQueue<G>, Deque<G> {
+ /**
+ * Constructs a new, empty array queue.
+ *
+ * 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 ArrayQueue (owned EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
+ this.equal_func = equal_func;
+ this._items = new G[10];
+ }
+
+ [CCode (notify = false)]
+ public EqualDataFunc<G> equal_func { private set; get; }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int size { get { return _length; } }
+
+ public bool is_empty { get { return _length == 0; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only { get { return false; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int capacity { get {return Queue.UNBOUNDED_CAPACITY;} }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int remaining_capacity { get {return Queue.UNBOUNDED_CAPACITY;} }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool is_full { get { return false; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G> iterator() {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool add (G element) {
+ return offer_tail (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool contains (G item) {
+ return find_index(item) != -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool remove (G item) {
+ _stamp++;
+ int index = find_index (item);
+ if (index == -1) {
+ return false;
+ } else {
+ remove_at (index);
+ return true;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear() {
+ _stamp++;
+ for (int i = 0; i < _length; i++) {
+ _items[(_start + i) % _items.length] = null;
+ }
+ _start = _length = 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? peek () {
+ return peek_head ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? poll () {
+ return poll_head ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer_head (G element) {
+ grow_if_needed ();
+ _start = (_items.length + _start - 1) % _items.length;
+ _length++;
+ _items[_start] = element;
+ _stamp++;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? peek_head () {
+ return _items[_start];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? poll_head () {
+ _stamp++;
+ if (_length == 0) {
+ _start = 0;
+ return null;
+ } else {
+ _length--;
+ G result = (owned)_items[_start];
+ _start = (_start + 1) % _items.length;
+ return (owned)result;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain_head (Collection<G> recipient, int amount = -1) {
+ return drain (recipient, amount);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer_tail (G element) {
+ grow_if_needed();
+ _items[(_start + _length++) % _items.length] = element;
+ _stamp++;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? peek_tail () {
+ return _items[(_items.length + _start + _length - 1) % _items.length];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? poll_tail () {
+ _stamp++;
+ if (_length == 0) {
+ _start = 0;
+ return null;
+ } else {
+ return (owned)_items[(_items.length + _start + --_length) % _items.length];
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain_tail (Collection<G> recipient, int amount = -1) {
+ G? item = null;
+ int drained = 0;
+ while((amount == -1 || --amount >= 0) && (item = poll_tail ()) != null) {
+ recipient.add(item);
+ drained++;
+ }
+ return drained;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ private void grow_if_needed () {
+ if (_items.length < _length +1 ) {
+ _items.resize (2 * _items.length);
+#if 0
+ _items.move (0, _length, _start);
+#else
+ // See bug #667452
+ for(int i = 0; i < _start; i++)
+ _items[_length + i] = (owned)_items[i];
+#endif
+ }
+ }
+
+ private int find_index (G item) {
+ for (int i = _start; i < int.min(_items.length, _start + _length); i++) {
+ if (equal_func(item, _items[i])) {
+ return i;
+ }
+ }
+ for (int i = 0; i < _start + _length - _items.length; i++) {
+ if (equal_func(item, _items[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void remove_at (int index) {
+ int end = (_items.length + _start + _length - 1) % _items.length + 1;
+ if (index == _start) {
+ _items[_start++] = null;
+ _length--;
+ return;
+ } else if (index > _start && end <= _start) {
+ _items[index] = null;
+ _items.move (index + 1, index, _items.length - 1);
+ _items[_items.length - 1] = (owned)_items[0];
+ _items.move (1, 0, end - 1);
+ _length--;
+ } else {
+ _items[index] = null;
+ _items.move (index + 1, index, end - (index + 1));
+ _length--;
+ }
+ }
+
+ private class Iterator<G> : GLib.Object, Traversable<G>, Vala.Iterator<G> {
+ public Iterator (ArrayQueue<G> queue) {
+ _queue = queue;
+ _stamp = _queue._stamp;
+ }
+
+ public bool next () {
+ assert (_queue._stamp == _stamp);
+ if (has_next ()) {
+ _offset++;
+ _removed = false;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_next () {
+ assert (_queue._stamp == _stamp);
+ return _offset + 1 < _queue._length;
+ }
+
+ public new G get () {
+ assert (_queue._stamp == _stamp);
+ assert (_offset != -1);
+ assert (!_removed);
+ return _queue._items[(_queue._start + _offset) % _queue._items.length];
+ }
+
+ public void remove () {
+ assert (_queue._stamp++ == _stamp++);
+ _queue.remove_at((_queue._start + _offset) % _queue._items.length);
+ _offset--;
+ _removed = true;
+ }
+
+ public bool valid { get {return _offset != -1 && !_removed;} }
+
+ public bool read_only { get {return false;} }
+
+ public bool foreach (ForallFunc<G> f) {
+ assert (_queue._stamp == _stamp);
+ if (!valid) {
+ _offset++;
+ _removed = false;
+ }
+ for (int i = _offset; i < _queue._length; i++) {
+ if (!f (_queue._items[(_queue._start + i) % _queue._items.length])) {
+ _offset = i;
+ return false;
+ }
+ }
+ _offset = _queue._length - 1;
+ return true;
+ }
+
+ private ArrayQueue _queue;
+ private int _stamp;
+ private int _offset = -1;
+ private bool _removed = false;
+ }
+
+ private G[] _items;
+ private int _start = 0;
+ private int _length = 0;
+ private int _stamp = 0;
+}
+
diff --git a/gee/bidiriterator.vala b/gee/bidiriterator.vala
new file mode 100644
index 0000000..01d3af2
--- /dev/null
+++ b/gee/bidiriterator.vala
@@ -0,0 +1,55 @@
+/* bidiriterator.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois, Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * A bi-directional iterator.
+ */
+[GenericAccessors]
+public interface Vala.BidirIterator<G> : Vala.Iterator<G> {
+ /**
+ * Rewinds to the previous element in the iteration.
+ *
+ * @return ``true`` if the iterator has a previous element
+ */
+ public abstract bool previous ();
+
+ /**
+ * Checks whether there is a previous element in the iteration.
+ *
+ * @return ``true`` if the iterator has a previous element
+ */
+ public abstract bool has_previous ();
+
+ /**
+ * Rewinds to the first element in the iteration.
+ *
+ * @return ``true`` if the iterator has a first element
+ */
+ public abstract bool first ();
+
+ /**
+ * Advances to the last element in the iteration.
+ *
+ * @return ``true`` if the iterator has a last element
+ */
+ public abstract bool last ();
+}
diff --git a/gee/bidirlist.vala b/gee/bidirlist.vala
new file mode 100644
index 0000000..f482adf
--- /dev/null
+++ b/gee/bidirlist.vala
@@ -0,0 +1,35 @@
+/* bidirlist.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+[GenericAccessors]
+public interface Vala.BidirList<G> : Vala.List<G> {
+ /**
+ * Returns a BidirListIterator that can be used for iteration over this list.
+ *
+ * @return a BidirListIterator that can be used for iteration over this list
+ */
+ public abstract new BidirListIterator<G> bidir_list_iterator ();
+
+ /**
+ * The read-only view of this list.
+ */
+ public abstract new BidirList<G> read_only_view { owned get; }
+}
diff --git a/gee/bidirlistiterator.vala b/gee/bidirlistiterator.vala
new file mode 100644
index 0000000..094a5f7
--- /dev/null
+++ b/gee/bidirlistiterator.vala
@@ -0,0 +1,30 @@
+/* bidirlistiterator.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+[GenericAccessors]
+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.
+ */
+ public abstract void insert (G item);
+}
+
diff --git a/gee/bidirmapiterator.vala b/gee/bidirmapiterator.vala
new file mode 100644
index 0000000..32e2e6b
--- /dev/null
+++ b/gee/bidirmapiterator.vala
@@ -0,0 +1,56 @@
+/* bidiriterator.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois, Maciej Piechotka
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * A bi-directional Map iterator.
+ */
+[GenericAccessors]
+public interface Vala.BidirMapIterator<K,V> : Vala.MapIterator<K,V> {
+ /**
+ * Rewinds to the previous element in the iteration.
+ *
+ * @return `true` if the iterator has a previous element
+ */
+ public abstract bool previous ();
+
+ /**
+ * Checks whether there is a previous element in the iteration.
+ *
+ * @return `true` if the iterator has a previous element
+ */
+ public abstract bool has_previous ();
+
+ /**
+ * Goes back to the first element.
+ *
+ * @return `true` if the iterator has a first element
+ */
+ public abstract bool first ();
+
+ /**
+ * Advances to the last element in the iteration.
+ *
+ * @return `true` if the iterator has a last element
+ */
+ public abstract bool last ();
+}
diff --git a/gee/bidirsortedmap.vala b/gee/bidirsortedmap.vala
new file mode 100644
index 0000000..1a70576
--- /dev/null
+++ b/gee/bidirsortedmap.vala
@@ -0,0 +1,45 @@
+/* bidirsortedmap.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+[GenericAccessors]
+public interface Vala.BidirSortedMap<K,V> : SortedMap<K,V> {
+ /**
+ * Returns a bi-directional iterator for this map.
+ *
+ * @return a bi-directional map iterator
+ */
+ public abstract BidirMapIterator<K,V> bidir_map_iterator ();
+
+ /**
+ * The read-only view of this set.
+ */
+ public abstract new BidirSortedMap<K,V> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty sorted set.
+ *
+ * @return an immutable empty sorted set
+ */
+ public static BidirSortedMap<K,V> empty<K,V> () {
+ return new TreeMap<K,V> ().read_only_view;
+ }
+}
+
diff --git a/gee/bidirsortedset.vala b/gee/bidirsortedset.vala
new file mode 100644
index 0000000..b22172d
--- /dev/null
+++ b/gee/bidirsortedset.vala
@@ -0,0 +1,46 @@
+/* bidirsortedset.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+[GenericAccessors]
+public interface Vala.BidirSortedSet<G> : SortedSet<G> {
+ /**
+ * Returns a {@link BidirIterator} that can be used for bi-directional
+ * iteration over this sorted set.
+ *
+ * @return a {@link BidirIterator} over this sorted set
+ */
+ public abstract BidirIterator<G> bidir_iterator ();
+
+ /**
+ * The read-only view of this set.
+ */
+ public abstract new BidirSortedSet<G> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty sorted set.
+ *
+ * @return an immutable empty sorted set
+ */
+ public static BidirSortedSet<G> empty<G> () {
+ return new TreeSet<G> ().read_only_view;
+ }
+}
+
diff --git a/gee/collection.vala b/gee/collection.vala
index 76f568a..112e6ac 100644
--- a/gee/collection.vala
+++ b/gee/collection.vala
@@ -1,6 +1,6 @@
/* collection.vala
*
- * Copyright (C) 2007 Jürg Billeter
+ * Copyright (C) 2007-2009 Jürg Billeter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,21 +21,32 @@
*/
/**
- * Serves as the base interface for implementing collection classes. Defines
- * size, iteration, and modification methods.
+ * A generic collection of objects.
*/
-public abstract class Vala.Collection<G> : Iterable<G> {
+[GenericAccessors]
+public interface Vala.Collection<G> : Iterable<G> {
/**
* The number of items in this collection.
*/
public abstract int size { get; }
/**
+ * Specifies whether this collection is empty.
+ */
+ 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.
+ */
+ public abstract bool read_only { get; }
+
+ /**
* Determines whether this collection contains the specified item.
*
* @param item the item to locate in the collection
*
- * @return true if item is found, false otherwise
+ * @return ``true`` if item is found, ``false`` otherwise
*/
public abstract bool contains (G item);
@@ -45,17 +56,17 @@ public abstract class Vala.Collection<G> : Iterable<G> {
*
* @param item the item to add to the collection
*
- * @return true if the collection has been changed, false otherwise
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
*/
public abstract bool add (G item);
/**
- * Removes the first occurrence of an item from this collection. Must not
+ * Removes the first occurence of an item from this collection. Must not
* be called on read-only collections.
*
* @param item the item to remove from the collection
*
- * @return true if the collection has been changed, false otherwise
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
*/
public abstract bool remove (G item);
@@ -64,5 +75,219 @@ public abstract class Vala.Collection<G> : Iterable<G> {
* read-only collections.
*/
public abstract void clear ();
+
+ /**
+ * Adds all items in the input collection to this collection.
+ *
+ * @param collection the collection which items will be added to this
+ * collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ public virtual bool add_all (Collection<G> collection) {
+ return collection.fold<bool> ((item, changed) => changed | add (item), false);
+ }
+
+ /**
+ * Returns ``true`` it this collection contains all items as the input
+ * collection.
+ *
+ * @param collection the collection which items will be compared with
+ * this collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ public virtual bool contains_all (Collection<G> collection) {
+ return collection.foreach ((item) => contains (item));
+ }
+
+ /**
+ * Removes the subset of items in this collection corresponding to the
+ * elments in the input collection. If there is several occurrences of
+ * the same value in this collection they are decremented of the number
+ * of occurrences in the input collection.
+ *
+ * @param collection the collection which items will be compared with
+ * this collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ public virtual bool remove_all (Collection<G> collection) {
+ return collection.fold<bool> ((item, changed) => changed | remove (item), false);
+ }
+
+ /**
+ * Removes all items in this collection that are not contained in the input
+ * collection. In other words all common items of both collections are
+ * retained in this collection.
+ *
+ * @param collection the collection which items will be compared with
+ * this collection.
+ *
+ * @return ``true`` if the collection has been changed, ``false`` otherwise
+ */
+ public virtual bool retain_all (Collection<G> collection) {
+ bool changed = false;
+ for (Iterator<G> iter = iterator(); iter.next ();) {
+ G item = iter.get ();
+ if (!collection.contains (item)) {
+ iter.remove ();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Returns an array containing all of items from this collection.
+ *
+ * @return an array containing all of items from this collection
+ */
+ public virtual G[] to_array () {
+ var t = typeof (G);
+ if (t == typeof (bool)) {
+ return (G[]) to_bool_array ((Collection<bool>) this);
+ } else if (t == typeof (char)) {
+ return (G[]) to_char_array ((Collection<char>) this);
+ } else if (t == typeof (uchar)) {
+ return (G[]) to_uchar_array ((Collection<uchar>) this);
+ } else if (t == typeof (int)) {
+ return (G[]) to_int_array ((Collection<int>) this);
+ } else if (t == typeof (uint)) {
+ return (G[]) to_uint_array ((Collection<uint>) this);
+ } else if (t == typeof (int64)) {
+ return (G[]) to_int64_array ((Collection<int64>) this);
+ } else if (t == typeof (uint64)) {
+ return (G[]) to_uint64_array ((Collection<uint64>) this);
+ } else if (t == typeof (long)) {
+ return (G[]) to_long_array ((Collection<long>) this);
+ } else if (t == typeof (ulong)) {
+ return (G[]) to_ulong_array ((Collection<ulong>) this);
+ } else if (t == typeof (float)) {
+ return (G[]) to_float_array ((Collection<float>) this);
+ } else if (t == typeof (double)) {
+ return (G[]) to_double_array ((Collection<double>) this);
+ } else {
+ G[] array = new G[size];
+ int index = 0;
+ foreach (G element in this) {
+ array[index++] = element;
+ }
+ return array;
+ }
+ }
+
+ private static bool[] to_bool_array (Collection<bool> coll) {
+ bool[] array = new bool[coll.size];
+ int index = 0;
+ foreach (bool element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static char[] to_char_array (Collection<char> coll) {
+ char[] array = new char[coll.size];
+ int index = 0;
+ foreach (char element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static uchar[] to_uchar_array (Collection<uchar> coll) {
+ uchar[] array = new uchar[coll.size];
+ int index = 0;
+ foreach (uchar element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static int[] to_int_array (Collection<int> coll) {
+ int[] array = new int[coll.size];
+ int index = 0;
+ foreach (int element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static uint[] to_uint_array (Collection<uint> coll) {
+ uint[] array = new uint[coll.size];
+ int index = 0;
+ foreach (uint element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ 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;
+ }
+ return array;
+ }
+
+ 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;
+ }
+ return array;
+ }
+
+ private static long[] to_long_array (Collection<long> coll) {
+ long[] array = new long[coll.size];
+ int index = 0;
+ foreach (long element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static ulong[] to_ulong_array (Collection<ulong> coll) {
+ ulong[] array = new ulong[coll.size];
+ int index = 0;
+ foreach (ulong element in coll) {
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ 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;
+ }
+ return array;
+ }
+
+ 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;
+ }
+ return array;
+ }
+
+ /**
+ * The read-only view of this collection.
+ */
+ 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;
+ }
}
diff --git a/gee/comparable.vala b/gee/comparable.vala
new file mode 100644
index 0000000..489a7c8
--- /dev/null
+++ b/gee/comparable.vala
@@ -0,0 +1,37 @@
+/* comparable.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * This interface defines a total ordering among instances of each class
+ * implementing it.
+ *
+ * @see Hashable
+ */
+public interface Vala.Comparable<G> : Object {
+ /**
+ * Compares this object with the specifed object.
+ *
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object
+ */
+ public abstract int compare_to (G object);
+}
diff --git a/gee/concurrentlist.vala b/gee/concurrentlist.vala
new file mode 100644
index 0000000..485e2d2
--- /dev/null
+++ b/gee/concurrentlist.vala
@@ -0,0 +1,587 @@
+/* concurrentlist.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * A single-linked list. This implementation is based on
+ * [[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
+ * visible to other threads.
+ */
+public class Vala.ConcurrentList<G> : AbstractList<G> {
+ /**
+ * The elements' equality testing function.
+ */
+ [CCode (notify = false)]
+ public Vala.EqualDataFunc<G> equal_func { private set; get; }
+
+ /**
+ * Construct new, empty single 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 ConcurrentList (owned Vala.EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null)
+ equal_func = Vala.Functions.get_equal_func_for (typeof (G));
+ this.equal_func = (owned)equal_func;
+ _head = new Node<G>.head ();
+ HazardPointer.set_pointer<Node<G>> (&_tail, _head);
+ }
+
+ ~ConcurrentList () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ _head = null;
+ HazardPointer.set_pointer<Node<G>?> (&_tail, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int size {
+ get {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ int result = 0;
+ for (var iter = iterator (); iter.next ();)
+ result++;
+ return result;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool is_empty {
+ get {
+ return !iterator ().next ();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool contains (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ for (var iter = iterator (); iter.next ();)
+ if (equal_func (item, iter.get ()))
+ return true;
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool add (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Node<G> node = new Node<G> (item);
+ node.insert (get_tail (), null);
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool remove (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Vala.Iterator<G> iter = iterator ();
+ while (iter.next ()) {
+ if (equal_func (item, iter.get ())) {
+ iter.remove ();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ var iter = iterator ();
+ while (iter.next ())
+ iter.remove ();
+ HazardPointer.set_pointer (&_tail, _head);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (_head);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override ListIterator<G> list_iterator () {
+ return new Iterator<G> (_head);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? get (int index) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (index >= 0);
+ for (var iterator = iterator (); iterator.next ();)
+ if (index-- == 0)
+ return iterator.get ();
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void set (int index, G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (index >= 0);
+ for (var iterator = list_iterator (); iterator.next ();) {
+ if (index-- == 0) {
+ iterator.set (item);
+ return;
+ }
+ }
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int index_of (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ int index = 0;
+ for (var iterator = list_iterator (); iterator.next (); index++)
+ if (equal_func (item, iterator.get ()))
+ return index;
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void insert (int index, G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (index >= 0);
+ if (index == 0) {
+ var prev = _head;
+ var next = _head.get_next ();
+ Node<G> new_node = new Node<G> (item);
+ new_node.insert (prev, next);
+ } else {
+ for (var iterator = list_iterator (); iterator.next ();) {
+ if (--index == 0) {
+ iterator.add (item);
+ return;
+ }
+ }
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G remove_at (int index) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ for (var iterator = list_iterator (); iterator.next ();) {
+ if (index-- == 0) {
+ G data = iterator.get ();
+ iterator.remove ();
+ return data;
+ }
+ }
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override List<G>? slice (int start, int end) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (0 <= start);
+ assert (start <= end);
+ var list = new ConcurrentList<G> (equal_func);
+ var iterator = iterator ();
+ int idx = 0;
+ for (; iterator.next (); idx++)
+ if (idx >= start && idx < end)
+ list.add (iterator.get ());
+ else if (idx >= end)
+ break;
+ assert (idx >= end);
+ return list;
+ }
+
+ private inline Node<G> update_tail () {
+ Node<G> tail = HazardPointer.get_pointer (&_tail);
+ Node.backtrace<G> (ref tail);
+ Node.search_for<G> (null, ref tail);
+ HazardPointer.set_pointer<Node<G>> (&_tail, tail);
+ return tail;
+ }
+
+ private inline Node<G> get_tail () {
+ return update_tail ();
+ }
+
+ private Node<G> _head;
+ private Node<G> *_tail;
+
+ 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 bool next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Node<G>? _old_prev = _removed ? _prev : null;
+ bool success = Node.proceed<G> (ref _prev, ref _curr);
+ if (success) {
+ if (_removed)
+ _prev = _old_prev;
+ _removed = false;
+ _started = true;
+ _index++;
+ }
+ return success;
+ }
+
+ public bool has_next () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ Node<G>? prev = _prev;
+ Node<G>? curr = _curr;
+ return Node.proceed<G> (ref prev, ref curr);
+ }
+
+ public new G get () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (valid);
+ return HazardPointer.get_pointer<G> (&_curr._data);
+ }
+
+ public new void set (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (valid);
+#if DEBUG
+ G item_copy = item;
+ stderr.printf (" Setting data %p to %p\n", _curr, item_copy);
+ HazardPointer.set_pointer<G> (&_curr._data, (owned)item_copy);
+#else
+ HazardPointer.set_pointer<G> (&_curr._data, item);
+#endif
+ }
+
+ public void remove () {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (valid);
+ _curr.remove (_prev);
+ _removed = true;
+ _index--;
+ }
+
+ public bool valid {
+ get { return _started && !_removed && _curr != null; }
+ }
+
+ public bool read_only { get { return false; } }
+
+ public int index() {
+ assert (valid);
+ return _index;
+ }
+
+ public void add (G item) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ assert (valid);
+ if (!Node.proceed<G> (ref _prev, ref _curr)) {
+ _prev = (owned)_curr;
+ _curr = null;
+ }
+ Node<G> new_node = new Node<G> (item);
+ new_node.insert (_prev, _curr);
+ _curr = (owned)new_node;
+ _index++;
+ }
+
+ public new bool foreach (ForallFunc<G> f) {
+ HazardPointer.Context ctx = new HazardPointer.Context ();
+ if (_started && !_removed) {
+ if (!f (HazardPointer.get_pointer<G> (&_curr._data))) {
+ return false;
+ }
+ }
+ Node<G>? _old_prev = _removed ? _prev : null;
+ while (Node.proceed<G> (ref _prev, ref _curr)) {
+ if (_removed)
+ _prev = _old_prev;
+ _removed = false;
+ _started = true;
+ _index++;
+ if (!f (HazardPointer.get_pointer<G> (&_curr._data))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool _started;
+ private bool _removed;
+ private int _index;
+ private Node<G> _prev;
+ private Node<G>? _curr;
+ }
+
+ private class Node<G> {
+ public inline Node (G data) {
+ AtomicPointer.set (&_succ, null);
+ AtomicPointer.set (&_backlink, null);
+ G data_copy = data;
+ G *data_ptr = (owned)data_copy;
+#if DEBUG
+ stderr.printf (" Creating node %p with data %p\n", this, data_ptr);
+#endif
+ AtomicPointer.set (&_data, (owned)data_ptr);
+ }
+
+ public inline Node.head () {
+ AtomicPointer.set (&_succ, null);
+ AtomicPointer.set (&_backlink, null);
+ AtomicPointer.set (&_data, null);
+#if DEBUG
+ stderr.printf (" Creating head node %p\n", this);
+#endif
+ }
+
+ inline ~Node () {
+ HazardPointer.set_pointer<Node<G>?> (&_succ, null, 3);
+ HazardPointer.set_pointer<Node<G>?> (&_backlink, null);
+#if DEBUG
+ HazardPointer<G?>? old_data = HazardPointer.exchange_hazard_pointer (&_data, null);
+ stderr.printf (" Freeing node %p (with data %p)\n", this, old_data != null ?
old_data.get() : null);
+ if (old_data != null) {
+ old_data.release (HazardPointer.get_destroy_notify<G?> ());
+ }
+#else
+ HazardPointer.set_pointer<G> (&_data, null);
+#endif
+ }
+
+ public static inline bool proceed<G> (ref Node<G>? prev, ref Node<G> curr, bool force =
false) {
+ Node<G>? next = curr.get_next ();
+ while (next != null) {
+ State next_state = next.get_state ();
+ State curr_state;
+ Node<G> curr_next = curr.get_succ (out curr_state);
+ if (next_state != State.MARKED || (curr_state == State.MARKED && curr_next ==
next))
+ break;
+ if (curr_next == next)
+ next.help_marked (curr);
+ next = curr_next;
+ }
+ bool success = next != null;
+ if (success || force) {
+ prev = (owned)curr;
+ curr = (owned)next;
+#if DEBUG
+ stderr.printf (" Procceed to %p (previous %p)\n", curr, prev);
+#endif
+ }
+ return success;
+ }
+
+ public static inline bool search_for<G> (Node<G>? goal, ref Node<G>? prev) {
+ Node<G>? curr = prev.get_next ();
+ while ((curr != goal || curr != null) && proceed<G> (ref prev, ref curr, true));
+ return curr == goal;
+ }
+
+ public inline bool remove (Node<G> prev_node) {
+#if DEBUG
+ stderr.printf (" Removing %p (previous %p)\n", this, prev_node);
+#endif
+ Node<G>? prev = prev_node;
+ bool result = try_flag (ref prev);
+ if (prev != null)
+ help_flagged (prev);
+ return result;
+ }
+
+ public inline void insert (owned Node<G> prev, Node<G>? next) {
+#if DEBUG
+ stderr.printf (" Inserting %p between %p and %p\n", this, prev, next);
+#endif
+ while (true) {
+ State prev_state;
+ Node<G>? prev_next = get_succ (out prev_state);
+ if (prev_state == State.FLAGGED) {
+ prev_next.help_flagged (prev);
+ } else {
+ set_succ (next, State.NONE);
+ bool result = prev.compare_and_exchange (next, State.NONE, this,
State.NONE);
+ if (result)
+ return;
+ prev_next = get_succ (out prev_state);
+ if (prev_state == State.FLAGGED)
+ prev_next.help_flagged (prev);
+ backtrace<G> (ref prev);
+ }
+ search_for<G> (next, ref prev);
+ }
+
+ }
+
+ public inline void help_flagged (Node<G> prev) {
+#if DEBUG
+ stderr.printf (" Help flagging %p (previous %p)\n", this, prev);
+#endif
+ set_backlink (prev);
+ if (get_state () != State.MARKED)
+ try_mark ();
+ help_marked (prev);
+ }
+
+ public inline void try_mark () {
+#if DEBUG
+ stderr.printf (" Try flagging %p\n", this);
+#endif
+ do {
+ Node<G>? next_node = get_next ();
+ bool result = compare_and_exchange (next_node, State.NONE, next_node,
State.MARKED);
+ if (!result) {
+ State state;
+ next_node = get_succ (out state);
+ if (state == State.FLAGGED)
+ help_flagged (next_node);
+ }
+ } while (get_state () != State.MARKED);
+ }
+
+ public inline void help_marked (Node<G> prev_node) {
+#if DEBUG
+ stderr.printf (" Help marking %p (previous %p)\n", this, prev_node);
+#endif
+ prev_node.compare_and_exchange (this, State.FLAGGED, get_next (), State.NONE);
+ }
+
+ public inline bool try_flag (ref Node<G>? prev_node) {
+#if DEBUG
+ stderr.printf (" Try flagging %p (previous %p)\n", this, prev_node);
+#endif
+ while (true) {
+ if (prev_node.compare_succ (this, State.FLAGGED))
+ return false;
+ bool result = prev_node.compare_and_exchange (this, State.NONE, this,
State.FLAGGED);
+ if (result)
+ return true;
+ State result_state;
+ Node<G>? result_node = prev_node.get_succ (out result_state);
+ if (result_node == this && result_state == State.FLAGGED)
+ return false;
+ backtrace<G> (ref prev_node);
+ if (!search_for<G> (this, ref prev_node)) {
+ prev_node = null;
+ return false;
+ }
+ }
+ }
+
+ public static inline void backtrace<G> (ref Node<G>? curr) {
+ while (curr.get_state () == State.MARKED)
+ curr = curr.get_backlink ();
+ }
+
+ public inline bool compare_and_exchange (Node<G>? old_node, State old_state, Node<G>?
new_node, State new_state) {
+#if DEBUG
+ bool b = HazardPointer.compare_and_exchange_pointer (&_succ, old_node, new_node, 3,
(size_t)old_state, (size_t)new_state);
+ stderr.printf (" Setting %p.succ to (%p, %s) if %p.succ is (%p, %s): %s\n",
this, new_node, new_state.to_string (), this, old_node, old_state.to_string (), b ? "success" : "failure");
+ return b;
+#else
+ return HazardPointer.compare_and_exchange_pointer<Node<G>> (&_succ, old_node,
new_node, 3, (size_t)old_state, (size_t)new_state);
+#endif
+ }
+
+ public inline bool compare_succ (Node<G>? next, State state) {
+ size_t cur = (size_t)AtomicPointer.get (&_succ);
+ return cur == ((size_t)next | (size_t)state);
+ }
+
+ public inline Node<G>? get_next () {
+ return get_succ (null);
+ }
+
+ public inline State get_state () {
+ return (State)((size_t)AtomicPointer.get (&_succ) & 3);
+ }
+
+ public inline Node<G>? get_succ (out State state) {
+ size_t rstate;
+ Node<G>? succ = HazardPointer.get_pointer<Node<G>> (&_succ, 3, out rstate);
+ state = (State)rstate;
+ return (owned)succ;
+ }
+
+ public inline void set_succ (Node<G>? next, State state) {
+#if DEBUG
+ stderr.printf (" Setting %p.succ to (%p, %s)\n", this, next, state.to_string ());
+#endif
+ HazardPointer.set_pointer<Node<G>> (&_succ, next, 3, (size_t)state);
+ }
+
+ public inline Node<G>? get_backlink () {
+ return HazardPointer.get_pointer<Node<G>> (&_backlink);
+ }
+
+ public inline void set_backlink (Node<G>? backlink) {
+#if DEBUG
+ stderr.printf (" Setting backlink from %p to %p\n", this, backlink);
+#endif
+ HazardPointer.compare_and_exchange_pointer<Node<G>?> (&_backlink, null, backlink);
+ }
+
+ public Node<G> *_succ;
+ public Node<G> *_backlink;
+ public G *_data;
+ }
+
+ private enum State {
+ NONE = 0,
+ MARKED = 1,
+ FLAGGED = 2
+ }
+}
diff --git a/gee/deque.vala b/gee/deque.vala
new file mode 100644
index 0000000..f2ae3e1
--- /dev/null
+++ b/gee/deque.vala
@@ -0,0 +1,123 @@
+/* deque.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * A double-ended queue.
+ *
+ * A deque can be used either as a queue (First-In-First-Out behavior) or as a
+ * stack (Last-In-First-Out behavior).
+ *
+ * The methods defined by this interface behaves exactely in the same way as
+ * the {@link Queue} methods with respect to capacity bounds.
+ *
+ * The Deque interface inherits from the {@link Queue} interface. Thus, to use
+ * a deque as a queue, you can equivalently use the folowing method set:
+ *
+ * ||<)(> ''Queue method'' ||<)(> ''Deque method'' ||
+ * || {@link Queue.offer} || {@link offer_tail} ||
+ * || {@link Queue.peek} || {@link peek_head} ||
+ * || {@link Queue.poll} || {@link poll_head} ||
+ * || {@link Queue.drain} || {@link drain_head} ||
+ *
+ * To use a deque as a stack, just use the method set that acts at the head of
+ * the deque:
+ *
+ * ||<)(> ''Operation'' ||<)(> ''Deque method'' ||
+ * || push an element || {@link offer_head} ||
+ * || peek an element || {@link peek_head} ||
+ * || pop an element || {@link poll_head} ||
+ */
+[GenericAccessors]
+public interface Vala.Deque<G> : Queue<G> {
+ /**
+ * Offers the specified element to the head of this deque.
+ *
+ * @param element the element to offer to the queue
+ *
+ * @return ``true`` if the element was added to the queue
+ */
+ public abstract bool offer_head (G element);
+
+ /**
+ * Peeks (retrieves, but not remove) an element from this queue.
+ *
+ * @return the element peeked from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? peek_head ();
+
+ /**
+ * Polls (retrieves and remove) an element from the head of this queue.
+ *
+ * @return the element polled from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? poll_head ();
+
+ /**
+ * Drains the specified amount of elements from the head of this queue in
+ * the specified recipient collection.
+ *
+ * @param recipient the recipient collection to drain the elements to
+ * @param amount the amount of elements to drain
+ *
+ * @return the amount of elements that were actually drained
+ */
+ public abstract int drain_head (Collection<G> recipient, int amount = -1);
+
+ /**
+ * Offers the specified element to the tail of this deque
+ *
+ * @param element the element to offer to the queue
+ *
+ * @return ``true`` if the element was added to the queue
+ */
+ public abstract bool offer_tail (G element);
+
+ /**
+ * Peeks (retrieves, but not remove) an element from the tail of this
+ * queue.
+ *
+ * @return the element peeked from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? peek_tail ();
+
+ /**
+ * Polls (retrieves and remove) an element from the tail of this queue.
+ *
+ * @return the element polled from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? poll_tail ();
+
+ /**
+ * Drains the specified amount of elements from the tail of this queue in
+ * the specified recipient collection.
+ *
+ * @param recipient the recipient collection to drain the elements to
+ * @param amount the amount of elements to drain
+ *
+ * @return the amount of elements that were actually drained
+ */
+ public abstract int drain_tail (Collection<G> recipient, int amount = -1);
+}
diff --git a/gee/functions.vala b/gee/functions.vala
new file mode 100644
index 0000000..a805bc8
--- /dev/null
+++ b/gee/functions.vala
@@ -0,0 +1,152 @@
+/* functions.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois, 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:
+ * Didier 'Ptitjes' Villevalois <ptitjes free fr>
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+using GLib;
+
+namespace Vala {
+
+ /**
+ * Helpers for equal, hash and compare functions.
+ *
+ * With those functions, you can retrieve the equal, hash and compare
+ * functions that best match your element, key or value types. Supported
+ * types are (non-boxed) primitive, string and ``Object`` types.
+ *
+ * A special care is taken for classes inheriting from the
+ * {@link Comparable} interface. For such types, an appropriate compare
+ * function is returned that calls {@link Comparable.compare_to}.
+ *
+ */
+ namespace Functions {
+
+ /**
+ * Get a equality testing function for a given type.
+ *
+ * @param t the type which to get an equality testing function for.
+ *
+ * @return the equality testing function corresponding to the given type.
+ */
+ public static EqualDataFunc get_equal_func_for (Type t) {
+ if (t == typeof (string)) {
+ return (a, b) => {
+ if (a == b)
+ return true;
+ else if (a == null || b == null)
+ return false;
+ else
+ return str_equal ((string) a, (string) b);
+ };
+ } else if (t.is_a (typeof (Hashable))) {
+ return (a, b) => {
+ if (a == b)
+ return true;
+ else if (a == null || b == null)
+ return false;
+ else
+ return ((Hashable<Hashable>) a).equal_to ((Hashable) b);
+ };
+ } else if (t.is_a (typeof (Comparable))) {
+ return (a, b) => {
+ if (a == b)
+ return true;
+ else if (a == null || b == null)
+ return false;
+ else
+ return ((Comparable<Comparable>) a).compare_to ((Comparable)
b) == 0;};
+ } else {
+ return (a, b) => {return direct_equal (a, b);};
+ }
+ }
+
+ /**
+ * Get a hash function for a given type.
+ *
+ * @param t the type which to get the hash function for.
+ *
+ * @return the hash function corresponding to the given type.
+ */
+ public static HashDataFunc get_hash_func_for (Type t) {
+ if (t == typeof (string)) {
+ return (a) => {
+ if (a == null)
+ return (uint)0xdeadbeef;
+ else
+ return str_hash ((string) a);
+ };
+ } else if (t.is_a (typeof (Hashable))) {
+ return (a) => {
+ if (a == null)
+ return (uint)0xdeadbeef;
+ else
+ return ((Hashable) a).hash();
+ };
+ } else {
+ return (a) => {return direct_hash (a);};
+ }
+ }
+
+ /**
+ * Get a comparator function for a given type.
+ *
+ * @param t the type which to get a comparator function for.
+ *
+ * @return the comparator function corresponding to the given type.
+ */
+ public static CompareDataFunc get_compare_func_for (Type t) {
+ if (t == typeof (string)) {
+ return (a, b) => {
+ if (a == b)
+ return 0;
+ else if (a == null)
+ return -1;
+ else if (b == null)
+ return 1;
+ else
+ return strcmp((string) a, (string) b);
+ };
+ } else if (t.is_a (typeof (Comparable))) {
+ return (a, b) => {
+ if (a == b)
+ return 0;
+ else if (a == null)
+ return -1;
+ else if (b == null)
+ return 1;
+ else
+ return ((Comparable<Comparable>) a).compare_to ((Comparable)
b);
+ };
+ } else {
+ return (_val1, _val2) => {
+ long val1 = (long)_val1, val2 = (long)_val2;
+ if (val1 > val2) {
+ return 1;
+ } else if (val1 == val2) {
+ return 0;
+ } else {
+ return -1;
+ }
+ };
+ }
+ }
+ }
+}
diff --git a/gee/hashable.vala b/gee/hashable.vala
new file mode 100644
index 0000000..9b806f1
--- /dev/null
+++ b/gee/hashable.vala
@@ -0,0 +1,44 @@
+/* hashable.vala
+ *
+ * Copyright (C) 2010 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 <uzytkwonik2 gmail com>
+ */
+
+/**
+ * This interface defines a hash function amongs instances of each class
+ * implementing it.
+ *
+ * @see Comparable
+ */
+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.
+ *
+ * @return hash of an object
+ */
+ public abstract uint hash ();
+
+ /**
+ * Compares this object with the specifed object.
+ *
+ * @return true if objects are equal
+ */
+ public abstract bool equal_to (G object);
+}
diff --git a/gee/hashmap.vala b/gee/hashmap.vala
index 9085f10..158e787 100644
--- a/gee/hashmap.vala
+++ b/gee/hashmap.vala
@@ -25,73 +25,162 @@
using GLib;
/**
- * Hashtable implementation of the Map interface.
+ * Hash table implementation of the {@link Map} interface.
+ *
+ * This implementation is better fit for highly heterogenous key values.
+ * In case of high key hashes redundancy or higher amount of data prefer using
+ * tree implementation like {@link TreeMap}.
+ *
+ * @see TreeMap
*/
-public class Vala.HashMap<K,V> : Map<K,V> {
+public class Vala.HashMap<K,V> : Vala.AbstractMap<K,V> {
+ /**
+ * {@inheritDoc}
+ */
public override int size {
get { return _nnodes; }
}
- public HashFunc<K> key_hash_func {
- set { _key_hash_func = value; }
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
}
- public EqualFunc<K> key_equal_func {
- set { _key_equal_func = value; }
+ /**
+ * {@inheritDoc}
+ */
+ public override Set<K> keys {
+ owned get {
+ Set<K> keys = _keys;
+ if (_keys == null) {
+ keys = new KeySet<K,V> (this);
+ _keys = keys;
+ keys.add_weak_pointer ((void**) (&_keys));
+ }
+ return keys;
+ }
}
- public EqualFunc<V> value_equal_func {
- set { _value_equal_func = value; }
+ /**
+ * {@inheritDoc}
+ */
+ public override Collection<V> values {
+ owned get {
+ Collection<K> values = _values;
+ if (_values == null) {
+ values = new ValueCollection<K,V> (this);
+ _values = values;
+ values.add_weak_pointer ((void**) (&_values));
+ }
+ return values;
+ }
}
+ /**
+ * {@inheritDoc}
+ */
+ public override Set<Map.Entry<K,V>> entries {
+ owned get {
+ Set<Map.Entry<K,V>> entries = _entries;
+ if (_entries == null) {
+ entries = new EntrySet<K,V> (this);
+ _entries = entries;
+ entries.add_weak_pointer ((void**) (&_entries));
+ }
+ return entries;
+ }
+ }
+
+ /**
+ * The keys' hash function.
+ */
+ [CCode (notify = false)]
+ public HashDataFunc<K> key_hash_func { private set; get; }
+
+ /**
+ * The keys' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<K> key_equal_func { private set; get; }
+
+ /**
+ * The values' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<V> value_equal_func { private set; get; }
+
private int _array_size;
private int _nnodes;
private Node<K,V>[] _nodes;
+ private weak Set<K> _keys;
+ private weak Collection<V> _values;
+ private weak Set<Map.Entry<K,V>> _entries;
+
// concurrent modification protection
private int _stamp = 0;
- private HashFunc<K> _key_hash_func;
- private EqualFunc<K> _key_equal_func;
- private EqualFunc<V> _value_equal_func;
-
private const int MIN_SIZE = 11;
private const int MAX_SIZE = 13845163;
- public HashMap (HashFunc<K> key_hash_func = GLib.direct_hash, EqualFunc<K> key_equal_func =
GLib.direct_equal, EqualFunc<V> value_equal_func = GLib.direct_equal) {
+ /**
+ * Constructs a new, empty hash map.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param key_hash_func an optional key hash function
+ * @param key_equal_func an optional key equality testing function
+ * @param value_equal_func an optional value equality testing function
+ */
+ public HashMap (owned HashDataFunc<K>? key_hash_func = null, owned EqualDataFunc<K>? key_equal_func =
null, owned EqualDataFunc<V>? value_equal_func = null) {
+ if (key_hash_func == null) {
+ key_hash_func = Functions.get_hash_func_for (typeof (K));
+ }
+ if (key_equal_func == null) {
+ key_equal_func = Functions.get_equal_func_for (typeof (K));
+ }
+ 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;
+
_array_size = MIN_SIZE;
_nodes = new Node<K,V>[_array_size];
}
- public override Set<K> get_keys () {
- return new KeySet<K,V> (this);
- }
-
- public override Collection<V> get_values () {
- return new ValueCollection<K,V> (this);
- }
-
- public override Vala.MapIterator<K,V> map_iterator () {
- return new MapIterator<K,V> (this);
- }
-
private Node<K,V>** lookup_node (K key) {
- uint hash_value = _key_hash_func (key);
+ uint hash_value = key_hash_func (key);
Node<K,V>** node = &_nodes[hash_value % _array_size];
- while ((*node) != null && (hash_value != (*node)->key_hash || !_key_equal_func ((*node)->key,
key))) {
+ while ((*node) != null && (hash_value != (*node)->key_hash || !key_equal_func ((*node)->key,
key))) {
node = &((*node)->next);
}
return node;
}
- public override bool contains (K key) {
+ /**
+ * {@inheritDoc}
+ */
+ public override bool has_key (K key) {
Node<K,V>** node = lookup_node (key);
return (*node != null);
}
+ /**
+ * {@inheritDoc}
+ */
+ public override bool has (K key, V value) {
+ Node<K,V>** node = lookup_node (key);
+ return (*node != null && value_equal_func ((*node)->value, value));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public override V? get (K key) {
Node<K,V>* node = (*lookup_node (key));
if (node != null) {
@@ -101,12 +190,15 @@ public class Vala.HashMap<K,V> : Map<K,V> {
}
}
+ /**
+ * {@inheritDoc}
+ */
public override void set (K key, V value) {
Node<K,V>** node = lookup_node (key);
if (*node != null) {
(*node)->value = value;
} else {
- uint hash_value = _key_hash_func (key);
+ uint hash_value = key_hash_func (key);
*node = new Node<K,V> (key, value, hash_value);
_nnodes++;
resize ();
@@ -114,25 +206,20 @@ public class Vala.HashMap<K,V> : Map<K,V> {
_stamp++;
}
- public override bool remove (K key) {
- Node<K,V>** node = lookup_node (key);
- if (*node != null) {
- Node<K,V> next = (owned) (*node)->next;
-
- (*node)->key = null;
- (*node)->value = null;
- delete *node;
-
- *node = (owned) next;
-
- _nnodes--;
- resize ();
- _stamp++;
- return true;
+ /**
+ * {@inheritDoc}
+ */
+ public override bool unset (K key, out V? value = null) {
+ bool b = unset_helper (key, out value);
+ if(b) {
+ resize();
}
- return false;
+ return b;
}
+ /**
+ * {@inheritDoc}
+ */
public override void clear () {
for (int i = 0; i < _array_size; i++) {
Node<K,V> node = (owned) _nodes[i];
@@ -147,7 +234,36 @@ public class Vala.HashMap<K,V> : Map<K,V> {
resize ();
}
- private void resize () {
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.MapIterator<K,V> map_iterator () {
+ return new MapIterator<K,V> (this);
+ }
+
+ private inline bool unset_helper (K key, out V? value = null) {
+ Node<K,V>** node = lookup_node (key);
+ if (*node != null) {
+ Node<K,V> next = (owned) (*node)->next;
+
+ value = (owned) (*node)->value;
+
+ (*node)->key = null;
+ (*node)->value = null;
+ delete *node;
+
+ *node = (owned) next;
+
+ _nnodes--;
+ _stamp++;
+ return true;
+ } else {
+ value = null;
+ }
+ return false;
+ }
+
+ private inline void resize () {
if ((_array_size >= 3 * _nnodes && _array_size >= MIN_SIZE) ||
(3 * _array_size <= _nnodes && _array_size < MAX_SIZE)) {
int new_array_size = (int) SpacedPrimes.closest (_nnodes);
@@ -180,27 +296,48 @@ public class Vala.HashMap<K,V> : Map<K,V> {
public V value;
public Node<K,V> next;
public uint key_hash;
+ public unowned Map.Entry<K,V>? entry;
public Node (owned K k, owned V v, uint hash) {
key = (owned) k;
value = (owned) v;
key_hash = hash;
+ entry = null;
}
}
- private class KeySet<K,V> : Set<K> {
- public HashMap<K,V> map {
- set { _map = value; }
+ private class Entry<K,V> : Map.Entry<K,V> {
+ private unowned Node<K,V> _node;
+
+ public static Map.Entry<K,V> entry_for<K,V> (Node<K,V> node) {
+ Map.Entry<K,V> result = node.entry;
+ if (node.entry == null) {
+ result = new Entry<K,V> (node);
+ node.entry = result;
+ result.add_weak_pointer ((void**) (&node.entry));
+ }
+ return result;
}
- private HashMap<K,V> _map;
+ public Entry (Node<K,V> node) {
+ _node = node;
+ }
- public KeySet (HashMap map) {
- this.map = map;
+ public override K key { get { return _node.key; } }
+
+ public override V value {
+ get { return _node.value; }
+ set { _node.value = value; }
}
- public override Type get_element_type () {
- return typeof (K);
+ public override bool read_only { get { return false; } }
+ }
+
+ private class KeySet<K,V> : AbstractSet<K> {
+ private HashMap<K,V> _map;
+
+ public KeySet (HashMap map) {
+ _map = map;
}
public override Iterator<K> iterator () {
@@ -211,6 +348,10 @@ public class Vala.HashMap<K,V> : Map<K,V> {
get { return _map.size; }
}
+ public override bool read_only {
+ get { return true; }
+ }
+
public override bool add (K key) {
assert_not_reached ();
}
@@ -224,170 +365,343 @@ public class Vala.HashMap<K,V> : Map<K,V> {
}
public override bool contains (K key) {
- return _map.contains (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 MapIterator<K,V> : Vala.MapIterator<K, V> {
- public HashMap<K,V> map {
- set {
- _map = value;
- _stamp = _map._stamp;
+ private class ValueCollection<K,V> : AbstractCollection<V> {
+ private HashMap<K,V> _map;
+
+ public ValueCollection (HashMap map) {
+ _map = map;
+ }
+
+ public override Iterator<V> iterator () {
+ return new ValueIterator<K,V> (_map);
+ }
+
+ public override int size {
+ get { return _map.size; }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public override bool add (V value) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (V value) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (V value) {
+ Iterator<V> it = iterator ();
+ while (it.next ()) {
+ if (_map.value_equal_func (it.get (), value)) {
+ return true;
+ }
}
+ 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>> {
private HashMap<K,V> _map;
- private int _index = -1;
- private weak Node<K,V> _node;
+
+ public EntrySet (HashMap<K,V> map) {
+ _map = map;
+ }
+
+ public override Iterator<Map.Entry<K, V>> iterator () {
+ return new EntryIterator<K,V> (_map);
+ }
+
+ public override int size {
+ get { return _map.size; }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public override bool add (Map.Entry<K, V> entry) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (Map.Entry<K, V> entry) {
+ assert_not_reached ();
+ }
+
+ 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
- private int _stamp;
+ protected int _stamp;
- public MapIterator (HashMap map) {
- this.map = map;
+ public NodeIterator (HashMap map) {
+ _map = map;
+ _stamp = _map._stamp;
}
- public override bool next () {
- if (_node != null) {
- _node = _node.next;
- }
- while (_node == null && _index + 1 < _map._array_size) {
- _index++;
- _node = _map._nodes[_index];
+ public bool next () {
+ assert (_stamp == _map._stamp);
+ if (!has_next ()) {
+ return false;
}
+ _node = _next;
+ _next = null;
return (_node != null);
}
- public override K? get_key () {
+ public bool has_next () {
assert (_stamp == _map._stamp);
- assert (_node != null);
- return _node.key;
+ if (_next == null) {
+ _next = _node;
+ if (_next != null) {
+ _next = _next.next;
+ }
+ while (_next == null && _index + 1 < _map._array_size) {
+ _index++;
+ _next = _map._nodes[_index];
+ }
+ }
+ return (_next != null);
}
- public override V? get_value () {
- assert (_stamp == _map._stamp);
- assert (_node != null);
- return _node.value;
+ public virtual bool read_only {
+ get {
+ return true;
+ }
}
- }
- private class KeyIterator<K,V> : Iterator<K> {
- public HashMap<K,V> map {
- set {
- _map = value;
- _stamp = _map._stamp;
+ public bool valid {
+ get {
+ return _node != null;
}
}
+ }
- private HashMap<K,V> _map;
- private int _index = -1;
- private weak Node<K,V> _node;
+ private class KeyIterator<K,V> : NodeIterator<K,V>, Traversable<K>, Iterator<K> {
+ public KeyIterator (HashMap map) {
+ base (map);
+ }
- // concurrent modification protection
- private int _stamp;
+ public new K get () {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ return _node.key;
+ }
- public KeyIterator (HashMap map) {
- this.map = map;
+ public void remove () {
+ assert_not_reached ();
}
- public override bool next () {
+ public bool foreach(ForallFunc<K> f) {
if (_node != null) {
- _node = _node.next;
- }
- while (_node == null && _index + 1 < _map._array_size) {
- _index++;
- _node = _map._nodes[_index];
+ if (!f(_node.key)) {
+ return false;
+ }
+ if(_next == null) {
+ _next = _node.next;
+ }
}
- return (_node != null);
+ do {
+ while(_next != null) {
+ _node = _next;
+ if (!f(_node.key)) {
+ return false;
+ }
+ _next = _next.next;
+ }
+ if (_index + 1 < _map._array_size) {
+ _next = _map._nodes[++_index];
+ } else {
+ return true;
+ }
+ } while(true);
+ }
+ }
+
+ private class MapIterator<K,V> : NodeIterator<K,V>, Vala.MapIterator<K,V> {
+ public MapIterator (HashMap map) {
+ base (map);
}
- public override K? get () {
+ public new K get_key () {
assert (_stamp == _map._stamp);
assert (_node != null);
return _node.key;
}
- }
- private class ValueCollection<K,V> : Collection<V> {
- public HashMap<K,V> map {
- set { _map = value; }
+ public void unset () {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ has_next ();
+ _map.unset_helper (_node.key);
+ _node = null;
+ _stamp = _map._stamp;
}
- private HashMap<K,V> _map;
-
- public ValueCollection (HashMap map) {
- this.map = map;
+ public V get_value () {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ return _node.value;
}
- public override Type get_element_type () {
- return typeof (V);
+ public void set_value (V value) {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ _map.set (_node.key, value);
+ _stamp = _map._stamp;
}
- public override Iterator<V> iterator () {
- return new ValueIterator<K,V> (_map);
+ public bool mutable {
+ get {
+ return true;
+ }
}
- public override int size {
- get { return _map.size; }
+ public override bool read_only {
+ get {
+ return false;
+ }
}
+ }
- public override bool add (V value) {
- assert_not_reached ();
+ private class ValueIterator<K,V> : NodeIterator<K,V>, Traversable<V>, Iterator<V> {
+ public ValueIterator (HashMap map) {
+ base (map);
}
- public override void clear () {
- assert_not_reached ();
+ public new V get () {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ return _node.value;
}
- public override bool remove (V value) {
+ public void remove () {
assert_not_reached ();
}
- public override bool contains (V value) {
- Iterator<V> it = iterator ();
- while (it.next ()) {
- if (_map._value_equal_func (it.get (), value)) {
- return true;
+ public bool foreach(ForallFunc<V> f) {
+ if (_node != null) {
+ if (!f(_node.value)) {
+ return false;
+ }
+ if(_next == null) {
+ _next = _node.next;
}
}
- return false;
+ do {
+ while(_next != null) {
+ _node = _next;
+ if (!f(_node.value)) {
+ return false;
+ }
+ _next = _next.next;
+ }
+ if (_index + 1 < _map._array_size) {
+ _next = _map._nodes[++_index];
+ } else {
+ return true;
+ }
+ } while(true);
}
}
- private class ValueIterator<K,V> : Iterator<V> {
- public HashMap<K,V> map {
- set {
- _map = value;
- _stamp = _map._stamp;
- }
+ private class EntryIterator<K,V> : NodeIterator<K,V>, Traversable<Map.Entry<K,V>>,
Iterator<Map.Entry<K,V>> {
+ public EntryIterator (HashMap map) {
+ base (map);
}
- private HashMap<V,K> _map;
- private int _index = -1;
- private weak Node<K,V> _node;
-
- // concurrent modification protection
- private int _stamp;
+ public new Map.Entry<K,V> get () {
+ assert (_stamp == _map._stamp);
+ assert (_node != null);
+ return Entry<K,V>.entry_for<K,V> (_node);
+ }
- public ValueIterator (HashMap map) {
- this.map = map;
+ public void remove () {
+ assert_not_reached ();
}
- public override bool next () {
+ public bool foreach(ForallFunc<Map.Entry<K,V>> f) {
if (_node != null) {
- _node = _node.next;
- }
- while (_node == null && _index + 1 < _map._array_size) {
- _index++;
- _node = _map._nodes[_index];
+ if (!f(Entry<K,V>.entry_for<K,V> (_node))) {
+ return false;
+ }
+ if(_next == null) {
+ _next = _node.next;
+ }
}
- return (_node != null);
- }
-
- public override V? get () {
- assert (_stamp == _map._stamp);
- assert (_node != null);
- return _node.value;
+ do {
+ while(_next != null) {
+ _node = _next;
+ if (!f(Entry<K,V>.entry_for<K,V> (_node))) {
+ return false;
+ }
+ _next = _next.next;
+ }
+ if (_index + 1 < _map._array_size) {
+ _next = _map._nodes[++_index];
+ } else {
+ return true;
+ }
+ } while(true);
}
}
}
diff --git a/gee/hashmultimap.vala b/gee/hashmultimap.vala
new file mode 100644
index 0000000..ca57fb8
--- /dev/null
+++ b/gee/hashmultimap.vala
@@ -0,0 +1,76 @@
+/* hashmultimap.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ */
+
+/**
+ * Hash table implementation of the {@link MultiMap} interface.
+ */
+public class Vala.HashMultiMap<K,V> : AbstractMultiMap<K,V> {
+ public HashDataFunc<K> key_hash_func {
+ get { return ((HashMap<K, Set<V>>) _storage_map).key_hash_func; }
+ }
+
+ public EqualDataFunc<K> key_equal_func {
+ get { return ((HashMap<K, Set<V>>) _storage_map).key_equal_func; }
+ }
+
+ [CCode (notify = false)]
+ public HashDataFunc<V> value_hash_func { private set; get; }
+
+ [CCode (notify = false)]
+ public EqualDataFunc<V> value_equal_func { private set; get; }
+
+ /**
+ * Constructs a new, empty hash multimap.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param key_hash_func an optional key hash function
+ * @param key_equal_func an optional key equality testing function
+ * @param value_hash_func an optional value hash function
+ * @param value_equal_func an optional value equality testing function
+ */
+ 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))));
+ 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;
+ }
+
+ protected override Collection<V> create_value_storage () {
+ return new HashSet<V> (_value_hash_func, _value_equal_func);
+ }
+
+ protected override MultiSet<K> create_multi_key_set () {
+ return new HashMultiSet<K> (key_hash_func, key_equal_func);
+ }
+
+ protected override EqualDataFunc get_value_equal_func () {
+ return _value_equal_func;
+ }
+}
diff --git a/gee/hashmultiset.vala b/gee/hashmultiset.vala
new file mode 100644
index 0000000..78b8500
--- /dev/null
+++ b/gee/hashmultiset.vala
@@ -0,0 +1,47 @@
+/* hashmultiset.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ */
+
+/**
+ * Hash table implementation of the {@link MultiSet} interface.
+ */
+public class Vala.HashMultiSet<G> : AbstractMultiSet<G> {
+ public HashDataFunc<G> hash_func {
+ get { return ((HashMap<G, int>) _storage_map).key_hash_func; }
+ }
+
+ public EqualDataFunc<G> equal_func {
+ get { return ((HashMap<G, int>) _storage_map).key_equal_func; }
+ }
+
+ /**
+ * Constructs a new, empty hash multi set.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @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) {
+ base (new HashMap<G, int> (hash_func, equal_func));
+ }
+}
diff --git a/gee/hashset.vala b/gee/hashset.vala
index 6ca0dfa..e4821d7 100644
--- a/gee/hashset.vala
+++ b/gee/hashset.vala
@@ -24,21 +24,46 @@
using GLib;
+namespace Vala {
+ public delegate uint HashDataFunc<T> (T v);
+ public delegate bool EqualDataFunc<T> (T a, T b);
+}
+
/**
- * Hashtable implementation of the Set interface.
+ * Hash table implementation of the {@link Set} interface.
+ *
+ * This implementation is better fit for highly heterogenous values.
+ * In case of high value hashes redundancy or higher amount of data prefer using
+ * tree implementation like {@link TreeSet}.
+ *
+ * @see TreeSet
*/
-public class Vala.HashSet<G> : Set<G> {
+public class Vala.HashSet<G> : AbstractSet<G> {
+ /**
+ * {@inheritDoc}
+ */
public override int size {
get { return _nnodes; }
}
- public HashFunc<G> hash_func {
- set { _hash_func = value; }
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
}
- public EqualFunc<G> equal_func {
- set { _equal_func = value; }
- }
+ /**
+ * The elements' hash function.
+ */
+ [CCode (notify = false)]
+ public HashDataFunc<G> hash_func { private set; get; }
+
+ /**
+ * The elements' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<G> equal_func { private set; get; }
private int _array_size;
private int _nnodes;
@@ -47,13 +72,25 @@ public class Vala.HashSet<G> : Set<G> {
// concurrent modification protection
private int _stamp = 0;
- private HashFunc<G> _hash_func;
- private EqualFunc<G> _equal_func;
-
private const int MIN_SIZE = 11;
private const int MAX_SIZE = 13845163;
- public HashSet (HashFunc<G> hash_func = GLib.direct_hash, EqualFunc<G> equal_func =
GLib.direct_equal) {
+ /**
+ * Constructs a new, empty hash set.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param hash_func an optional hash function
+ * @param equal_func an optional equality testing function
+ */
+ public HashSet (owned HashDataFunc<G>? hash_func = null, owned EqualDataFunc<G>? equal_func = null) {
+ if (hash_func == null) {
+ hash_func = Functions.get_hash_func_for (typeof (G));
+ }
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
this.hash_func = hash_func;
this.equal_func = equal_func;
_array_size = MIN_SIZE;
@@ -61,33 +98,38 @@ public class Vala.HashSet<G> : Set<G> {
}
private Node<G>** lookup_node (G key) {
- uint hash_value = _hash_func (key);
+ uint hash_value = hash_func (key);
Node<G>** node = &_nodes[hash_value % _array_size];
- while ((*node) != null && (hash_value != (*node)->key_hash || !_equal_func ((*node)->key,
key))) {
+ while ((*node) != null && (hash_value != (*node)->key_hash || !equal_func ((*node)->key,
key))) {
node = &((*node)->next);
}
return node;
}
+ /**
+ * {@inheritDoc}
+ */
public override bool contains (G key) {
Node<G>** node = lookup_node (key);
return (*node != null);
}
- public override Type get_element_type () {
- return typeof (G);
- }
-
+ /**
+ * {@inheritDoc}
+ */
public override Vala.Iterator<G> iterator () {
return new Iterator<G> (this);
}
+ /**
+ * {@inheritDoc}
+ */
public override bool add (G key) {
Node<G>** node = lookup_node (key);
if (*node != null) {
return false;
} else {
- uint hash_value = _hash_func (key);
+ uint hash_value = hash_func (key);
*node = new Node<G> (key, hash_value);
_nnodes++;
resize ();
@@ -96,24 +138,20 @@ public class Vala.HashSet<G> : Set<G> {
}
}
+ /**
+ * {@inheritDoc}
+ */
public override bool remove (G key) {
- Node<G>** node = lookup_node (key);
- if (*node != null) {
- Node<G> next = (owned) (*node)->next;
-
- (*node)->key = null;
- delete *node;
-
- *node = (owned) next;
-
- _nnodes--;
+ bool b = remove_helper(key);
+ if(b) {
resize ();
- _stamp++;
- return true;
}
- return false;
+ return b;
}
+ /**
+ * {@inheritDoc}
+ */
public override void clear () {
for (int i = 0; i < _array_size; i++) {
Node<G> node = (owned) _nodes[i];
@@ -127,6 +165,24 @@ public class Vala.HashSet<G> : Set<G> {
resize ();
}
+ private inline bool remove_helper (G key) {
+ Node<G>** node = lookup_node (key);
+ if (*node != null) {
+ assert (*node != null);
+ Node<G> next = (owned) (*node)->next;
+
+ (*node)->key = null;
+ delete *node;
+
+ *node = (owned) next;
+
+ _nnodes--;
+ _stamp++;
+ return true;
+ }
+ return false;
+ }
+
private void resize () {
if ((_array_size >= 3 * _nnodes && _array_size >= MIN_SIZE) ||
(3 * _array_size <= _nnodes && _array_size < MAX_SIZE)) {
@@ -166,41 +222,110 @@ public class Vala.HashSet<G> : Set<G> {
}
}
- private class Iterator<G> : Vala.Iterator<G> {
- public HashSet<G> set {
- set {
- _set = value;
- _stamp = _set._stamp;
- }
- }
-
+ 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) {
- this.set = set;
+ _set = set;
+ _stamp = _set._stamp;
}
- public override bool next () {
- if (_node != null) {
- _node = _node.next;
- }
- while (_node == null && _index + 1 < _set._array_size) {
- _index++;
- _node = _set._nodes[_index];
+ public bool next () {
+ assert (_stamp == _set._stamp);
+ if (!has_next ()) {
+ return false;
}
+ _node = _next;
+ _next = null;
return (_node != null);
}
- public override G? get () {
+ public bool has_next () {
+ assert (_stamp == _set._stamp);
+ if (_next == null) {
+ _next = _node;
+ if (_next != null) {
+ _next = _next.next;
+ }
+ while (_next == null && _index + 1 < _set._array_size) {
+ _index++;
+ _next = _set._nodes[_index];
+ }
+ }
+ return (_next != null);
+ }
+
+ public new G get () {
assert (_stamp == _set._stamp);
assert (_node != null);
return _node.key;
}
+
+ public void remove () {
+ assert (_stamp == _set._stamp);
+ assert (_node != null);
+ has_next ();
+ _set.remove_helper (_node.key);
+ _node = null;
+ _stamp = _set._stamp;
+ }
+
+ public bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool valid {
+ get {
+ return _node != null;
+ }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ assert (_stamp == _set._stamp);
+ unowned Node<G>? node = _node, next = _next, current = null, prev = null;
+ if (node != null) {
+ if (!f (node.key)) {
+ return false;
+ }
+ prev = node;
+ current = node.next;
+ }
+ if (next != null) {
+ if (!f (next.key)) {
+ _node = next;
+ _next = null;
+ return false;
+ }
+ prev = next;
+ current = next.next;
+ }
+ do {
+ while (current != null) {
+ if (!f (current.key)) {
+ _node = current;
+ _next = null;
+ return false;
+ }
+ prev = current;
+ current = current.next;
+ }
+ while (current == null && _index + 1 < _set._array_size) {
+ _index++;
+ current = _set._nodes[_index];
+ }
+ } while (current != null);
+ _node = prev;
+ _next = null;
+ return true;
+ }
}
}
diff --git a/gee/hazardpointer.vala b/gee/hazardpointer.vala
new file mode 100644
index 0000000..a26fbeb
--- /dev/null
+++ b/gee/hazardpointer.vala
@@ -0,0 +1,775 @@
+/* hazardpointer.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * Hazard pointer is a method of protecting a pointer shared by many threads.
+ * If you want to use atomic pointer that may be freed you should use following code:
+ *
+ * {{{
+ * string *shared_pointer = ...;
+ * HazardPointer<string> hptr = HazardPointer.get_hazard_pointer (&shared_pointer);
+ * // my_string contains value from shared_pinter. It is valid as long as hptr is alive.
+ * unowned string my_string = ptr.get ();
+ * // instead of delete
+ * ptr.release ((ptr) => {string *sptr = ptr;string ref = (owned)sptr;});
+ * });
+ * }}}
+ *
+ * In some cases you may use helper methods which might involve copying of object (and are unsafe for
unowned objects):
+ * {{{
+ * Gtk.Window *window = ...;
+ * Gtk.Window? local_window = HazardPointer.get_pointer (&window);
+ * HazardPointer.set_pointer (&window, ...)
+ * local_window = HazardPointer.exchange_pointer (&window, null);
+ * HazardPointer.compare_and_exchange (&window, null, local_window);
+ * }}}
+ *
+ * The class also provides helper methods if least significant bits are used for storing flags.
+ *
+ * HazardPointers are not thread-safe (unless documentation states otherwise).
+ */
+[Compact]
+public class Vala.HazardPointer<G> { // FIXME: Make it a struct
+ /**
+ * Creates a hazard pointer for a pointer.
+ *
+ * @param ptr Protected pointer
+ */
+ public HazardPointer (G *ptr) {
+ this._node = acquire ();
+ this._node.set ((void *)ptr);
+ }
+
+ /**
+ * Create a hazard pointer from Node.
+ */
+ internal HazardPointer.from_node (Node node) {
+ this._node = node;
+ }
+
+ /**
+ * Gets hazard pointer from atomic pointer safely.
+ *
+ * @param aptr Atomic pointer.
+ * @param mask Mask of bits.
+ * @param mask_out Result of mask.
+ * @return Hazard pointer containing the element.
+ */
+ public static HazardPointer<G>? get_hazard_pointer<G> (G **aptr, size_t mask = 0, out size_t mask_out
= null) {
+ unowned Node node = acquire ();
+ void *rptr = null;
+ void *ptr = null;
+ mask_out = 0;
+ do {
+ rptr = AtomicPointer.get ((void **)aptr);
+ ptr = (void *)((size_t) rptr & ~mask);
+ mask_out = (size_t) rptr & mask;
+ node.set (ptr);
+ } while (rptr != AtomicPointer.get ((void **)aptr));
+ if (ptr != null) {
+ return new HazardPointer<G>.from_node (node);
+ } else {
+ node.release ();
+ return null;
+ }
+ }
+
+ /**
+ * Copy an object from atomic pointer.
+ *
+ * @param aptr Atomic pointer.
+ * @param mask Mask of flags.
+ * @param mask_out Result of mask.
+ * @return A copy of object from atomic pointer.
+ */
+ public static G? get_pointer<G> (G **aptr, size_t mask = 0, out size_t mask_out = null) {
+ unowned Node node = acquire ();
+ void *rptr = null;
+ void *ptr = null;
+ mask_out = 0;
+ do {
+ rptr = AtomicPointer.get ((void **)aptr);
+ ptr = (void *)((size_t) rptr & ~mask);
+ mask_out = (size_t) rptr & mask;
+ node.set (ptr);
+ } while (rptr != AtomicPointer.get ((void **)aptr));
+ G? res = (G *)ptr;
+ node.release ();
+ return res;
+ }
+
+ /**
+ * Exchange objects safly.
+ *
+ * @param aptr Atomic pointer.
+ * @param new_ptr New value
+ * @param mask Mask of flags.
+ * @param new_mask New mask.
+ * @param old_mask Previous mask mask.
+ * @return Hazard pointer containing old value.
+ */
+ public static HazardPointer<G>? exchange_hazard_pointer<G> (G **aptr, owned G? new_ptr, size_t mask =
0, size_t new_mask = 0, out size_t old_mask = null) {
+ unowned Node? new_node = null;
+ if (new_ptr != null) {
+ new_node = acquire ();
+ new_node.set (new_ptr);
+ }
+ old_mask = 0;
+ void *new_rptr = (void *)((size_t)((owned) new_ptr) | (mask & new_mask));
+ unowned Node node = acquire ();
+ void *rptr = null;
+ void *ptr = null;
+ do {
+ rptr = AtomicPointer.get ((void **)aptr);
+ ptr = (void *)((size_t) rptr & ~mask);
+ old_mask = (size_t) rptr & mask;
+ node.set (ptr);
+ } while (!AtomicPointer.compare_and_exchange((void **)aptr, rptr, new_rptr));
+ if (new_node != null)
+ new_node.release ();
+ if (ptr != null) {
+ return new HazardPointer<G>.from_node (node);
+ } else {
+ node.release ();
+ return null;
+ }
+ }
+
+ /**
+ * Sets object safely
+ *
+ * @param aptr Atomic pointer.
+ * @param new_ptr New value
+ * @param mask Mask of flags.
+ * @param new_mask New mask.
+ */
+ 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);
+ }
+ }
+
+ /**
+ * Exchange objects safly.
+ *
+ * @param aptr Atomic pointer.
+ * @param new_ptr New value
+ * @param mask Mask of flags.
+ * @param new_mask New mask.
+ * @param old_mask Previous mask mask.
+ * @return Value that was previously stored.
+ */
+ public static G? exchange_pointer<G> (G **aptr, owned G? new_ptr, size_t mask = 0, size_t new_mask =
0, out size_t old_mask = null) {
+ HazardPointer<G>? ptr = exchange_hazard_pointer<G> (aptr, new_ptr, mask, new_mask, out
old_mask);
+ G? rptr = ptr != null ? ptr.get () : null;
+ return rptr;
+ }
+
+ /**
+ * Compares and exchanges objects.
+ *
+ * @param aptr Atomic pointer.
+ * @param old_ptr Old pointer.
+ * @param _new_ptr New value.
+ * @param old_mask Old mask.
+ * @param new_mask New mask.
+ * @return Value that was previously stored.
+ */
+ public static bool compare_and_exchange_pointer<G> (G **aptr, G? old_ptr, owned G? _new_ptr, size_t
mask = 0, size_t old_mask = 0, size_t new_mask = 0) {
+ G *new_ptr = (owned)_new_ptr;
+ void *new_rptr = (void *)((size_t)(new_ptr) | (mask & new_mask));
+ 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) {
+ Context.get_current_context ()->release_ptr (old_ptr, (owned)notify);
+ }
+ } else if (new_ptr != null) {
+ _new_ptr = (owned)new_ptr;
+ }
+ return success;
+ }
+
+ ~HazardPointer () {
+ _node.release ();
+ }
+
+ /**
+ * Gets the pointer hold by hazard pointer.
+ *
+ * @param other_thread Have to be set to ``true`` if accessed from thread that did not create this
thread.
+ * @return The value hold by pointer.
+ */
+ public inline new unowned G get (bool other_thread = false) {
+ return _node[other_thread];
+ }
+
+ /**
+ * Free the pointer.
+ *
+ * @param notify method freeing object
+ */
+ public void release (owned DestroyNotify notify) {
+ unowned G item = _node[false];
+ _node.set (null);
+ if (item != null) {
+ Context.get_current_context ()->release_ptr (item, (owned)notify);
+ }
+ }
+
+ /**
+ * Sets default policy (i.e. default policy for user-created contexts).
+ * The policy must be concrete and should not be blocking.
+ *
+ * @param policy New default policy.
+ */
+ public static void set_default_policy (Policy policy) requires (policy.is_concrete ()) {
+ if (policy.is_blocking ())
+ warning ("Setting blocking defautl Vala.HazardPointer.Policy (there may be a
deadlock).\n");
+ AtomicInt.set(ref _default_policy, (int)policy);
+ }
+
+ /**
+ * Sets thread exit policy (i.e. default policy for the top-most Context).
+ * The policy must be concrete and should not be unsafe.
+ *
+ * @param policy New thread policy.
+ */
+ public static void set_thread_exit_policy (Policy policy) requires (policy.is_concrete ()) {
+ if (!policy.is_safe ())
+ warning ("Setting unsafe globale thread-exit Vala.HazardPointer.Policy (there may be
a memory leak).\n");
+ AtomicInt.set(ref _thread_exit_policy, (int)policy);
+ }
+
+ /**
+ * Sets release (i.e. how exactly the released objects arefreed).
+ *
+ * The method can be only set before any objects is released and is not thread-safe.
+ *
+ * @param policy New release policy.
+ */
+ public static bool set_release_policy (ReleasePolicy policy) {
+ int old_policy = AtomicInt.get (ref release_policy);
+ if ((old_policy & (sizeof(int) * 8 - 1)) != 0) {
+ critical ("Attempt to change the policy of running helper. Failing.");
+ return false;
+ }
+ if (!AtomicInt.compare_and_exchange (ref release_policy, old_policy, (int)policy)) {
+ critical ("Concurrent access to release policy detected. Failing.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Policy determines what happens on exit from Context.
+ */
+ public enum Policy {
+ /**
+ * Performs default action on exit from thread.
+ */
+ DEFAULT,
+ /**
+ * Performs the same action as on exit from current thread.
+ */
+ THREAD_EXIT,
+ /**
+ * Goes through the free list and attempts to free un-freed elements.
+ */
+ TRY_FREE,
+ /**
+ * Goes through the free list and attempts to free un-freed elements
+ * untill all elements are freed.
+ */
+ FREE,
+ /**
+ * Release the un-freed elements to either helper thread or to main loop.
+ * Please note if the operation would block it is not performed.
+ */
+ TRY_RELEASE,
+ /**
+ * Release the un-freed elements to either helper thread or to main loop.
+ * Please note it may block while adding to queue.
+ */
+ RELEASE;
+
+ /**
+ * Checks if the policy is concrete or if it depends on global variables.
+ *
+ * @return ``true`` if this policy does not depend on global variables
+ */
+ public bool is_concrete () {
+ switch (this) {
+ case DEFAULT:
+ case THREAD_EXIT:
+ return false;
+ case TRY_FREE:
+ case FREE:
+ case TRY_RELEASE:
+ case RELEASE:
+ return true;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * Checks if policy blocks or is lock-free.
+ * Please note that it works on a concrete policy only.
+ *
+ * @return ``true`` if the policy may block the thread.
+ */
+ public bool is_blocking () requires (this.is_concrete ()) {
+ switch (this) {
+ case TRY_FREE:
+ case TRY_RELEASE:
+ return false;
+ case FREE:
+ case RELEASE:
+ return true;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * Checks if policy guarantees freeing all elements.
+ * Please note that it works on a concrete policy only.
+ *
+ * @return ``true`` if the policy guarantees freeing all elements.
+ */
+ public bool is_safe () requires (this.is_concrete ()) {
+ switch (this) {
+ case TRY_FREE:
+ case TRY_RELEASE:
+ return false;
+ case FREE:
+ case RELEASE:
+ return true;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * Finds concrete policy which corresponds to given policy.
+ *
+ * @return Policy that corresponds to given policy at given time in given thread.
+ */
+ public Policy to_concrete () ensures (result.is_concrete ()) {
+ switch (this) {
+ case TRY_FREE:
+ case FREE:
+ case TRY_RELEASE:
+ case RELEASE:
+ return this;
+ case DEFAULT:
+ return (Policy) AtomicInt.get (ref _default_policy);
+ case THREAD_EXIT:
+ return (Policy) AtomicInt.get (ref _thread_exit_policy);
+ default:
+ assert_not_reached ();
+
+ }
+ }
+
+ /**
+ * Runs the policy.
+ * @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) {
+ switch (this.to_concrete ()) {
+ case TRY_FREE:
+ return try_free (to_free) ? (owned) to_free : null;
+ case FREE:
+ while (try_free (to_free)) {
+ Thread.yield ();
+ }
+ return null;
+ case TRY_RELEASE:
+ ReleasePolicy.ensure_start ();
+ if (_queue_mutex.trylock ()) {
+ _queue.offer ((owned) to_free);
+ _queue_mutex.unlock ();
+ return null;
+ } else {
+ return (owned) to_free;
+ }
+ case RELEASE:
+ ReleasePolicy.ensure_start ();
+ _queue_mutex.lock ();
+ _queue.offer ((owned) to_free);
+ _queue_mutex.unlock ();
+ return null;
+ default:
+ assert_not_reached ();
+ }
+ }
+ }
+
+ public delegate void DestroyNotify (void *ptr);
+
+ /**
+ * Release policy determines what happens with object freed by Policy.TRY_RELEASE
+ * and Policy.RELEASE.
+ */
+ public enum ReleasePolicy {
+ /**
+ * Libgee spawns helper thread to free those elements.
+ * This is default.
+ */
+ HELPER_THREAD,
+ /**
+ * Libgee uses GLib main loop.
+ * This is recommended for application using GLib main loop.
+ */
+ MAIN_LOOP;
+
+ 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 ();
+ }
+ });
+ } catch (ThreadError error) {
+ assert_not_reached ();
+ }
+ break;
+ case MAIN_LOOP:
+ Idle.add (() => {
+ attempt_free ();
+ return true;
+ }, Priority.LOW);
+ break;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * Ensures that helper methods are started.
+ */
+ internal static inline void ensure_start () {
+ int policy = AtomicInt.get (ref release_policy);
+ if ((policy & (1 << (sizeof(int) * 8 - 1))) != 0)
+ return;
+ if (_queue_mutex.trylock ()) {
+ policy = AtomicInt.get (ref release_policy);
+ 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)));
+ start ((ReleasePolicy) policy);
+ }
+ _queue_mutex.unlock ();
+ }
+ }
+
+ private static inline void attempt_free () {
+ if (_queue_mutex.trylock ()) {
+ 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;});
+ }
+ try_free (_global_to_free);
+ }
+ }
+
+ /**
+ * Create a new context. User does not need to create explicitly however it might be benefitial
+ * if he is about to issue bunch of commands he might consider it benefitial to fine-tune the
creation of contexts.
+ *
+ * {{{
+ * Context ctx = new Context ();
+ * lock_free_collection.operation1 ();
+ * // Normally on exit the thread exit operation would be executed but here the default operation of
+ * // child context is executed.
+ * lock_free_collection.operation2 ();
+ * }}}
+ *
+ * Please note that the Context in implicitly part of stack and:
+ *
+ * 1. It cannot be moved between threads.
+ * 2. If in given thread the child (created later) context is alive parent must be alive as well.
+ */
+ [Compact]
+ public class Context { // FIXME: Should be struct
+ public Context (Policy? policy = null) {
+ this._to_free = new ArrayList<FreeNode *> ();
+ this._parent = _current_context.get ();
+ _current_context.set (this, null);
+ if (policy == null) {
+ if (_parent == null) {
+ _policy = (Policy)AtomicInt.get (ref _thread_exit_policy);
+ } else {
+ _policy = (Policy)AtomicInt.get (ref _default_policy);
+ }
+ } else {
+ this._policy = policy.to_concrete ();
+ }
+#if DEBUG
+ stderr.printf ("Entering context %p (policy %s, parent %p)\n", this, _policy != null
? _policy.to_string () : null, _parent);
+#endif
+ }
+
+ ~Context () {
+#if DEBUG
+ stderr.printf ("Exiting context %p (policy %s, parent %p)\n", this, _policy != null ?
_policy.to_string () : null, _parent);
+#endif
+ 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 DEBUG
+ stderr.printf ("Setting current context to %p\n", _parent);
+#endif
+ _current_context.set (_parent, null);
+ if (clean_parent)
+ HazardPointer.try_free (_parent->_to_free);
+ }
+
+ /**
+ * Tries to free all freed pointer in current context.
+ */
+ public void try_free () {
+ HazardPointer.try_free (_to_free);
+ }
+
+ /**
+ * Ensure that whole context is freed. Plase note that it might block.
+ */
+ public void free_all () {
+ while (HazardPointer.try_free (_to_free))
+ Thread.yield ();
+ }
+
+ /**
+ * Tries to push the current context to releaser.
+ */
+ public void try_release () {
+ if (_queue_mutex.trylock ()) {
+ _queue.offer ((owned) _to_free);
+ _to_free = new ArrayList<FreeNode *> ();
+ _queue_mutex.unlock ();
+ }
+ }
+
+ /**
+ * Pushes the current context to releaser. Plase note that it might block.
+ */
+ public void release () {
+ _queue_mutex.lock ();
+ _queue.offer ((owned) _to_free);
+ _to_free = new ArrayList<FreeNode *> ();
+ _queue_mutex.unlock ();
+ }
+
+ /**
+ * Add pointer to freed array.
+ */
+ internal inline void release_ptr (void *ptr, owned DestroyNotify notify) {
+ FreeNode *node = new FreeNode ();
+ node->pointer = ptr;
+ node->destroy_notify = (owned)notify;
+ _to_free.add (node);
+ if (_to_free.size >= THRESHOLD)
+ HazardPointer.try_free (_to_free);
+ }
+
+ /**
+ * Gets current context.
+ */
+ internal inline static Context *get_current_context () {
+ 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;
+ internal static StaticPrivate _current_context;
+ internal static StaticPrivate _root_context;
+ private static uint THRESHOLD = 10;
+ }
+
+ /**
+ * Gets a new hazard pointer node.
+ *
+ * @return new hazard pointer node.
+ */
+ internal static inline unowned Node acquire () {
+ for (unowned Node? curr = get_head (); curr != null; curr = curr.get_next ())
+ if (curr.activate ())
+ return curr;
+ Node *node = new Node ();
+ Node *old_head = null;
+ do {
+ node->set_next (old_head = (Node *)AtomicPointer.get (&_head));
+ } while (!AtomicPointer.compare_and_exchange (&_head, old_head, node));
+ return node;
+ }
+
+ /**
+ * Tries to free from list.
+ *
+ * @return ``true`` if list is empty.
+ */
+ internal static bool try_free (ArrayList<FreeNode *> to_free) {
+ Collection<void *> used = new HashSet<void *>();
+ for (unowned Node? current = get_head (); current != null; current = current.get_next ()) {
+ used.add (current.get ());
+ }
+ for (int i = 0; i < to_free.size;) {
+ FreeNode *current = to_free[i];
+ if (used.contains (current->pointer)) {
+#if DEBUG
+ stderr.printf ("Skipping freeing %p\n", current->pointer);
+#endif
+ i++;
+ } else {
+#if DEBUG
+ stderr.printf ("Freeing %p\n", current->pointer);
+#endif
+ FreeNode *cur = to_free.remove_at (to_free.size - 1);
+ if (i != to_free.size) {
+ FreeNode *temp = to_free[i];
+ to_free[i] = cur;
+ cur = temp;
+ }
+ cur->destroy_notify (cur->pointer);
+ delete cur;
+ }
+ }
+ return to_free.size > 0;
+ }
+
+ /**
+ * Gets head of hazard pointers.
+ * @return Hazard pointer head.
+ */
+ internal static unowned Node? get_head () {
+ return (Node *)AtomicPointer.get(&_head);
+ }
+
+ internal unowned Node _node;
+
+ internal static Node *_head = null;
+
+ internal static int _default_policy = (int)Policy.TRY_FREE;
+ internal static int _thread_exit_policy = (int)Policy.RELEASE;
+
+ internal static int release_policy = 0;
+
+ internal static Queue<ArrayList<FreeNode *>> _queue;
+ internal static StaticMutex _queue_mutex;
+
+ 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;
+ public DestroyNotify destroy_notify;
+ }
+
+ /**
+ * List of used pointers.
+ */
+ [Compact]
+ internal class Node {
+ public Node () {
+ AtomicPointer.set (&_hazard, null);
+ AtomicInt.set (ref _active, 1);
+ }
+
+ inline ~Node () {
+ delete _next;
+ }
+
+ public void release () {
+ AtomicPointer.set (&_hazard, null);
+ AtomicInt.set (ref _active, 0);
+ }
+
+ public inline bool is_active () {
+ return AtomicInt.get (ref _active) != 0;
+ }
+
+ public inline bool activate () {
+ return AtomicInt.compare_and_exchange (ref _active, 0, 1);
+ }
+
+ public inline void set (void *ptr) {
+ AtomicPointer.set (&_hazard, ptr);
+ }
+
+ public inline void *get (bool safe = true) {
+ if (safe) {
+ return (void *)AtomicPointer.get (&_hazard);
+ } else {
+ return (void *)_hazard;
+ }
+ }
+
+ public inline unowned Node? get_next () {
+ return (Node *)AtomicPointer.get (&_next);
+ }
+
+ public inline void set_next (Node *next) {
+ AtomicPointer.set (&_next, next);
+ }
+
+ public Node *_next;
+ public int _active;
+ public void *_hazard;
+ }
+}
+
diff --git a/gee/iterable.vala b/gee/iterable.vala
index b0097ac..67a302c 100644
--- a/gee/iterable.vala
+++ b/gee/iterable.vala
@@ -23,17 +23,15 @@
using GLib;
/**
- * Implemented by classes that support a simple iteration over instances of the
- * collection.
+ * An object that can provide an {@link Iterator}.
*/
-public abstract class Vala.Iterable<G> {
- public abstract Type get_element_type ();
-
+[GenericAccessors]
+public interface Vala.Iterable<G> : Object, Traversable<G> {
/**
- * Returns a Iterator that can be used for simple iteration over a
+ * Returns a {@link Iterator} that can be used for simple iteration over a
* collection.
*
- * @return a Iterator that can be used for simple iteration over a
+ * @return a {@link Iterator} that can be used for simple iteration over a
* collection
*/
public abstract Iterator<G> iterator ();
diff --git a/gee/iterator.vala b/gee/iterator.vala
index 5190fb6..8064e96 100644
--- a/gee/iterator.vala
+++ b/gee/iterator.vala
@@ -1,6 +1,8 @@
/* iterator.vala
*
* Copyright (C) 2007-2008 Jürg Billeter
+ * Copyright (C) 2009 Didier Villevalois, Maciej Piechotka
+ * Copyright (C) 2010-2011 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,25 +20,99 @@
*
* Author:
* Jürg Billeter <j bitron ch>
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
*/
/**
- * Implemented by classes that support a simple iteration over instances of the
- * collection.
+ * An iterator over a collection.
+ *
+ * Gee's iterators are "on-track" iterators. They always point to an item
+ * except before the first call to {@link next}, or, when an
+ * 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 next}, they will be defined again.
*/
-public abstract class Vala.Iterator<G> {
+public interface Vala.Iterator<G> : Object, Traversable<G> {
/**
* Advances to the next element in the iteration.
*
- * @return true if the iterator has a next element
+ * @return ``true`` if the iterator has a next element
*/
public abstract bool next ();
/**
+ * Checks whether there is a next element in the iteration.
+ *
+ * @return ``true`` if the iterator has a next element
+ */
+ public abstract bool has_next ();
+
+ /**
* Returns the current element in the iteration.
*
* @return the current element in the iteration
*/
- public abstract G? get ();
+ public abstract G get ();
+
+ /**
+ * Removes the current element in the iteration. The cursor is set in an
+ * in-between state. Both {@link get} and {@link remove} will fail until
+ * the next move of the cursor (calling {@link next}).
+ */
+ public abstract void remove ();
+
+ /**
+ * Determines wheather the call to {@link get} is legal. It is false at the
+ * beginning and after {@link remove} call and true otherwise.
+ */
+ public abstract bool valid { get; }
+
+ /**
+ * Determines wheather the call to {@link remove} 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; }
+
+ /**
+ * Create iterator from unfolding function. The lazy value is
+ * force-evaluated before progressing to next element.
+ *
+ * @param f Unfolding function
+ * @param current If iterator is to be valid it contains the current value of it
+ */
+ public static Iterator<A> unfold<A> (owned UnfoldFunc<A> f, owned Lazy<G>? current = null) {
+ return new UnfoldIterator<A> ((owned) f, (owned) current);
+ }
+
+ /**
+ * Concatinate iterators.
+ *
+ * @param iters Iterators of iterators
+ * @return Iterator containg values of each iterator
+ */
+ public static Iterator<G> concat<G> (Iterator<Iterator<G>> iters) {
+ Iterator<G>? current = null;
+ if (iters.valid)
+ current = iters.get ();
+ return unfold<G> (() => {
+ while (true) {
+ if (current == null) {
+ if (iters.next ()) {
+ current = iters.get ();
+ } else {
+ return null;
+ }
+ } else if (current.next ()) {
+ return new Lazy<G>.from_value (current.get ());
+ } else {
+ current = null;
+ }
+ }
+ });
+ }
}
diff --git a/gee/lazy.vala b/gee/lazy.vala
new file mode 100644
index 0000000..ed1ac3c
--- /dev/null
+++ b/gee/lazy.vala
@@ -0,0 +1,60 @@
+/* lazy.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+namespace Vala {
+ public delegate G LazyFunc<G> ();
+}
+
+/**
+ * Represents a lazy value. I.e. value that is computed on demand.
+ */
+public class Vala.Lazy<G> {
+ public Lazy (owned LazyFunc<G> func) {
+ _func = (owned)func;
+ }
+
+ public Lazy.from_value (G item) {
+ _value = item;
+ }
+
+ public void eval () {
+ if (_func != null) {
+ _value = _func ();
+ _func = null;
+ }
+ }
+
+ public new G get () {
+ eval ();
+ return _value;
+ }
+
+ public new G value {
+ get {
+ eval ();
+ return _value;
+ }
+ }
+
+ private LazyFunc<G>? _func;
+ private G? _value;
+}
diff --git a/gee/linkedlist.vala b/gee/linkedlist.vala
new file mode 100644
index 0000000..16d82da
--- /dev/null
+++ b/gee/linkedlist.vala
@@ -0,0 +1,690 @@
+/* linkedlist.vala
+ *
+ * Copyright (C) 2004-2005 Novell, Inc
+ * Copyright (C) 2005 David Waite
+ * Copyright (C) 2007-2008 Jürg Billeter
+ * Copyright (C) 2009 Mark Lee, Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ * Mark Lee <marklee src gnome org>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Doubly-linked list implementation of the {@link List} interface.
+ *
+ * This implementation is pretty well designed for highly mutable data. When
+ * indexed access is privileged prefer using {@link ArrayList}.
+ *
+ * @see ArrayList
+ */
+public class Vala.LinkedList<G> : AbstractBidirList<G>, Queue<G>, Deque<G> {
+ private int _size = 0;
+ private int _stamp = 0;
+ private Node<G>? _head = null;
+ private weak Node<G>? _tail = null;
+
+ /**
+ * The elements' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<G> equal_func { private set; get; }
+
+ /**
+ * 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 LinkedList (owned EqualDataFunc<G>? equal_func = null) {
+ if (equal_func == null) {
+ equal_func = Functions.get_equal_func_for (typeof (G));
+ }
+ this.equal_func = equal_func;
+ }
+
+ ~LinkedList () {
+ this.clear ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool foreach(ForallFunc<G> f) {
+ for (weak Node<G>? node = _head; node != null; node = node.next) {
+ if (!f (node.data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override ListIterator<G> list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override BidirListIterator<G> bidir_list_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int size {
+ get { return this._size; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool contains (G item) {
+ return this.index_of (item) != -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool add (G item) {
+ Node<G> n = new Node<G> (item);
+ if (this._head == null && this._tail == null) {
+ this._tail = n;
+ this._head = (owned) n;
+ } else {
+ n.prev = this._tail;
+ this._tail.next = (owned) n;
+ this._tail = this._tail.next;
+ }
+
+ // Adding items to the list during iterations is allowed.
+ //++this._stamp;
+
+ this._size++;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool remove (G item) { // Should remove only the first occurence (a test should be
added)
+ for (weak Node<G> n = this._head; n != null; n = n.next) {
+ if (this.equal_func (item, n.data)) {
+ this._remove_node (n);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear () {
+ while (_head != null) {
+ _remove_node (_head);
+ }
+
+ ++this._stamp;
+ this._head = null;
+ this._tail = null;
+ this._size = 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G get (int index) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+ unowned Node<G>? n = this._get_node_at (index);
+ assert (n != null);
+ return n.data;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void set (int index, G item) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+ unowned Node<G>? n = this._get_node_at (index);
+ return_if_fail (n != null);
+ n.data = item;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int index_of (G item) {
+ int idx = 0;
+ for (weak Node<G>? node = _head; node != null; node = node.next, idx++) {
+ if (this.equal_func (item, node.data)) {
+ return idx;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void insert (int index, G item) {
+ assert (index >= 0);
+ assert (index <= this._size);
+
+ if (index == this._size) {
+ this.add (item);
+ } else {
+ Node<G> n = new Node<G> (item);
+ if (index == 0) {
+ n.next = (owned) this._head;
+ n.next.prev = n;
+ this._head = (owned)n;
+ } else {
+ weak Node prev = this._head;
+ for (int i = 0; i < index - 1; i++) {
+ prev = prev.next;
+ }
+ n.prev = prev;
+ n.next = (owned) prev.next;
+ n.next.prev = n;
+ prev.next = (owned) n;
+ }
+
+ // Adding items to the list during iterations is allowed.
+ //++this._stamp;
+
+ this._size++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G remove_at (int index) {
+ assert (index >= 0);
+ assert (index < this._size);
+
+ unowned Node<G>? n = this._get_node_at (index);
+ assert (n != null);
+ G element = n.data;
+ this._remove_node (n);
+ return element;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override List<G>? slice (int start, int stop) {
+ return_val_if_fail (start <= stop, null);
+ return_val_if_fail (start >= 0, null);
+ return_val_if_fail (stop <= this._size, null);
+
+ List<G> slice = new LinkedList<G> (this.equal_func);
+ weak Node<G> n = this._get_node_at (start);
+ for (int i = start; i < stop; i++) {
+ slice.add (n.data);
+ n = n.next;
+ }
+
+ return slice;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G first () {
+ assert (_size > 0);
+ return _head.data;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G last () {
+ assert (_size > 0);
+ return _tail.data;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int capacity {
+ get { return UNBOUNDED_CAPACITY; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int remaining_capacity {
+ get { return UNBOUNDED_CAPACITY; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool is_full {
+ get { return false; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer (G element) {
+ return offer_tail (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? peek () {
+ return peek_head ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? poll () {
+ return poll_head ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain (Collection<G> recipient, int amount = -1) {
+ return drain_head (recipient, amount);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer_head (G element) {
+ insert (0, element);
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? peek_head () {
+ if (this._size == 0) {
+ return null;
+ }
+ return get (0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? poll_head () {
+ if (this._size == 0) {
+ return null;
+ }
+ return remove_at (0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain_head (Collection<G> recipient, int amount = -1) {
+ if (amount == -1) {
+ amount = this._size;
+ }
+ for (int i = 0; i < amount; i++) {
+ if (this._size == 0) {
+ return i;
+ }
+ recipient.add (remove_at (0));
+ }
+ return amount;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer_tail (G element) {
+ return add (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? peek_tail () {
+ if (this._size == 0) {
+ return null;
+ }
+ return get (_size - 1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? poll_tail () {
+ if (this._size == 0) {
+ return null;
+ }
+ return remove_at (_size - 1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain_tail (Collection<G> recipient, int amount = -1) {
+ if (amount == -1) {
+ amount = this._size;
+ }
+ for (int i = 0; i < amount; i++) {
+ if (this._size == 0) {
+ return i;
+ }
+ recipient.add (remove_at (this._size - 1));
+ }
+ return amount;
+ }
+
+ [Compact]
+ private class Node<G> { // Maybe a compact class should be used?
+ public G data;
+ public weak Node<G>? prev = null;
+ public Node<G>? next = null;
+ public Node (owned G data) {
+ this.data = data;
+ }
+ }
+
+ 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._index = -1;
+ this._stamp = list._stamp;
+ }
+
+ public bool next () {
+ assert (this._stamp == this._list._stamp);
+
+ if (this.removed) {
+ if (this.position != null) {
+ this.removed = false;
+ 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++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public bool has_next () {
+ assert (this._stamp == this._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;
+ }
+ return false;
+ }
+
+ public bool first () {
+ assert (this._stamp == this._list._stamp);
+ if (this._list.size == 0) {
+ return false;
+ }
+ this.position = this._list._head;
+ this.started = true;
+ this._index = 0;
+ this.removed = false;
+ return this.position != null;
+ }
+
+ public new G get () {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ return this.position.data;
+ }
+
+ public void remove () {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ unowned Node<G>? new_position = this.position.next;
+ if (new_position == null) {
+ started = false;
+ }
+ _list._remove_node (this.position);
+ this.position = new_position;
+ this.removed = true;
+ this._stamp = this._list._stamp;
+ }
+
+ public bool previous () {
+ assert (this._stamp == this._list._stamp);
+
+ if (!this.started) {
+ this.position = null;
+ return false;
+ } else if (this.position != null && this.position.prev != null) {
+ this.position = this.position.prev;
+ this._index--;
+ return true;
+ }
+ return false;
+ }
+
+ public bool has_previous () {
+ assert (this._stamp == this._list._stamp);
+
+ if (!this.started) {
+ return false;
+ } else if (this.position != null) {
+ return this.position.prev != null;
+ }
+ return false;
+ }
+
+ public bool last () {
+ assert (this._stamp == this._list._stamp);
+
+ if (this._list.size == 0) {
+ return false;
+ }
+ this.position = this._list._tail;
+ this.started = true;
+ this._index = this._list._size - 1;
+ return this.position != null;
+ }
+
+ public new void set (G item) {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ this.position.data = item;
+ }
+
+ public void insert (G item) {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ Node<G> n = new Node<G> (item);
+ if (this.position.prev != null) {
+ 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;
+ } else {
+ Node<G> position = (owned) this._list._head;
+ position.prev = n;
+ n.next = (owned) position;
+ this._list._head = (owned) n;
+ }
+ this._list._size++;
+ this._index++;
+ _stamp = _list._stamp;
+ }
+
+ public void add (G item) {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ Node<G> n = new Node<G> (item);
+ if (this.position.next != null) {
+ this.position.next.prev = n;
+ n.next = (owned) this.position.next;
+ } else {
+ this._list._tail = n;
+ }
+ this.position.next = (owned) n;
+ this.position.next.prev = this.position;
+ this.position = this.position.next;
+ this._list._size++;
+ this._index++;
+ _stamp = _list._stamp;
+ }
+
+ public int index () {
+ assert (this._stamp == this._list._stamp);
+ assert (this.position != null);
+
+ return this._index;
+ }
+
+ public bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool valid {
+ get {
+ return !this.removed && this.position != null;
+ }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ assert (_stamp == _list._stamp);
+ if (!started) {
+ position = _list._head;
+ if (position != null)
+ started = true;
+ }
+ removed = false;
+ while (position != null) {
+ if (!f (position.data)) {
+ return false;
+ }
+ position = position.next;
+ }
+ position = _list._tail;
+ return true;
+ }
+ }
+
+ private unowned Node<G>? _get_node_at (int index) {
+ unowned Node<G>? n = null;;
+ if (index == 0) {
+ n = this._head;
+ } else if (index == this._size - 1) {
+ n = this._tail;
+ } else if (index <= this._size / 2) {
+ n = this._head;
+ for (int i = 0; index != i; i++) {
+ n = n.next;
+ }
+ } else {
+ n = this._tail;
+ for (int i = this._size - 1; index != i; i--) {
+ n = n.prev;
+ }
+ }
+ return n;
+ }
+
+ private void _remove_node (Node<G> _n) {
+ Node<G> n;
+ weak Node<G> next;
+ if (_n == this._head) {
+ n = (owned) this._head;
+ next = this._head = (owned) n.next;
+ } else {
+ n = (owned) _n.prev.next;
+ next = n.prev.next = (owned) n.next;
+ }
+ if (n == this._tail) {
+ this._tail = n.prev;
+ } else {
+ next.prev = n.prev;
+ }
+ n.prev = null;
+ n.next = null;
+ n.data = null;
+ ++this._stamp;
+ this._size--;
+ }
+}
+
diff --git a/gee/list.vala b/gee/list.vala
index d730283..b99d598 100644
--- a/gee/list.vala
+++ b/gee/list.vala
@@ -21,9 +21,17 @@
*/
/**
- * Represents a collection of items in a well-defined order.
+ * An ordered collection.
*/
-public abstract class Vala.List<G> : Collection<G> {
+[GenericAccessors]
+public interface Vala.List<G> : Collection<G> {
+ /**
+ * Returns a ListIterator that can be used for iteration over this list.
+ *
+ * @return a ListIterator that can be used for iteration over this list
+ */
+ public abstract new ListIterator<G> list_iterator ();
+
/**
* Returns the item at the specified index in this list.
*
@@ -31,7 +39,7 @@ public abstract class Vala.List<G> : Collection<G> {
*
* @return the item at the specified index in the list
*/
- public abstract G? get (int index);
+ public abstract G get (int index);
/**
* Sets the item at the specified index in this list.
@@ -41,10 +49,10 @@ public abstract class Vala.List<G> : Collection<G> {
public abstract void set (int index, G item);
/**
- * Returns the index of the first occurrence of the specified item in
+ * Returns the index of the first occurence of the specified item in
* this list.
*
- * @return the index of the first occurrence of the specified item, or
+ * @return the index of the first occurence of the specified item, or
* -1 if the item could not be found
*/
public abstract int index_of (G item);
@@ -61,7 +69,77 @@ public abstract class Vala.List<G> : Collection<G> {
* Removes the item at the specified index of this list.
*
* @param index zero-based index of the item to be removed
+ *
+ * @return the removed element
+ */
+ public abstract G remove_at (int index);
+
+ /**
+ * Returns a slice of this list.
+ *
+ * @param start zero-based index of the begin of the slice
+ * @param stop zero-based index after the end of the slice
+ *
+ * @return A list containing a slice of this list
+ */
+ public abstract List<G>? slice (int start, int stop);
+
+ /**
+ * Returns the first item of the list. Fails if the list is empty.
+ *
+ * @return first item in the list
+ */
+ public virtual G first () {
+ return get (0);
+ }
+
+ /**
+ * Returns the last item of the list. Fails if the list is empty.
+ *
+ * @return last item in the list
+ */
+ public virtual G last () {
+ return get (size - 1);
+ }
+
+ /**
+ * Inserts items into this list for the input collection at the
+ * specified position.
+ *
+ * @param index zero-based index of the items to be inserted
+ * @param collection collection of items to be inserted
+ */
+ public virtual void insert_all (int index, Collection<G> collection) {
+ foreach (G item in collection) {
+ insert(index, item);
+ index++;
+ }
+ }
+
+ /**
+ * Sorts items by comparing with the specified compare function.
+ *
+ * @param compare_func compare function to use to compare items
+ */
+ public virtual void sort (owned CompareDataFunc<G>? compare_func = null) {
+ if (compare_func == null) {
+ compare_func = Functions.get_compare_func_for (typeof (G));
+ }
+ TimSort.sort<G> (this, compare_func);
+ }
+
+ /**
+ * The read-only view of this list.
+ */
+ public abstract new List<G> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty list.
+ *
+ * @return an immutable empty list
*/
- public abstract void remove_at (int index);
+ public static List<G> empty<G> () {
+ return new LinkedList<G> ().read_only_view;
+ }
}
diff --git a/gee/listiterator.vala b/gee/listiterator.vala
new file mode 100644
index 0000000..a57a7df
--- /dev/null
+++ b/gee/listiterator.vala
@@ -0,0 +1,44 @@
+/* listiterator.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * A list iterator. This supports bi-directionnal and index-based iteration.
+ */
+public interface Vala.ListIterator<G> : Vala.Iterator<G> {
+ /**
+ * Sets the current item in the iteration to the specified new item.
+ */
+ public abstract void set (G item);
+
+ /**
+ * Adds the specified item after the current item in the iteration. The
+ * cursor is moved to point to the new added item.
+ */
+ public abstract void add (G item);
+
+ /**
+ * Returns the current index in the iteration.
+ *
+ * @return the current index
+ */
+ public abstract int index ();
+}
diff --git a/gee/map.vala b/gee/map.vala
index 2c96a3d..e48cb8a 100644
--- a/gee/map.vala
+++ b/gee/map.vala
@@ -21,43 +21,100 @@
*/
/**
- * A map is a generic collection of key/value pairs.
+ * An object that maps keys to values.
*/
-public abstract class Vala.Map<K,V> {
+[GenericAccessors]
+public interface Vala.Map<K,V> : Object, Iterable<Map.Entry<K,V>> {
/**
* The number of items in this map.
*/
public abstract int size { get; }
/**
- * Returns the keys of this map as a read-only set.
- *
- * @return the keys of the map
+ * 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.
+ */
+ public abstract bool read_only { get; }
+
+ /**
+ * The read-only view of the keys of this map.
+ */
+ public abstract Set<K> keys { owned get; }
+
+ /**
+ * The read-only view of the values of this map.
*/
- public abstract Set<K> get_keys ();
+ public abstract Collection<V> values { owned get; }
+
+ /**
+ * The read-only view of the entries of this map.
+ */
+ public abstract Set<Entry<K,V>> entries { owned get; }
+
+ /**
+ * An entry of a map.
+ */
+ public abstract class Entry<K,V> : Object {
+ /**
+ * The key of this entry.
+ */
+ public abstract K key { get; }
+
+ /**
+ * The value of this entry.
+ */
+ public abstract V value { get; set; }
+
+ /**
+ * ``true'' if the setting value is permitted.
+ */
+ public abstract bool read_only { get; }
+ }
/**
- * Returns the values of this map as a read-only collection.
+ * Determines whether this map has the specified key.
*
- * @return the values of the map
+ * @param key the key to locate in the map
+ *
+ * @return ``true`` if key is found, ``false`` otherwise
*/
- public abstract Collection<V> get_values ();
+ public abstract bool has_key (K key);
/**
* Determines whether this map contains the specified key.
*
* @param key the key to locate in the map
*
- * @return true if key is found, false otherwise
+ * @return ``true`` if key is found, ``false`` otherwise
+ *
+ * @deprecated Use {@link has_key} method instead.
+ */
+ [Version (deprecated = true)]
+ public bool contains (K key) {
+ return has_key(key);
+ }
+
+ /**
+ * Determines whether this map has the specified key/value entry.
+ *
+ * @param key the key to locate in the map
+ * @param value the corresponding value
+ *
+ * @return ``true`` if key is found, ``false`` otherwise
*/
- public abstract bool contains (K key);
+ public abstract bool has (K key, V value);
/**
* Returns the value of the specified key in this map.
*
* @param key the key whose value is to be retrieved
*
- * @return the value associated with the key, or null if the key
+ * @return the value associated with the key, or ``null`` if the key
* couldn't be found
*/
public abstract V? get (K key);
@@ -73,11 +130,27 @@ public abstract class Vala.Map<K,V> {
/**
* Removes the specified key from this map.
*
- * @param key the key to remove from the map
+ * @param key the key to remove from the map
+ * @param value the receiver variable for the removed value
*
- * @return true if the map has been changed, false otherwise
+ * @return ``true`` if the map has been changed, ``false`` otherwise
*/
- public abstract bool remove (K key);
+ public abstract bool unset (K key, out V? value = null);
+
+ /**
+ * Removes the specified key from this map.
+ *
+ * @param key the key to remove from the map
+ * @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)]
+ public bool remove (K key, out V? value = null) {
+ return unset (key, out value);
+ }
/**
* Removes all items from this collection. Must not be called on
@@ -86,12 +159,98 @@ public abstract class Vala.Map<K,V> {
public abstract void clear ();
/**
- * Returns a Iterator that can be used for simple iteration over a
- * map.
+ * Returns an iterator for this map.
*
- * @return a Iterator that can be used for simple iteration over a
- * map
+ * @return a map iterator
*/
public abstract MapIterator<K,V> map_iterator ();
+
+ /**
+ * Inserts all items that are contained in the input map to this map.
+ *
+ * @param map the map which items are inserted to this map
+ */
+ public virtual void set_all (Map<K,V> map) {
+ foreach (Map.Entry<K,V> entry in map.entries) {
+ set (entry.key, entry.value);
+ }
+ }
+
+ /**
+ * Removes all items from this map that are common to the input map
+ * and this map.
+ *
+ * @param map the map which common items are deleted from this map
+ */
+ public virtual bool unset_all (Map<K,V> map) {
+ bool changed = false;
+ foreach (K key in map.keys) {
+ changed = changed | unset (key);
+ }
+ return changed;
+ }
+
+ /**
+ * Removes all items from this map that are common to the input map
+ * 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)]
+ public bool remove_all (Map<K,V> map) {
+ return unset_all (map);
+ }
+
+ /**
+ * Returns ``true`` it this map contains all items as the input map.
+ *
+ * @param map the map which items will be compared with this map
+ */
+ public virtual bool has_all (Map<K,V> map) {
+ foreach (Map.Entry<K,V> entry in map.entries) {
+ if (!has (entry.key, entry.value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 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)]
+ public bool contains_all (Map<K,V> map) {
+ return has_all (map);
+ }
+
+ /**
+ * The read-only view this map.
+ */
+ public abstract Map<K,V> read_only_view { owned get; }
+
+ /**
+ * The type of the keys in this map.
+ */
+ public Type key_type { get { return typeof(K); } }
+
+ /**
+ * The type of the values in this map.
+ */
+ public Type value_type { get { return typeof(V); } }
+
+ /**
+ * Returns an immutable empty map.
+ *
+ * @return an immutable empty map
+ */
+ public static Map<K,V> empty<K,V> () {
+ return new HashMap<K,V> ().read_only_view;
+ }
}
diff --git a/gee/mapiterator.vala b/gee/mapiterator.vala
index 78243c2..2ad5890 100644
--- a/gee/mapiterator.vala
+++ b/gee/mapiterator.vala
@@ -1,6 +1,7 @@
/* mapiterator.vala
*
- * Copyright (C) 2011 Florian Brosch
+ * Copyright (C) 2009 Didier Villevalois
+ * Copyright (C) 2011 Maciej Piechotka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,23 +18,43 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author:
- * Florian Brosch <flo brosch gmail com>
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
*/
-
+namespace Vala {
+ public delegate A FoldMapFunc<A, K, V> (K k, V v, owned A a);
+ public delegate bool ForallMapFunc<K, V> (K k, V v);
+}
/**
* An iterator over a map.
+ *
+ * Gee's iterators are "on-track" iterators. They always point to an item
+ * except before the first call to {@link next}, or, when an
+ * item has been removed, until the next call to {@link next}.
+ *
+ * Please note that when the iterator is out of track, neither {@link get_key},
+ * {@link get_value}, {@link set_value} nor {@link unset} are defined and all
+ * will fail. After the next call to {@link next}, they will
+ * be defined again.
*/
-public abstract class Vala.MapIterator<K,V> {
+[GenericAccessors]
+public interface Vala.MapIterator<K,V> : Object {
/**
- * Advances to the next element in the iteration.
+ * Advances to the next entry in the iteration.
*
- * @return true if the iterator has a next element
+ * @return ``true`` if the iterator has a next entry
*/
public abstract bool next ();
/**
+ * Checks whether there is a next entry in the iteration.
+ *
+ * @return ``true`` if the iterator has a next entry
+ */
+ public abstract bool has_next ();
+
+ /**
* Returns the current key in the iteration.
*
* @return the current key in the iteration
@@ -41,12 +62,84 @@ public abstract class Vala.MapIterator<K,V> {
public abstract K get_key ();
/**
- * Returns the current value in the iteration.
+ * Returns the value associated with the current key in the iteration.
*
- * @return the current value in the iteration
+ * @return the value for the current key
*/
public abstract V get_value ();
-}
+ /**
+ * Sets the value associated with the current key in the iteration.
+ *
+ * @param value the new value for the current key
+ */
+ public abstract void set_value (V value);
+
+ /**
+ * Unsets the current entry in the iteration. The cursor is set in an
+ * in-between state. {@link get_key}, {@link get_value}, {@link set_value}
+ * and {@link unset} will fail until the next move of the cursor (calling
+ * {@link next}).
+ */
+ public abstract void unset ();
+ /**
+ * 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.
+ *
+ * It takes a function, seed and first element, returns the new seed and
+ * progress to next element when the operation repeats.
+ *
+ * Operation moves the iterator to last element in iteration. If iterator
+ * points at some element it will be included in iteration.
+ */
+ public virtual A fold<A> (FoldMapFunc<A, K, V> f, owned A seed)
+ {
+ if (valid)
+ seed = f (get_key (), get_value (), (owned) seed);
+ while (next ())
+ seed = f (get_key (), get_value (), (owned) seed);
+ return (owned) seed;
+ }
+
+ /**
+ * 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.
+ */
+ public new virtual bool foreach (ForallMapFunc<K, V> f) {
+ if (valid) {
+ if (!f (get_key (), get_value ())) {
+ return false;
+ }
+ }
+ while (next ()) {
+ if (!f (get_key (), get_value ())) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/gee/multimap.vala b/gee/multimap.vala
new file mode 100644
index 0000000..6c1748b
--- /dev/null
+++ b/gee/multimap.vala
@@ -0,0 +1,127 @@
+/* multimap.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ */
+
+/**
+ * A map with multiple values per key.
+ */
+[GenericAccessors]
+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.
+ */
+ public abstract bool read_only { get; }
+
+ /**
+ * Returns the keys of this multimap as a read-only set.
+ *
+ * @return the keys of the map
+ */
+ public abstract Set<K> get_keys ();
+
+ /**
+ * Returns the keys of this multimap as a read-only set.
+ *
+ * @return the keys of the map
+ */
+ public abstract MultiSet<K> get_all_keys ();
+
+ /**
+ * Returns the values of this map as a read-only collection.
+ *
+ * @return the values of the map
+ */
+ public abstract Collection<V> get_values ();
+
+ /**
+ * Determines whether this map contains the specified key.
+ *
+ * @param key the key to locate in the map
+ *
+ * @return ``true`` if key is found, ``false`` otherwise
+ */
+ public abstract bool contains (K key);
+
+ /**
+ * Returns the values for the specified key in this map.
+ *
+ * @param key the key whose values are to be retrieved
+ *
+ * @return a Collection of values associated with the given key
+ */
+ public abstract Collection<V> get (K key);
+
+ /**
+ * Inserts a key/value pair into this map.
+ *
+ * @param key the key to insert
+ * @param value the value to associate with the key
+ */
+ public abstract void set (K key, V value);
+
+ /**
+ * Removes the specified key/value pair from this multimap.
+ *
+ * @param key the key to remove from the map
+ * @param value the value to remove from the map
+ *
+ * @return ``true`` if the map has been changed, ``false`` otherwise
+ */
+ public abstract bool remove (K key, V value);
+
+ /**
+ * Removes the specified key and all the associated values from this
+ * multimap.
+ *
+ * @param key the key to remove from the map
+ *
+ * @return ``true`` if the map has been changed, ``false`` otherwise
+ */
+ public abstract bool remove_all (K key);
+
+ /**
+ * Removes all items from this collection.
+ */
+ public abstract void clear ();
+
+ /**
+ * Returns an iterator for this map.
+ *
+ * @return a map iterator
+ */
+ public abstract MapIterator<K, V> map_iterator ();
+
+ /**
+ * The type of the keys in this multimap.
+ */
+ public Type key_type { get { return typeof (K); } }
+
+ /**
+ * The type of the values in this multimap.
+ */
+ public Type value_type { get { return typeof (V); } }
+}
diff --git a/gee/multiset.vala b/gee/multiset.vala
new file mode 100644
index 0000000..7b9f774
--- /dev/null
+++ b/gee/multiset.vala
@@ -0,0 +1,36 @@
+/* multiset.vala
+ *
+ * Copyright (C) 2009 Ali Sabil
+ *
+ * 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:
+ * Ali Sabil <ali sabil gmail com>
+ */
+
+/**
+ * A collection with duplicate elements.
+ */
+[GenericAccessors]
+public interface Vala.MultiSet<G> : Collection<G> {
+ /**
+ * Returns the number of occurences of an item in this multiset.
+ *
+ * @param item the item to count occurences of
+ *
+ * @return the number of occurences of the item in this multiset.
+ */
+ public abstract int count (G item);
+}
diff --git a/gee/priorityqueue.vala b/gee/priorityqueue.vala
new file mode 100644
index 0000000..04d0a00
--- /dev/null
+++ b/gee/priorityqueue.vala
@@ -0,0 +1,1207 @@
+/* priorityqueue.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ * Copyright (C) 2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Relaxed fibonacci heap priority queue implementation of the {@link Queue}.
+ *
+ * The elements of the priority queue are ordered according to their natural
+ * ordering, or by a compare_func provided at queue construction time. A
+ * priority queue does not permit null elements and does not have bounded
+ * capacity.
+ *
+ * This implementation provides O(1) time for offer and peek methods, and
+ * O(log n) for poll method. It is based on the algorithms described by
+ * Boyapati Chandra Sekhar in:
+ *
+ * "Worst Case Efficient Data Structures
+ * for Priority Queues and Deques with Heap Order"
+ * Boyapati Chandra Sekhar (under the guidance of Prof. C. Pandu Rangan)
+ * Department of Computer Science and Engineering
+ * Indian Institute of Technology, Madras
+ * May 1996
+ */
+public class Vala.PriorityQueue<G> : Vala.AbstractQueue<G> {
+
+ /**
+ * The elements' comparator function.
+ */
+ [CCode (notify = false)]
+ public CompareDataFunc<G> compare_func { private set; get; }
+
+ private int _size = 0;
+ private int _stamp = 0;
+ private Type1Node<G>? _r = null;
+ private Type2Node<G>? _r_prime = null;
+ private Type2Node<G>? _lm_head = null;
+ private Type2Node<G>? _lm_tail = null;
+ private Type1Node<G>? _p = null;
+ private Type1Node<G>?[] _a = new Type1Node<G>?[0];
+ private NodePair<G>? _lp_head = null;
+ private NodePair<G>? _lp_tail = null;
+ private bool[] _b = new bool[0];
+ private Type1Node<G>? _ll_head = null;
+ private Type1Node<G>? _ll_tail = null;
+ private unowned Node<G> _iter_head = null;
+ private unowned Node<G> _iter_tail = null;
+
+ /**
+ * Constructs a new, empty priority queue.
+ *
+ * If not provided, the function parameter is requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param compare_func an optional element comparator function
+ */
+ public PriorityQueue (owned CompareDataFunc<G>? compare_func = null) {
+ if (compare_func == null) {
+ compare_func = Functions.get_compare_func_for (typeof (G));
+ }
+ this.compare_func = compare_func;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int capacity {
+ get { return UNBOUNDED_CAPACITY; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int remaining_capacity {
+ get { return UNBOUNDED_CAPACITY; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool is_full {
+ get { return false; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool offer (G element) {
+ #if DEBUG
+ _dump ("Start offer: %s".printf ((string)element));
+ #endif
+ if (_r == null) {
+ _r = new Type1Node<G> (element, ref _iter_head, ref _iter_tail);
+ _p = _r;
+ } else if (_r_prime == null) {
+ _r_prime = new Type2Node<G> (element, ref _iter_head, ref _iter_tail);
+ _r_prime.parent = _r;
+ _r.type2_child = _r_prime;
+ if (_compare (_r_prime, _r) < 0)
+ _swap_data (_r_prime, _r);
+ } else {
+ // Form a tree with a single node N of type I consisting of element e
+ Type1Node<G> node = new Type1Node<G> (element, ref _iter_head, ref _iter_tail);
+
+ //Add(Q, N)
+ _add (node);
+ }
+
+ _stamp++;
+ _size++;
+ #if DEBUG
+ _dump ("End offer: %s".printf ((string)element));
+ #endif
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? peek () {
+ if (_r == null) {
+ return null;
+ }
+ return _r.data;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? poll () {
+ #if DEBUG
+ _dump ("Start poll:");
+ #endif
+
+ // 1a. M inElement <- R.element
+ if (_r == null) {
+ return null;
+ }
+ G min = _r.data;
+ _r.pending_drop = false;
+ _stamp++;
+ _size--;
+
+ // 1b. R.element = R'.element
+ if (_r_prime == null) {
+ if (_r.iter_next != null) {
+ _r.iter_next.iter_prev = _r.iter_prev;
+ }
+ if (_r.iter_prev != null) {
+ _r.iter_prev.iter_next = _r.iter_next;
+ }
+ if (_iter_head == _r) {
+ _iter_head = _r.iter_next;
+ }
+ if (_iter_tail == _r) {
+ _iter_tail = _r.iter_prev;
+ }
+ _r = null;
+ _p = null;
+ return min;
+ }
+ _move_data (_r, _r_prime);
+
+
+ // 1c. R'' <- The child of R' containing the minimum element among the children of R'
+ if (_r_prime.type1_children_head == null) {
+ _remove_type2_node (_r_prime, true);
+ _r_prime = null;
+ return min;
+ }
+ Type1Node<G>? r_second = null;
+ Type1Node<G> node = _r_prime.type1_children_head;
+ while (node != null) {
+ if (r_second == null || _compare (node, r_second) < 0) {
+ r_second = node;
+ }
+ node = node.brothers_next;
+ }
+
+ // 1d. R'.element <- R''.element
+ _move_data (_r_prime, r_second);
+
+ // 2a. Delete the subtree rooted at R'' from Q
+ _remove_type1_node (r_second, true);
+
+ // 2b. For all children N of type I of R'' do make N a child of R' of Q
+ node = r_second.type1_children_head;
+ while (node != null) {
+ Type1Node<G> next = node.brothers_next;
+ _remove_type1_node (node, false);
+ _add_in_r_prime (node);
+ node = next;
+ }
+
+ // For now we can't have type2 node other than R' (left for reference)
+ #if false
+ // 3a. If R'' has no child of type II then goto Step 4.
+ if (r_second.type2_child != null) {
+ // 3b. Let M' be the child of type II of R''. Insert(Q, M'.element)
+ Type2Node<G> m_prime = r_second.type2_child;
+ _remove_type2_node (m_prime);
+ offer (m_prime.data);
+
+ // 3c. For all children N of M do make N a child of R' of Q
+ node = m_prime.type1_children_head;
+ while (node != null) {
+ Type1Node<G> next = node.brothers_next;
+ _remove_type1_node (node);
+ _add_in_r_prime (node);
+ node = next;
+ }
+ }
+ #endif
+
+ // 4. Adjust(Q, P, P)
+ _adjust (_p, _p);
+
+ // For now we can't have type2 node other than R' (left for reference)
+ #if false
+ // 5a. if LM is empty then goto Step 6
+ if (_lm_head != null) {
+ // 5b. M <- Head(LM); LM <- Tail(LM)
+ Type2Node<G> m = _lm_head;
+
+ // 5c. Delete M from Q
+ _remove_type2_node (m);
+
+ // 5d. I nsert(Q, M.element)
+ offer (m.data);
+
+ // 5e. For all children N of M do make M a child of R' of Q
+ node = m.type1_children_head;
+ while (node != null) {
+ Type1Node<G> next = node.brothers_next;
+ _remove_type1_node (node);
+ _add_in_r_prime (node);
+ node = next;
+ }
+ }
+ #endif
+
+ // 6. While among the children of R' there exist any two different nodes Ri and Rj
+ // such that Ri.degree = Rj.degree do Link(Q, Ri, Rj)
+ while (_check_linkable ()) {}
+
+ // 7. Return MinElement
+ return min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int drain (Collection<G> recipient, int amount = -1) {
+ if (amount == -1) {
+ amount = this._size;
+ }
+ for (int i = 0; i < amount; i++) {
+ if (this._size == 0) {
+ return i;
+ }
+ recipient.add (poll ());
+ }
+ return amount;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override int size {
+ get { return _size; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool contains (G item) {
+ foreach (G an_item in this) {
+ if (compare_func (item, an_item) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool add (G item) {
+ return offer (item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool remove (G item) {
+ #if DEBUG
+ _dump ("Start remove: %s".printf ((string) item));
+ #endif
+
+ Iterator<G> iterator = new Iterator<G> (this);
+ while (iterator.next ()) {
+ G an_item = iterator.get ();
+ if (compare_func (item, an_item) == 0) {
+ iterator.remove ();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear () {
+ _size = 0;
+ _r = null;
+ _r_prime = null;
+ _lm_head = null;
+ _lm_tail = null;
+ _p = null;
+ _a = new Type1Node<G>?[0];
+ _lp_head = null;
+ _lp_tail = null;
+ _b = new bool[0];
+ _ll_head = null;
+ _ll_tail = null;
+ _iter_head = null;
+ _iter_tail = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ private inline int _compare (Node<G> node1, Node<G> node2) {
+ // Assume there can't be two nodes pending drop
+ if (node1.pending_drop) {
+ return -1;
+ } else if (node2.pending_drop) {
+ return 1;
+ } else {
+ return compare_func (node1.data, node2.data);
+ }
+ }
+
+ private inline void _swap_data (Node<G> node1, Node<G> node2) {
+ #if DEBUG
+ _dump ("Before swap: %p(%s) %p(%s)".printf(node1, (string)node1.data, node2,
(string)node2.data));
+ #endif
+ G temp_data = (owned) node1.data;
+ bool temp_pending_drop = node1.pending_drop;
+ node1.data = (owned) node2.data;
+ node1.pending_drop = node2.pending_drop;
+ node2.data = (owned) temp_data;
+ node2.pending_drop = temp_pending_drop;
+
+ if (node1.iter_next == node2) { // Before swap: N1 N2
+ unowned Node<G> temp_iter_prev = node1.iter_prev;
+ unowned Node<G> temp_iter_next = node2.iter_next;
+
+ node1.iter_prev = node2;
+ node1.iter_next = temp_iter_next;
+ node2.iter_prev = temp_iter_prev;
+ node2.iter_next = node1;
+ } else if (node1.iter_prev == node2) { // Before swap: N2 N1
+ unowned Node<G> temp_iter_prev = node2.iter_prev;
+ unowned Node<G> temp_iter_next = node1.iter_next;
+
+ node1.iter_prev = temp_iter_prev;
+ node1.iter_next = node2;
+ node2.iter_prev = node1;
+ node2.iter_next = temp_iter_next;
+ } else {
+ unowned Node<G> temp_iter_prev = node1.iter_prev;
+ unowned Node<G> temp_iter_next = node1.iter_next;
+
+ node1.iter_prev = node2.iter_prev;
+ node1.iter_next = node2.iter_next;
+ node2.iter_prev = temp_iter_prev;
+ node2.iter_next = temp_iter_next;
+ }
+
+ if (node2 == _iter_head) {
+ _iter_head = node1;
+ } else if (node1 == _iter_head) {
+ _iter_head = node2;
+ }
+ if (node2 == _iter_tail) {
+ _iter_tail = node1;
+ } else if (node1 == _iter_tail) {
+ _iter_tail = node2;
+ }
+
+ if (node1.iter_prev != null) {
+ node1.iter_prev.iter_next = node1;
+ }
+ if (node1.iter_next != null) {
+ node1.iter_next.iter_prev = node1;
+ }
+ if (node2.iter_prev != null) {
+ node2.iter_prev.iter_next = node2;
+ }
+ if (node2.iter_next != null) {
+ node2.iter_next.iter_prev = node2;
+ }
+
+ #if DEBUG
+ _dump ("After swap: %p(%s) %p(%s)".printf(node1, (string)node1.data, node2,
(string)node2.data));
+ #endif
+ }
+
+ private inline void _move_data (Node<G> target, Node<G> source) {
+ #if DEBUG
+ _dump ("Before move: %p(%s) <- %p(%s)".printf(target, (string)target.data, source,
(string)source.data));
+ #endif
+
+ if (target.iter_next != null) {
+ target.iter_next.iter_prev = target.iter_prev;
+ } else if (_iter_tail == target) {
+ _iter_tail = target.iter_prev;
+ }
+ if (target.iter_prev != null) {
+ target.iter_prev.iter_next = target.iter_next;
+ } else if (_iter_head == target) {
+ _iter_head = target.iter_next;
+ }
+
+ target.data = source.data;
+ target.pending_drop = source.pending_drop;
+ target.iter_next = source.iter_next;
+ target.iter_prev = source.iter_prev;
+ source.iter_next = null;
+ source.iter_prev = null;
+
+ if (target.iter_next != null) {
+ target.iter_next.iter_prev = target;
+ } else if (_iter_tail == source) {
+ _iter_tail = target;
+ }
+ if (target.iter_prev != null) {
+ target.iter_prev.iter_next = target;
+ } else if (_iter_head == source) {
+ _iter_head = target;
+ }
+ #if DEBUG
+ _dump ("After move:");
+ #endif
+ }
+
+ private void _link (owned Type1Node<G> ri, owned Type1Node<G> rj) {
+ assert (ri.degree () == rj.degree ());
+
+ // Delete the subtrees rooted at Ri and Rj from Q
+ _remove_type1_node (ri, false);
+ _remove_type1_node (rj, false);
+
+ // If Ri.element > Rj.element then Swap(Ri,Rj)
+ if (_compare (ri, rj) > 0) {
+ Type1Node<G> temp = ri;
+ ri = rj;
+ rj = temp;
+ }
+
+ // Make Rj the last child of Ri
+ _add_to (rj, ri);
+
+ // Make Ri (whose degree now = d+1) a child of R' of Q
+ _add_in_r_prime (ri);
+ }
+
+ private void _add (Type1Node<G> n) {
+ // Make N a child of R' of Q
+ _add_in_r_prime (n);
+
+ // If N.element < R'.element then Swap(N.element, R'.element)
+ if (_compare (n, _r_prime) < 0) {
+ _swap_data (n, _r_prime);
+ }
+
+ // If R'.element < R.element then Swap(R'.element, R.element)
+ if (_compare (_r_prime, _r) < 0) {
+ _swap_data (_r_prime, _r);
+ }
+
+ // If among the children of R' there exist any two different nodes Ri and Rj
+ // such that Ri.degree = Rj.degree then Link(Q, Ri, Rj)
+ _check_linkable ();
+
+ #if DEBUG
+ _dump ("End _add: %p(%s)".printf (n, (string) n.data));
+ #endif
+ }
+
+ private bool _check_linkable () {
+ #if DEBUG
+ _dump ("Start _check_linkable:");
+ #endif
+
+ if (_lp_head != null) {
+ NodePair<G> pair = _lp_head;
+ _link (pair.node1, pair.node2);
+ return true;
+ }
+ return false;
+ }
+
+ private Node<G> _re_insert (owned Type1Node<G> n) {
+ assert (n != _r);
+
+ #if DEBUG
+ _dump ("Start _re_insert: %p(%s)".printf (n, (string) n.data));
+ #endif
+
+ //Parent <- N.parent
+ Node<G> parent = n.parent;
+
+ // Delete the subtree rooted at N from Q
+ _remove_type1_node (n, false);
+
+ // Add(Q, N)
+ _add (n);
+
+ // Return Parent
+ return parent;
+ }
+
+ private void _adjust (Type1Node<G> p1, Type1Node<G> p2) {
+ // If M.lost <= 1 for all nodes M in Q then return
+ if (_ll_head == null) {
+ return;
+ }
+
+ #if DEBUG
+ _dump ("Start _adjust: %p(%s), %p(%s)".printf (p1, (string) p1.data, p2, (string)
p2.data));
+ #endif
+
+ // If P1.lost > P2.lost then M <- P1 else M <- P2
+ Type1Node<G> m;
+ if (p1.lost > p2.lost) {
+ m = p1;
+ } else {
+ m = p2;
+ }
+
+ // If M.lost <= 1 then M <- M' for some node M' in Q such that M'.lost > 1
+ if (m.lost <= 1) {
+ m = _ll_head;
+ if (_ll_head.ll_next != null) {
+ _ll_head.ll_next.ll_prev = null;
+ }
+ _ll_head = _ll_head.ll_next;
+ }
+
+ // P <- ReInsert(Q, M)
+ _p = (Type1Node<G>) _re_insert (m);
+
+ #if DEBUG
+ _dump ("End _adjust: %p(%s), %p(%s)".printf (p1, (string) p1.data, p2, (string)
p2.data));
+ #endif
+ }
+
+ private void _delete (Node<G> n) {
+ // DecreaseKey(Q, N, infinite)
+ _decrease_key (n);
+
+ // DeleteMin(Q)
+ poll ();
+ }
+
+ private void _decrease_key (Node<G> n) {
+ #if DEBUG
+ _dump ("Start _decrease_key: %p(%s)".printf (n, (string) n.data));
+ #endif
+
+ if (n == _r || _r_prime == null) {
+ return;
+ }
+
+ n.pending_drop = true;
+
+ // If (N = R or R') and (R'.element < R.element) then
+ // Swap(R'.element, R.element); return
+ if (n == _r_prime && _compare (_r_prime, _r) < 0) {
+ _swap_data (_r_prime, _r);
+ return;
+ }
+
+ // For now we can't have type2 node other than R' (left for reference)
+ #if false
+ // If (N is of type II) and (N.element < N.parent.element) then
+ // Swap(N.element, N.parent.element); N <- N.parent
+ if (n is Type2Node && _compare (n, n.parent) < 0) {
+ _swap_data (n, n.parent);
+ n = n.parent;
+ }
+ #endif
+
+ // Can't occur as we made n be the most little (left for reference)
+ #if false
+ // If N.element >= N.parent.element then return
+ if (n.parent != null && _compare (n, n.parent) >= 0) {
+ return;
+ }
+ #endif
+
+ // P' <- ReInsert(Q, N)
+ Node<G> p_prime = _re_insert ((Type1Node<G>) n);
+
+ if (p_prime is Type2Node) {
+ // Adjust(Q, P, P);
+ _adjust (_p, _p);
+ } else {
+ // Adjust(Q, P, P');
+ _adjust (_p, (Type1Node<G>) p_prime);
+ }
+ }
+
+ private void _add_to (Type1Node<G> node, Type1Node<G> parent) {
+ parent.add (node);
+ parent.lost = 0;
+ }
+
+ private void _add_in_r_prime (Type1Node<G> node) {
+ #if DEBUG
+ _dump ("Start _add_in_r_prime: %p(%s)".printf (node, (string) node.data));
+ #endif
+
+ int degree = node.degree ();
+
+ Type1Node<G>? insertion_point = null;
+ if (degree < _a.length) {
+ insertion_point = _a[degree];
+ }
+
+ if (insertion_point == null) {
+ if (_r_prime.type1_children_tail != null) {
+ node.brothers_prev = _r_prime.type1_children_tail;
+ _r_prime.type1_children_tail.brothers_next = node;
+ } else {
+ _r_prime.type1_children_head = node;
+ }
+ _r_prime.type1_children_tail = node;
+ } else {
+ if (insertion_point.brothers_prev != null) {
+ insertion_point.brothers_prev.brothers_next = node;
+ node.brothers_prev = insertion_point.brothers_prev;
+ } else {
+ _r_prime.type1_children_head = node;
+ }
+ node.brothers_next = insertion_point;
+ insertion_point.brothers_prev = node;
+ }
+ node.parent = _r_prime;
+
+ // Maintain A, B and LP
+ if (degree >= _a.length) {
+ _a.resize (degree + 1);
+ _b.resize (degree + 1);
+ }
+
+ // If there is already a child of such degree
+ if (_a[degree] == null) {
+ _b[degree] = true;
+ } else {
+ // Else if there is an odd number of child of such degree
+ if (_b[degree]) {
+ // Make a pair
+ NodePair<G> pair = new NodePair<G> (node, node.brothers_next);
+ node.brothers_next.pair = pair;
+ node.pair = pair;
+ if (_lp_head == null) {
+ _lp_head = pair;
+ _lp_tail = pair;
+ } else {
+ pair.lp_prev = _lp_tail;
+ _lp_tail.lp_next = pair;
+ _lp_tail = pair;
+ }
+ // There is now an even number of child of such degree
+ _b[degree] = false;
+ } else {
+ _b[degree] = true;
+ }
+ }
+ _a[degree] = node;
+
+ #if DEBUG
+ _dump ("End _add_in_r_prime: %p(%s)".printf (node, (string) node.data));
+ #endif
+ }
+
+ private void _remove_type1_node (Type1Node<G> node, bool with_iteration) {
+ #if DEBUG
+ _dump ("Start _remove_type1_node: %p(%s)".printf (node, (string) node.data));
+ #endif
+
+ if (node.parent == _r_prime) {
+ _updated_degree (node, false);
+ } else {
+ // Maintain LL
+ if (node.ll_prev != null) {
+ node.ll_prev.ll_next = node.ll_next;
+ } else if (_ll_head == node) {
+ _ll_head = node.ll_next;
+ }
+ if (node.ll_next != null) {
+ node.ll_next.ll_prev = node.ll_prev;
+ } else if (_ll_tail == node) {
+ _ll_tail = node.ll_prev;
+ }
+
+ if (node.parent != null) {
+ if (node.parent.parent == _r_prime) {
+ _updated_degree ((Type1Node<G>) node.parent, true);
+ } else if (node.parent.parent != null) {
+ Type1Node<G> parent = (Type1Node<G>) node.parent;
+
+ // Increment parent's lost count
+ parent.lost++;
+
+ // And add it to LL if needed
+ if (parent.lost > 1) {
+ if (_ll_tail != null) {
+ parent.ll_prev = _ll_tail;
+ _ll_tail.ll_next = parent;
+ } else {
+ _ll_head = parent;
+ }
+ _ll_tail = parent;
+ }
+ }
+ }
+ }
+
+ // Check whether removed node is P
+ if (node == _p) {
+ _p = _r;
+ }
+
+ // Maintain brothers list
+ node.remove ();
+
+ // Maintain iteration
+ if (with_iteration) {
+ if (node.iter_prev != null) {
+ node.iter_prev.iter_next = node.iter_next;
+ } else if (_iter_head == node) {
+ _iter_head = node.iter_next;
+ }
+ if (node.iter_next != null) {
+ node.iter_next.iter_prev = node.iter_prev;
+ } else if (_iter_tail == node) {
+ _iter_tail = node.iter_prev;
+ }
+ }
+ #if DEBUG
+ _dump ("End _remove_type1_node: %p(%s)".printf (node, (string) node.data));
+ #endif
+ }
+
+ private void _updated_degree (Type1Node<G> node, bool child_removed) {
+ int degree = node.degree ();
+
+ // Ensure proper sizes of A and B
+ if (degree >= _a.length) {
+ _a.resize (degree + 1);
+ _b.resize (degree + 1);
+ }
+
+ // Maintain A and B
+ if (child_removed && _a[degree - 1] == null) {
+ _a[degree - 1] = node;
+ _b[degree - 1] = ! _b[degree - 1];
+ }
+
+ _b[degree] = ! _b[degree];
+ if (_a[degree] == node) {
+ Type1Node<G> next = node.brothers_next;
+ if (next != null && next.degree () == degree) {
+ _a[degree] = next;
+ } else {
+ _a[degree] = null;
+
+ int i = _a.length - 1;
+ while (i >= 0 && _a[i] == null) {
+ i--;
+ }
+ _a.resize (i + 1);
+ _b.resize (i + 1);
+ }
+ }
+
+ // Maintain LP
+ if (node.pair != null) {
+ NodePair<G> pair = node.pair;
+ Type1Node<G> other = (pair.node1 == node ? pair.node2 : pair.node1);
+ node.pair = null;
+ other.pair = null;
+ if (pair.lp_prev != null) {
+ pair.lp_prev.lp_next = pair.lp_next;
+ } else {
+ _lp_head = pair.lp_next;
+ }
+ if (pair.lp_next != null) {
+ pair.lp_next.lp_prev = pair.lp_prev;
+ } else {
+ _lp_tail = pair.lp_prev;
+ }
+ }
+ }
+
+ private void _remove_type2_node (Type2Node<G> node, bool with_iteration) {
+ #if DEBUG
+ _dump ("Start _remove_type2_node: %p(%s)".printf (node, (string) node.data));
+ #endif
+ ((Type1Node<G>) node.parent).type2_child = null;
+ node.parent = null;
+
+ // For now we can't have type2 node other than R' (left for reference)
+ #if false
+ // Maintain LM
+ if (node != _r_prime) {
+ if (node.lm_prev != null) {
+ node.lm_prev.lm_next = node.lm_next;
+ } else if (_lm_head == node) {
+ _lm_head = node.lm_next;
+ }
+ if (node.lm_next != null) {
+ node.lm_next.lm_prev = node.lm_prev;
+ } else if (_lm_tail == node) {
+ _lm_tail = node.lm_prev;
+ }
+ node.lm_next = null;
+ node.lm_prev = null;
+ }
+ #endif
+
+ // Maintain iteration
+ if (with_iteration) {
+ if (node.iter_prev != null) {
+ node.iter_prev.iter_next = node.iter_next;
+ } else if (_iter_head == node) {
+ _iter_head = node.iter_next;
+ }
+ if (node.iter_next != null) {
+ node.iter_next.iter_prev = node.iter_prev;
+ } else if (_iter_tail == node) {
+ _iter_tail = node.iter_prev;
+ }
+ }
+ #if DEBUG
+ _dump ("End _remove_type2_node: %p(%s)".printf (node, (string) node.data));
+ #endif
+ }
+
+ #if DEBUG
+ public void _dump (string message) {
+ stdout.printf (">>>> %s\n", message);
+
+ stdout.printf ("A.length = %d:", _a.length);
+ foreach (Node<G>? node in _a) {
+ stdout.printf (" %p(%s);", node, node != null ? (string) node.data : null);
+ }
+ stdout.printf ("\n");
+
+ stdout.printf ("B.length = %d:", _b.length);
+ foreach (bool even in _b) {
+ stdout.printf (" %s;", even.to_string ());
+ }
+ stdout.printf ("\n");
+
+ stdout.printf ("LP:");
+ unowned NodePair<G>? pair = _lp_head;
+ while (pair != null) {
+ stdout.printf (" (%p(%s),%p(%s));", pair.node1, (string) pair.node1.data, pair.node2,
(string) pair.node2.data);
+ pair = pair.lp_next;
+ }
+ stdout.printf ("\n");
+
+ stdout.printf ("LL:");
+ unowned Type1Node<G>? node = _ll_head;
+ while (node != null) {
+ stdout.printf (" %p(%s);", node, (string) node.data);
+ node = node.ll_next;
+ }
+ stdout.printf ("\n");
+
+ stdout.printf ("ITER:");
+ unowned Node<G>? inode_prev = null;
+ unowned Node<G>? inode = _iter_head;
+ while (inode != null) {
+ stdout.printf (" %p(%s);", inode, (string) inode.data);
+ assert (inode.iter_prev == inode_prev);
+ inode_prev = inode;
+ inode = inode.iter_next;
+ }
+ stdout.printf ("\n");
+
+ stdout.printf ("%s\n", _r != null ? _r.to_string () : null);
+
+ stdout.printf ("\n");
+ }
+ #endif
+
+ private abstract class Node<G> {
+ public G data;
+ public weak Node<G>? parent = null;
+
+ public int type1_children_count;
+ public Type1Node<G>? type1_children_head = null;
+ public Type1Node<G>? type1_children_tail = null;
+
+ public unowned Node<G>? iter_prev;
+ public unowned Node<G>? iter_next = null;
+
+ public bool pending_drop;
+
+ protected Node (G data, ref unowned Node<G>? head, ref unowned Node<G>? tail) {
+ this.data = data;
+ iter_prev = tail;
+ tail = this;
+ if (iter_prev != null) {
+ iter_prev.iter_next = this;
+ }
+ if (head == null) {
+ head = this;
+ }
+ }
+
+ public inline int degree () {
+ return type1_children_count;
+ }
+
+ #if DEBUG
+ public string children_to_string (int level = 0) {
+ StringBuilder builder = new StringBuilder ();
+ bool first = true;
+ Type1Node<G> child = type1_children_head;
+ while (child != null) {
+ if (!first) {
+ builder.append (",\n");
+ }
+ first = false;
+ builder.append (child.to_string (level));
+ child = child.brothers_next;
+ }
+ return builder.str;
+ }
+
+ public abstract string to_string (int level = 0);
+ #endif
+ }
+
+ private class Type1Node<G> : Node<G> {
+ public uint lost;
+ public weak Type1Node<G>? brothers_prev = null;
+ public Type1Node<G>? brothers_next = null;
+ public Type2Node<G>? type2_child = null;
+ public weak Type1Node<G>? ll_prev = null;
+ public Type1Node<G>? ll_next = null;
+ public weak NodePair<G>? pair = null;
+
+ public Type1Node (G data, ref unowned Node<G>? head, ref unowned Node<G>? tail) {
+ base (data, ref head, ref tail);
+ }
+
+ public inline void add (Type1Node<G> node) {
+ node.parent = this;
+ if (type1_children_head == null) {
+ type1_children_head = node;
+ } else {
+ node.brothers_prev = type1_children_tail;
+ }
+ if (type1_children_tail != null) {
+ type1_children_tail.brothers_next = node;
+ }
+ type1_children_tail = node;
+ type1_children_count++;
+ }
+
+ public inline void remove () {
+ if (brothers_prev == null) {
+ parent.type1_children_head = brothers_next;
+ } else {
+ brothers_prev.brothers_next = brothers_next;
+ }
+ if (brothers_next == null) {
+ parent.type1_children_tail = brothers_prev;
+ } else {
+ brothers_next.brothers_prev = brothers_prev;
+ }
+ parent.type1_children_count--;
+ parent = null;
+ brothers_prev = null;
+ brothers_next = null;
+ }
+
+ #if DEBUG
+ public override string to_string (int level = 0) {
+ StringBuilder builder = new StringBuilder ();
+ builder.append (string.nfill (level, '\t'));
+ builder.append ("(");
+ builder.append_printf("%p(%s)/%u", this, (string)data, lost);
+ if (type1_children_head != null || type2_child != null) {
+ builder.append (":\n");
+ }
+ if (type1_children_head != null) {
+ builder.append (children_to_string (level + 1));
+ }
+ if (type1_children_head != null && type2_child != null) {
+ builder.append (",\n");
+ }
+ if (type2_child != null) {
+ builder.append (type2_child.to_string (level + 1));
+ }
+ if (type1_children_head != null || type2_child != null) {
+ builder.append ("\n");
+ builder.append (string.nfill (level, '\t'));
+ }
+ builder.append (")");
+ return builder.str;
+ }
+ #endif
+ }
+
+ private class Type2Node<G> : Node<G> {
+ // For now we can't have type2 node other than R' (left for reference)
+ #if false
+ public weak Type2Node<G>? lm_prev = null;
+ public Type2Node<G>? lm_next = null;
+ #endif
+
+ public Type2Node (G data, ref unowned Node<G>? head, ref unowned Node<G>? tail) {
+ base (data, ref head, ref tail);
+ }
+
+ #if DEBUG
+ public override string to_string (int level = 0) {
+ StringBuilder builder = new StringBuilder ();
+ builder.append (string.nfill (level, '\t'));
+ builder.append_printf ("[%p(%s)", this, (string)data);
+ if (type1_children_head != null) {
+ builder.append (":\n");
+ builder.append (children_to_string (level + 1));
+ builder.append ("\n");
+ builder.append (string.nfill (level, '\t'));
+ }
+ builder.append ("]");
+ return builder.str;
+ }
+ #endif
+ }
+
+ private class DummyNode<G> : Node<G> {
+ public DummyNode (ref unowned Node<G>? prev_next, ref unowned Node<G>? next_prev, Node<G>?
iter_prev, Node<G>? iter_next) {
+ #if DEBUG
+ base ("<<dummy>>", ref prev_next, ref next_prev);
+ #else
+ base (null, ref prev_next, ref next_prev);
+ #endif
+ this.iter_prev = iter_prev;
+ this.iter_next = iter_next;
+ prev_next = next_prev = this;
+ }
+
+ #if DEBUG
+ public override string to_string (int level = 0) {
+ StringBuilder builder = new StringBuilder ();
+ builder.append (string.nfill (level, '\t'));
+ builder.append ("%p<<dummy>>".printf(this));
+ return builder.str;
+ }
+ #endif
+ }
+
+ private class NodePair<G> {
+ public weak NodePair<G>? lp_prev = null;
+ public NodePair<G>? lp_next = null;
+ public Type1Node<G> node1 = null;
+ public Type1Node<G> node2 = null;
+
+ public NodePair (Type1Node<G> node1, Type1Node<G> node2) {
+ this.node1 = node1;
+ this.node2 = node2;
+ }
+ }
+
+ private class Iterator<G> : Object, 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;
+ this.previous = null;
+ this.stamp = queue._stamp;
+ }
+
+ public bool next () {
+ unowned Node<G>? next = _get_next_node ();
+ if (next != null) {
+ previous = position;
+ position = next;
+ }
+ return next != null;
+ }
+
+ public bool has_next () {
+ return _get_next_node () != null;
+ }
+
+ private inline unowned Node<G>? _get_next_node () {
+ if (position != null) {
+ return position.iter_next;
+ } else {
+ return (previous != null) ? previous.iter_next : queue._iter_head;
+ }
+ }
+
+ public new G get () {
+ assert (stamp == queue._stamp);
+ assert (position != null);
+ return position.data;
+ }
+
+ public void remove () {
+ assert (stamp == queue._stamp);
+ assert (position != null);
+ DummyNode<G> dn;
+ if (previous != null) {
+ dn = new DummyNode<G> (ref previous.iter_next, ref position.iter_prev,
previous, position);
+ } else {
+ dn = new DummyNode<G> (ref queue._iter_head, ref position.iter_prev, null,
position);
+ }
+ queue._delete (position);
+ position = null;
+ if (previous != null) {
+ previous.iter_next = dn.iter_next;
+ }
+ if (dn == queue._iter_head) {
+ queue._iter_head = dn.iter_next;
+ }
+ if (dn.iter_next != null) {
+ dn.iter_next.iter_prev = previous;
+ }
+ if (dn == queue._iter_tail) {
+ queue._iter_tail = previous;
+ }
+ stamp++;
+ assert (stamp == queue._stamp);
+ }
+
+ public bool read_only { get { return false; } }
+
+ public bool valid { get { return position != null; } }
+
+ public bool foreach (ForallFunc<G> f) {
+ if (position == null) {
+ position = (previous != null) ? previous.iter_next : queue._iter_head;
+ }
+ if (position == null) {
+ return true;
+ }
+ if (!f (position.data)) {
+ return false;
+ }
+ while (position.iter_next != null) {
+ previous = position;
+ position = position.iter_next;
+ if (!f (position.data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/gee/queue.vala b/gee/queue.vala
new file mode 100644
index 0000000..df678d1
--- /dev/null
+++ b/gee/queue.vala
@@ -0,0 +1,115 @@
+/* queue.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * A collection designed for holding elements prior to processing.
+ *
+ * Although all Queue implementations do not limit the amount of elements they
+ * can contain, this interface supports for capacity-bounded queues. When
+ * capacity is not bound, then the {@link capacity} and
+ * {@link remaining_capacity} both return {@link UNBOUNDED_CAPACITY}.
+ *
+ * This interface defines methods that will never fail whatever the state of
+ * the queue is. For capacity-bounded queues, those methods will either return
+ * ``false`` or ``null`` to specify that the insert or retrieval did not occur
+ * because the queue was full or empty.
+ *
+ * Queue implementations are not limited to First-In-First-Out behavior and can
+ * propose different ordering of their elements. Each Queue implementation have
+ * to specify how it orders its elements.
+ *
+ * Queue implementations do not allow insertion of ``null`` elements, although
+ * some implementations, such as {@link LinkedList}, do not prohibit insertion
+ * of ``null``. Even in the implementations that permit it, ``null`` should not be
+ * inserted into a Queue, as ``null`` is also used as a special return value by
+ * the poll method to indicate that the queue contains no elements.
+ */
+[GenericAccessors]
+public interface Vala.Queue<G> : Collection<G> {
+
+ /**
+ * The unbounded capacity value.
+ */
+ public const int UNBOUNDED_CAPACITY = -1;
+
+ /**
+ * The capacity of this queue (or ``null`` if capacity is not bound).
+ */
+ public abstract int capacity { get; }
+
+ /**
+ * The remaining capacity of this queue (or ``null`` if capacity is not
+ * bound).
+ */
+ public abstract int remaining_capacity { get; }
+
+ /**
+ * Specifies whether this queue is full.
+ */
+ public abstract bool is_full { get; }
+
+ /**
+ * Offers the specified element to this queue.
+ *
+ * @param element the element to offer to the queue
+ *
+ * @return ``true`` if the element was added to the queue
+ */
+ public virtual bool offer (G element) {
+ return add (element);
+ }
+
+ /**
+ * Peeks (retrieves, but not remove) an element from this queue.
+ *
+ * @return the element peeked from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? peek ();
+
+ /**
+ * Polls (retrieves and remove) an element from this queue.
+ *
+ * @return the element polled from the queue (or ``null`` if none was
+ * available)
+ */
+ public abstract G? poll ();
+
+ /**
+ * Drains the specified amount of elements from this queue in the specified
+ * recipient collection.
+ *
+ * @param recipient the recipient collection to drain the elements to
+ * @param amount the amount of elements to drain
+ *
+ * @return the amount of elements that were actually drained
+ */
+ public virtual int drain (Collection<G> recipient, int amount = -1) {
+ G? item = null;
+ int drained = 0;
+ while((amount == -1 || --amount >= 0) && (item = poll ()) != null) {
+ recipient.add (item);
+ drained++;
+ }
+ return drained;
+ }
+}
diff --git a/gee/readonlybidirlist.vala b/gee/readonlybidirlist.vala
new file mode 100644
index 0000000..3287950
--- /dev/null
+++ b/gee/readonlybidirlist.vala
@@ -0,0 +1,73 @@
+/* readonlybidirlist.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+internal class Vala.ReadOnlyBidirList<G> : Vala.ReadOnlyList<G>, BidirList<G> {
+
+ /**
+ * Constructs a read-only list that mirrors the content of the specified
+ * list.
+ *
+ * @param list the list to decorate.
+ */
+ public ReadOnlyBidirList (BidirList<G> list) {
+ base (list);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public BidirListIterator<G> bidir_list_iterator () {
+ return new Iterator<G> (((Vala.BidirList<G>) _collection).bidir_list_iterator ());
+ }
+
+ /**
+ * The read-only view of this list.
+ */
+ public virtual new BidirList<G> read_only_view { owned get { return this; } }
+
+ private class Iterator<G> : ReadOnlyList.Iterator<G>, BidirIterator<G>, BidirListIterator<G> {
+ public Iterator (ListIterator<G> iterator) {
+ base (iterator);
+ }
+
+ public bool previous () {
+ return ((BidirIterator<G>) _iter).previous ();
+ }
+
+ public bool has_previous () {
+ return ((BidirIterator<G>) _iter).has_previous ();
+ }
+
+ public bool first () {
+ return ((BidirIterator<G>) _iter).first ();
+ }
+
+ public bool last () {
+ return ((BidirIterator<G>) _iter).last ();
+ }
+
+ public void insert (G item) {
+ assert_not_reached ();
+ }
+ }
+}
+
diff --git a/gee/readonlybidirsortedmap.vala b/gee/readonlybidirsortedmap.vala
new file mode 100644
index 0000000..a50c036
--- /dev/null
+++ b/gee/readonlybidirsortedmap.vala
@@ -0,0 +1,80 @@
+/* readonlybidirsortedmap.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+/**
+ * Read-only view for {@link BidirSortedMap} collections.
+ *
+ * This class decorates any class which implements the {@link BidirSortedMap}
+ * interface by making it read only. Any method which normally modify data will
+ * throw an error.
+ *
+ * @see BidirSortedMap
+ */
+internal class Vala.ReadOnlyBidirSortedMap<K,V> : ReadOnlySortedMap<K,V>, BidirSortedMap<K,V> {
+ /**
+ * Constructs a read-only map that mirrors the content of the specified map.
+ *
+ * @param set the set to decorate.
+ */
+ public ReadOnlyBidirSortedMap (BidirSortedMap<K,V> map) {
+ base (map);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.BidirMapIterator<K,V> bidir_map_iterator () {
+ return new BidirMapIterator<K,V> ((_map as BidirSortedMap<K,V>).bidir_map_iterator ());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new BidirSortedMap<K,V> read_only_view {
+ owned get {
+ return this;
+ }
+ }
+
+ protected class BidirMapIterator<K,V> : Vala.ReadOnlyMap.MapIterator<K,V>, Vala.BidirMapIterator<K,V>
{
+ public BidirMapIterator (Vala.BidirMapIterator<K,V> iterator) {
+ base (iterator);
+ }
+
+ public bool first () {
+ return (_iter as Vala.BidirMapIterator<K,V>).first ();
+ }
+
+ public bool previous () {
+ return (_iter as Vala.BidirMapIterator<K,V>).previous ();
+ }
+
+ public bool has_previous () {
+ return (_iter as Vala.BidirMapIterator<K,V>).has_previous ();
+ }
+
+ public bool last () {
+ return (_iter as Vala.BidirMapIterator<K,V>).last ();
+ }
+ }
+}
+
diff --git a/gee/readonlybidirsortedset.vala b/gee/readonlybidirsortedset.vala
new file mode 100644
index 0000000..f5b4ad7
--- /dev/null
+++ b/gee/readonlybidirsortedset.vala
@@ -0,0 +1,71 @@
+/* readonlybidirsortedset.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+/**
+ * Read-only view for {@link BidirSortedSet} collections.
+ *
+ * This class decorates any class which implements the {@link BidirSortedSet}
+ * interface by making it read only. Any method which normally modify data will
+ * throw an error.
+ *
+ * @see BidirSortedSet
+ */
+internal class Vala.ReadOnlyBidirSortedSet<G> : ReadOnlySortedSet<G>, BidirSortedSet<G> {
+ /**
+ * Constructs a read-only set that mirrors the content of the specified set.
+ *
+ * @param set the set to decorate.
+ */
+ public ReadOnlyBidirSortedSet (BidirSortedSet<G> set) {
+ base (set);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.BidirIterator<G> bidir_iterator () {
+ return new BidirIterator<G> ((_collection as BidirSortedSet<G>).bidir_iterator ());
+ }
+
+ protected class BidirIterator<G> : Vala.ReadOnlyCollection.Iterator<G>, Vala.BidirIterator<G> {
+ public BidirIterator (Vala.BidirIterator<G> iterator) {
+ base (iterator);
+ }
+
+ public bool first () {
+ return (_iter as Vala.BidirIterator<G>).first ();
+ }
+
+ public bool previous () {
+ return (_iter as Vala.BidirIterator<G>).previous ();
+ }
+
+ public bool has_previous () {
+ return (_iter as Vala.BidirIterator<G>).has_previous ();
+ }
+
+ public bool last () {
+ return (_iter as Vala.BidirIterator<G>).last ();
+ }
+ }
+}
+
diff --git a/gee/readonlycollection.vala b/gee/readonlycollection.vala
new file mode 100644
index 0000000..f810f20
--- /dev/null
+++ b/gee/readonlycollection.vala
@@ -0,0 +1,235 @@
+/* readonlycollection.vala
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ *
+ * 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:
+ * Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+/**
+ * Read-only view for {@link Collection} 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 Collection
+ */
+internal class Vala.ReadOnlyCollection<G> : Object, Traversable<G>, Iterable<G>, Collection<G> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size {
+ get { return _collection.size; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool is_empty {
+ get { return _collection.is_empty; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool read_only {
+ get { return true; }
+ }
+
+ protected Collection<G> _collection;
+
+ /**
+ * Constructs a read-only collection that mirrors the content of the
+ * specified collection.
+ *
+ * @param collection the collection to decorate.
+ */
+ public ReadOnlyCollection (Collection<G> collection) {
+ this._collection = collection;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool foreach (ForallFunc<G> f) {
+ return _collection.foreach (f);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.Iterator<A> stream<A> (owned StreamFunc<A> f) {
+ return _collection.stream<A> ((owned)f);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.Iterator<G> filter (owned Predicate<G> f) {
+ return _collection.filter ((owned)f);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.Iterator<G> chop (int offset, int length = -1) {
+ return _collection.chop (offset, length);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Type element_type {
+ get { return typeof (G); }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.Iterator<G> iterator () {
+ return new Iterator<G> (_collection.iterator ());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool contains (G item) {
+ return _collection.contains (item);
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public bool add (G item) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public bool remove (G item) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public void clear () {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public bool add_all (Collection<G> collection) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool contains_all (Collection<G> collection) {
+ return _collection.contains_all (collection);
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public bool remove_all (Collection<G> collection) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only collection).
+ */
+ public bool retain_all (Collection<G> collection) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G[] to_array () {
+ return _collection.to_array ();
+ }
+
+ protected class Iterator<G> : Object, Traversable<G>, Vala.Iterator<G> {
+ protected Vala.Iterator<G> _iter;
+
+ public Iterator (Vala.Iterator<G> iterator) {
+ _iter = iterator;
+ }
+
+ public bool next () {
+ return _iter.next ();
+ }
+
+ public bool has_next () {
+ return _iter.has_next ();
+ }
+
+ public new G get () {
+ return _iter.get ();
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public bool valid {
+ get {
+ return _iter.valid;
+ }
+ }
+
+ public bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public Type element_type {
+ get { return typeof (G); }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ return _iter.foreach (f);
+ }
+
+ public Vala.Iterator<A> stream<A> (owned StreamFunc<A, G> f) {
+ return _iter.stream<A> ((owned)f);
+ }
+
+ public Vala.Iterator<G> filter (owned Predicate<G> f) {
+ return _iter.filter ((owned)f);
+ }
+
+ public Vala.Iterator<G> chop (int offset, int length = -1) {
+ return _iter.chop ( offset, length);
+ }
+ }
+
+ public virtual Collection<G> read_only_view {
+ owned get { return this; }
+ }
+
+}
+
diff --git a/gee/readonlylist.vala b/gee/readonlylist.vala
new file mode 100644
index 0000000..de44c65
--- /dev/null
+++ b/gee/readonlylist.vala
@@ -0,0 +1,149 @@
+/* readonlylist.vala
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ *
+ * 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:
+ * Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+/**
+ * Read-only view for {@link List} collections.
+ *
+ * This class decorates any class which implements the {@link List}
+ * interface by making it read only. Any method which normally modify data will
+ * throw an error.
+ *
+ * @see List
+ */
+internal class Vala.ReadOnlyList<G> : Vala.ReadOnlyCollection<G>, List<G> {
+
+ /**
+ * Constructs a read-only list that mirrors the content of the specified
+ * list.
+ *
+ * @param list the list to decorate.
+ */
+ public ReadOnlyList (List<G> list) {
+ base (list);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ListIterator<G> list_iterator () {
+ return new Iterator<G> (((Vala.List<G>) _collection).list_iterator ());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int index_of (G item) {
+ return ((Vala.List<G>) _collection).index_of (item);
+ }
+
+ /**
+ * Unimplemented method (read only list).
+ */
+ public void insert (int index, G item) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only list).
+ */
+ public G remove_at (int index) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new G? get (int index) {
+ return ((Vala.List<G>) _collection).get (index);
+ }
+
+ /**
+ * Unimplemented method (read only list).
+ */
+ public new void set (int index, G o) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<G>? slice (int start, int stop) {
+ return ((Vala.List<G>) _collection).slice (start, stop);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? first () {
+ return ((Vala.List<G>) _collection).first ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? last () {
+ return ((Vala.List<G>) _collection).last ();
+ }
+
+ /**
+ * Unimplemented method (read only list).
+ */
+ public void insert_all (int index, Collection<G> collection) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sort (owned CompareDataFunc<G>? compare = null) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public virtual new List<G> read_only_view {
+ owned get { return this; }
+ }
+
+
+ protected class Iterator<G> : ReadOnlyCollection.Iterator<G>, ListIterator<G> {
+ public Iterator (ListIterator<G> iterator) {
+ base (iterator);
+ }
+
+ public new void set (G item) {
+ assert_not_reached ();
+ }
+
+ public void add (G item) {
+ assert_not_reached ();
+ }
+
+ public int index () {
+ return ((ListIterator<G>) _iter).index ();
+ }
+ }
+}
+
diff --git a/gee/readonlymap.vala b/gee/readonlymap.vala
new file mode 100644
index 0000000..c14ebbe
--- /dev/null
+++ b/gee/readonlymap.vala
@@ -0,0 +1,297 @@
+/* readonlymap.vala
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ *
+ * 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:
+ * Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+/**
+ * Read-only view for {@link Map} collections.
+ *
+ * This class decorates any class which implements the {@link Map} interface
+ * by making it read only. Any method which normally modify data will throw an
+ * error.
+ *
+ * @see Map
+ */
+internal class Vala.ReadOnlyMap<K,V> : Object, Traversable<Map.Entry<K,V>>, Iterable<Map.Entry<K,V>>,
Map<K,V> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size {
+ get { return _map.size; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool is_empty {
+ get { return _map.is_empty; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool read_only {
+ get { return true; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<K> keys {
+ owned get {
+ return _map.keys;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<V> values {
+ owned get {
+ return _map.values;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<Map.Entry<K,V>> entries {
+ owned get {
+ return _map.entries;
+ }
+ }
+
+ protected Map<K,V> _map;
+
+ /**
+ * Constructs a read-only map that mirrors the content of the specified map.
+ *
+ * @param map the map to decorate.
+ */
+ public ReadOnlyMap (Map<K,V> map) {
+ this._map = map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool has_key (K key) {
+ return _map.has_key (key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool contains (K key) {
+ return _map.has_key (key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool has (K key, V value) {
+ return _map.has (key, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new V? get (K key) {
+ return _map.get (key);
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public new void set (K key, V value) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public bool unset (K key, out V? value = null) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public bool remove (K key, out V? value = null) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public void clear () {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.MapIterator<K,V> map_iterator () {
+ return new MapIterator<K,V> (_map.map_iterator ());
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public void set_all (Map<K,V> map) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public bool unset_all (Map<K,V> map) {
+ assert_not_reached ();
+ }
+
+ /**
+ * Unimplemented method (read only map).
+ */
+ public bool remove_all (Map<K,V> map) {
+ assert_not_reached ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool has_all (Map<K,V> map) {
+ return _map.has_all (map);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool contains_all (Map<K,V> map) {
+ return _map.has_all (map);
+ }
+
+ public virtual Map<K,V> read_only_view {
+ owned get { return this; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Type key_type {
+ get { return typeof (K); }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Type value_type {
+ get { return typeof (V); }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Type element_type {
+ get { return typeof (Map.Entry); }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Map.Entry<K,V>> iterator () {
+ return entries.iterator ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public bool foreach (ForallFunc<Map.Entry<K, V>> f) {
+ return _map.foreach (f);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<A> stream<A> (owned StreamFunc<Map.Entry<K, V>, A> f) {
+ return _map.stream<A> ((owned) f);
+ }
+
+ public Iterator<Map.Entry<K, V>> filter (owned Predicate<Map.Entry<K, V>> f) {
+ return _map.filter ((owned)f);
+ }
+
+ public Iterator<Map.Entry<K, V>> chop (int offset, int length = -1) {
+ return _map.chop (offset, length);
+ }
+
+ protected class MapIterator<K,V> : Object, Vala.MapIterator<K,V> {
+ protected Vala.MapIterator<K,V> _iter;
+
+ public MapIterator (Vala.MapIterator<K,V> iterator) {
+ _iter = iterator;
+ }
+
+ public bool next () {
+ return _iter.next ();
+ }
+
+ public bool has_next () {
+ return _iter.has_next ();
+ }
+
+ public K get_key () {
+ return _iter.get_key ();
+ }
+
+ public V get_value () {
+ return _iter.get_value ();
+ }
+
+ public void set_value (V value) {
+ assert_not_reached ();
+ }
+
+ 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/readonlyset.vala b/gee/readonlyset.vala
new file mode 100644
index 0000000..f8b1f9d
--- /dev/null
+++ b/gee/readonlyset.vala
@@ -0,0 +1,50 @@
+/* readonlyset.vala
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ *
+ * 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:
+ * Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+/**
+ * Read-only view for {@link Set} collections.
+ *
+ * This class decorates any class which implements the {@link Set} interface
+ * by making it read only. Any method which normally modify data will throw an
+ * error.
+ *
+ * @see Set
+ */
+internal class Vala.ReadOnlySet<G> : Vala.ReadOnlyCollection<G>, Set<G> {
+
+ /**
+ * Constructs a read-only set that mirrors the content of the specified set.
+ *
+ * @param set the set to decorate.
+ */
+ public ReadOnlySet (Set<G> set) {
+ base (set);
+ }
+
+ public virtual new Set<G> read_only_view {
+ owned get { return this; }
+ }
+
+}
+
diff --git a/gee/readonlysortedmap.vala b/gee/readonlysortedmap.vala
new file mode 100644
index 0000000..3b87455
--- /dev/null
+++ b/gee/readonlysortedmap.vala
@@ -0,0 +1,90 @@
+/* readonlysortedmap.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * Read-only view for {@link SortedMap} collections.
+ *
+ * This class decorates any class which implements the {@link SortedMap} interface
+ * by making it read only. Any method which normally modify data will throw an
+ * error.
+ *
+ * @see SortedMap
+ */
+internal class Vala.ReadOnlySortedMap<K,V> : ReadOnlyMap<K,V>, SortedMap<K,V> {
+ /**
+ * Constructs a read-only map that mirrors the content of the specified map.
+ *
+ * @param map the map to decorate.
+ */
+ public ReadOnlySortedMap (Map<K,V> map) {
+ base (map);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedMap<K,V> head_map (K before) {
+ return (_map as SortedMap<K,V>).head_map (before).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedMap<K,V> tail_map (K after) {
+ return (_map as SortedMap<K,V>).tail_map (after).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedMap<K,V> sub_map (K from, K to) {
+ return (_map as SortedMap<K,V>).sub_map (from, to).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<K> ascending_keys {
+ owned get {
+ return (_map as SortedMap<K,V>).ascending_keys.read_only_view;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<Map.Entry<K,V>> ascending_entries {
+ owned get {
+ return (_map as SortedMap<K,V>).ascending_entries.read_only_view;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new SortedMap<K, V> read_only_view {
+ owned get {
+ return this;
+ }
+ }
+}
+
diff --git a/gee/readonlysortedset.vala b/gee/readonlysortedset.vala
new file mode 100644
index 0000000..85cd776
--- /dev/null
+++ b/gee/readonlysortedset.vala
@@ -0,0 +1,123 @@
+/* readonlysortedset.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois, Maciej Piechotka
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * Read-only view for {@link SortedSet} collections.
+ *
+ * This class decorates any class which implements the {@link SortedSet} interface
+ * by making it read only. Any method which normally modify data will throw an
+ * error.
+ *
+ * @see SortedSet
+ */
+internal class Vala.ReadOnlySortedSet<G> : ReadOnlySet<G>, SortedSet<G> {
+ /**
+ * Constructs a read-only set that mirrors the content of the specified set.
+ *
+ * @param set the set to decorate.
+ */
+ public ReadOnlySortedSet (SortedSet<G> set) {
+ base (set);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G first () {
+ return (_collection as SortedSet<G>).first ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G last () {
+ return (_collection as SortedSet<G>).last ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vala.Iterator<G>? iterator_at (G element) {
+ var iter = (_collection as SortedSet<G>).iterator_at (element);
+ return (iter != null) ? new Iterator<G> (iter) : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? lower (G element) {
+ return (_collection as SortedSet<G>).lower (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? higher (G element) {
+ return (_collection as SortedSet<G>).higher (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? floor (G element) {
+ return (_collection as SortedSet<G>).floor (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public G? ceil (G element) {
+ return (_collection as SortedSet<G>).ceil (element);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<G> head_set (G before) {
+ return (_collection as SortedSet<G>).head_set (before).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<G> tail_set (G after) {
+ return(_collection as SortedSet<G>).tail_set (after).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<G> sub_set (G from, G to) {
+ return (_collection as SortedSet<G>).sub_set (from, to).read_only_view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public new SortedSet<G> read_only_view {
+ owned get {
+ return this;
+ }
+ }
+}
+
diff --git a/gee/set.vala b/gee/set.vala
index 6449023..ab946c2 100644
--- a/gee/set.vala
+++ b/gee/set.vala
@@ -21,8 +21,23 @@
*/
/**
- * A set is a collection without duplicates.
+ * A collection without duplicate elements.
*/
-public abstract class Vala.Set<G> : Collection<G> {
+[GenericAccessors]
+public interface Vala.Set<G> : Collection<G> {
+
+ /**
+ * The read-only view of this set.
+ */
+ public abstract new Set<G> read_only_view { owned get; }
+
+ /**
+ * 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/sortedmap.vala b/gee/sortedmap.vala
new file mode 100644
index 0000000..8b23201
--- /dev/null
+++ b/gee/sortedmap.vala
@@ -0,0 +1,66 @@
+/* sortedset.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+public interface Vala.SortedMap<K,V> : Vala.Map<K,V> {
+ /**
+ * Returns map containing pairs with key strictly lower the the argument.
+ */
+ public abstract SortedMap<K,V> head_map (K before);
+
+ /**
+ * Returns map containing pairs with key equal or larger then the argument.
+ */
+ public abstract SortedMap<K,V> tail_map (K after);
+
+ /**
+ * Returns right-open map (i.e. containing all pair which key is strictly
+ * lower then the second argument and equal or bigger then the first one).
+ *
+ * Null as one parameter means that it should include all from this side.
+ */
+ public abstract SortedMap<K,V> sub_map (K before, K after);
+
+ /**
+ * Returns the keys in ascending order.
+ */
+ public abstract SortedSet<K> ascending_keys { owned get; }
+
+ /**
+ * Returns the entries in ascending order.
+ */
+ public abstract SortedSet<Map.Entry<K,V>> ascending_entries { owned get; }
+
+ /**
+ * The read-only view this map.
+ */
+ public new abstract SortedMap<K,V> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty map.
+ *
+ * @return an immutable empty map
+ */
+ public static Map<K,V> empty<K,V> () {
+ return new TreeMap<K,V> ().read_only_view;
+ }
+}
+
diff --git a/gee/sortedset.vala b/gee/sortedset.vala
new file mode 100644
index 0000000..66ea370
--- /dev/null
+++ b/gee/sortedset.vala
@@ -0,0 +1,137 @@
+/* sortedset.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois, Maciej Piechotka
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+/**
+ * A sorted set, which you can navigate over and get sub-sets of.
+ */
+[GenericAccessors]
+public interface Vala.SortedSet<G> : Vala.Set<G> {
+ /**
+ * Returns the first element of the sorted set. Set must not be empty.
+ *
+ * @return the first element in the sorted set
+ */
+ public abstract G first ();
+
+ /**
+ * Returns the last element of the sorted set. Set must not be empty.
+ *
+ * @return the last element in the sorted set
+ */
+ public abstract G last ();
+
+ /**
+ * Returns a {@link BidirIterator} initialy pointed at the specified
+ * element.
+ *
+ * @param element the element to point the iterator at
+ *
+ * @return a {@link BidirIterator} over this sorted set, or null if
+ * the specified element is not in this set
+ */
+ public abstract Iterator<G>? iterator_at (G element);
+
+ /**
+ * Returns the element which is strictly lower than the specified element.
+ *
+ * @param element the element which you want the lower element for
+ *
+ * @return the corresponding element
+ */
+ public abstract G? lower (G element);
+
+ /**
+ * Returns the element which is strictly higher than the specified element.
+ *
+ * @param element the element which you want the strictly higher element
+ * for
+ *
+ * @return the corresponding element
+ */
+ public abstract G? higher (G element);
+
+ /**
+ * Returns the element which is lower or equal then the specified element.
+ *
+ * @param element the element which you want the lower or equal element for
+ *
+ * @return the corresponding element
+ */
+ public abstract G? floor (G element);
+
+ /**
+ * Returns the element which is higher or equal then the specified element.
+ *
+ * @param element the element which you want the higher or equal element
+ * for
+ *
+ * @return the corresponding element
+ */
+ public abstract G? ceil (G element);
+
+ /**
+ * Returns the sub-set of this sorted set containing elements strictly
+ * lower than the specified element.
+ *
+ * @param before the lower inclusive bound for the sub-set
+ *
+ * @return the corresponding sub-set of this sorted set
+ */
+ public abstract SortedSet<G> head_set (G before);
+
+ /**
+ * Returns the sub-set of this sorted set containing elements equal or
+ * higher than the specified element.
+ *
+ * @param after the higher exclusive bound for the sub-set
+ *
+ * @return the corresponding sub-set of this sorted set
+ */
+ public abstract SortedSet<G> tail_set (G after);
+
+ /**
+ * Returns the right-open sub-set of this sorted set, thus containing
+ * elements equal or higher than the specified ``from`` element, and stricly
+ * lower than the specified ``to`` element.
+ *
+ * @param from the lower inclusive bound for the sub-set
+ * @param to the higher exclusive bound for the sub-set
+ *
+ * @return the corresponding sub-set of this sorted set
+ */
+ public abstract SortedSet<G> sub_set (G from, G to);
+
+ /**
+ * The read-only view of this set.
+ */
+ public abstract new SortedSet<G> read_only_view { owned get; }
+
+ /**
+ * Returns an immutable empty sorted set.
+ *
+ * @return an immutable empty sorted set
+ */
+ public static SortedSet<G> empty<G> () {
+ return new TreeSet<G> ().read_only_view;
+ }
+}
diff --git a/gee/timsort.vala b/gee/timsort.vala
new file mode 100644
index 0000000..5d1a862
--- /dev/null
+++ b/gee/timsort.vala
@@ -0,0 +1,713 @@
+/* timsort.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * A stable, adaptive, iterative mergesort that requires far fewer than n*lg(n)
+ * comparisons when running on partially sorted arrays, while offering
+ * performance comparable to a traditional mergesort when run on random arrays.
+ * Like all proper mergesorts, this sort is stable and runs O(n*log(n)) time
+ * (worst case). In the worst case, this sort requires temporary storage space
+ * for n/2 object references; in the best case, it requires only a small
+ * constant amount of space.
+ *
+ * This implementation was adapted from Tim Peters's list sort for Python,
+ * which is described in detail here:
+ * [[http://svn.python.org/projects/python/trunk/Objects/listsort.txt]]
+ *
+ * Tim's C code may be found here:
+ * [[http://svn.python.org/projects/python/trunk/Objects/listobject.c]]
+ *
+ * The underlying techniques are described in this paper (and may have even
+ * earlier origins):
+ *
+ * "Optimistic Sorting and Information Theoretic Complexity"
+ * Peter McIlroy
+ * SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), pp
+ * 467-474, Austin, Texas, 25-27 January 1993.
+ */
+internal class Vala.TimSort<G> : Object {
+
+ public static void sort<G> (List<G> list, CompareDataFunc<G> compare) {
+ if (list is ArrayList) {
+ TimSort.sort_arraylist<G> ((ArrayList<G>) list, compare);
+ } else {
+ TimSort.sort_list<G> (list, compare);
+ }
+ }
+
+ private static void sort_list<G> (List<G> list, CompareDataFunc<G> compare) {
+ TimSort<G> helper = new TimSort<G> ();
+
+ helper.list_collection = list;
+ helper.array = list.to_array ();
+ helper.list = helper.array;
+ helper.index = 0;
+ helper.size = list.size;
+ helper.compare = compare;
+
+ helper.do_sort ();
+
+ // TODO Use a list iterator and use iter.set (item)
+ list.clear ();
+ foreach (G item in helper.array) {
+ list.add (item);
+ }
+ }
+
+ private static void sort_arraylist<G> (ArrayList<G> list, CompareDataFunc<G> compare) {
+ TimSort<G> helper = new TimSort<G> ();
+
+ helper.list_collection = list;
+ helper.list = list._items;
+ helper.index = 0;
+ helper.size = list._size;
+ helper.compare = compare;
+
+ helper.do_sort ();
+ }
+
+ private const int MINIMUM_GALLOP = 7;
+
+ private List<G> list_collection;
+ private G[] array;
+ private void** list;
+ private int index;
+ private int size;
+ private Slice<G>[] pending;
+ private int minimum_gallop;
+ private CompareDataFunc<G> compare;
+
+ private void do_sort () {
+ if (size < 2) {
+ return;
+ }
+
+ pending = new Slice<G>[0];
+ minimum_gallop = MINIMUM_GALLOP;
+
+ Slice<G> remaining = new Slice<G> (list, index, size);
+ int minimum_length = compute_minimum_run_length (remaining.length);
+
+ while (remaining.length > 0) {
+ // Get the next run
+ bool descending;
+ Slice<G> run = compute_longest_run (remaining, out descending);
+ #if DEBUG
+ message ("New run (%d, %d) %s", run.index, run.length,
+ descending ? "descending" : "ascending");
+ #endif
+ if (descending) {
+ run.reverse ();
+ }
+
+ // Extend it to minimum_length, if needed
+ if (run.length < minimum_length) {
+ int sorted_count = run.length;
+ run.length = int.min (minimum_length, remaining.length);
+ insertion_sort (run, sorted_count);
+ #if DEBUG
+ message ("Extended to (%d, %d) and sorted from index %d",
+ run.index, run.length, sorted_count);
+ #endif
+ }
+
+ // Move remaining after run
+ remaining.shorten_start (run.length);
+
+ // Add run to pending runs and try to merge
+ pending += (owned) run;
+ merge_collapse ();
+ }
+
+ assert (remaining.index == size);
+
+ merge_force_collapse ();
+
+ assert (pending.length == 1);
+ assert (pending[0].index == 0);
+ assert (pending[0].length == size);
+ }
+
+ private delegate bool LowerFunc (G left, G right);
+
+ private inline bool lower_than (G left, G right) {
+ return compare (left, right) < 0;
+ }
+
+ private inline bool lower_than_or_equal_to (G left, G right) {
+ return compare (left, right) <= 0;
+ }
+
+ private int compute_minimum_run_length (int length) {
+ int run_length = 0;
+ while (length >= 64) {
+ run_length |= length & 1;
+ length >>= 1;
+ }
+ return length + run_length;
+ }
+
+ private Slice<G> compute_longest_run (Slice<G> a, out bool descending) {
+ int run_length;
+ if (a.length <= 1) {
+ run_length = a.length;
+ descending = false;
+ } else {
+ run_length = 2;
+ if (lower_than (a.list[a.index + 1], a.list[a.index])) {
+ descending = true;
+ for (int i = a.index + 2; i < a.index + a.length; i++) {
+ if (lower_than (a.list[i], a.list[i-1])) {
+ run_length++;
+ } else {
+ break;
+ }
+ }
+ } else {
+ descending = false;
+ for (int i = a.index + 2; i < a.index + a.length; i++) {
+ if (lower_than (a.list[i], a.list[i-1])) {
+ break;
+ } else {
+ run_length++;
+ }
+ }
+ }
+ }
+ return new Slice<G> (a.list, a.index, run_length);
+ }
+
+ private void insertion_sort (Slice<G> a, int offset) {
+ #if DEBUG
+ message ("Sorting (%d, %d) at %d", a.index, a.length, offset);
+ #endif
+ for (int start = a.index + offset; start < a.index + a.length; start++) {
+ int left = a.index;
+ int right = start;
+ void* pivot = a.list[right];
+
+ while (left < right) {
+ int p = left + ((right - left) >> 1);
+ if (lower_than (pivot, a.list[p])) {
+ right = p;
+ } else {
+ left = p + 1;
+ }
+ }
+ assert (left == right);
+
+ Memory.move (&a.list[left + 1], &a.list[left], sizeof (G) * (start - left));
+ a.list[left] = pivot;
+ }
+ }
+
+ private void merge_collapse () {
+ #if DEBUG
+ message ("Merge Collapse");
+ #endif
+ int count = pending.length;
+ while (count > 1) {
+ #if DEBUG
+ message ("Pending count: %d", count);
+ if (count >= 3) {
+ message ("pending[count-3]=%p; pending[count-2]=%p;
pending[count-1]=%p",
+ pending[count-3], pending[count-2], pending[count-1]);
+ }
+ #endif
+ if (count >= 3 && pending[count-3].length <= pending[count-2].length +
pending[count-1].length) {
+ if (pending[count-3].length < pending[count-1].length) {
+ merge_at (count-3);
+ } else {
+ merge_at (count-2);
+ }
+ } else if (pending[count-2].length <= pending[count-1].length) {
+ merge_at (count-2);
+ } else {
+ break;
+ }
+ count = pending.length;
+ #if DEBUG
+ message ("New pending count: %d", count);
+ #endif
+ }
+ }
+
+ private void merge_force_collapse () {
+ #if DEBUG
+ message ("Merge Force Collapse");
+ #endif
+ int count = pending.length;
+ #if DEBUG
+ message ("Pending count: %d", count);
+ #endif
+ while (count > 1) {
+ if (count >= 3 && pending[count-3].length < pending[count-1].length) {
+ merge_at (count-3);
+ } else {
+ merge_at (count-2);
+ }
+ count = pending.length;
+ #if DEBUG
+ message ("New pending count: %d", count);
+ #endif
+ }
+ }
+
+ private void merge_at (int index) {
+ #if DEBUG
+ message ("Merge at %d", index);
+ #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);
+
+ pending[index] = new Slice<G> (list, a.index, a.length + b.length);
+ pending.move (index + 2, index + 1, pending.length - index - 2);
+ pending.length -= 1;
+
+ int sorted_count = gallop_rightmost (b.peek_first (), a, 0);
+ a.shorten_start (sorted_count);
+ if (a.length == 0) {
+ return;
+ }
+
+ b.length = gallop_leftmost (a.peek_last (), b, b.length - 1);
+ if (b.length == 0) {
+ return;
+ }
+
+ if (a.length <= b.length) {
+ merge_low ((owned) a, (owned) b);
+ } else {
+ merge_high ((owned) a, (owned) b);
+ }
+ }
+
+ private int gallop_leftmost (G key, Slice<G> a, int hint) {
+ #if DEBUG
+ message ("Galop leftmost in (%d, %d), hint=%d", a.index, a.length, hint);
+ #endif
+ assert (0 <= hint);
+ assert (hint < a.length);
+
+ int p = a.index + hint;
+ int last_offset = 0;
+ int offset = 1;
+ if (lower_than (a.list[p], key)) {
+ int max_offset = a.length - hint;
+ while (offset < max_offset) {
+ if (lower_than (a.list[p + offset], key)) {
+ last_offset = offset;
+ offset <<= 1;
+ offset++;
+ } else {
+ break;
+ }
+ }
+
+ if (offset > max_offset) {
+ offset = max_offset;
+ }
+
+ last_offset = hint + last_offset;
+ offset = hint + offset;
+ } else {
+ int max_offset = hint + 1;
+ while (offset < max_offset) {
+ if (lower_than (a.list[p - offset], key)) {
+ break;
+ } else {
+ last_offset = offset;
+ offset <<= 1;
+ offset++;
+ }
+ }
+
+ if (offset > max_offset) {
+ offset = max_offset;
+ }
+
+ int temp_last_offset = last_offset;
+ int temp_offset = offset;
+ last_offset = hint - temp_offset;
+ offset = hint - temp_last_offset;
+ }
+
+ assert (-1 <= last_offset);
+ assert (last_offset < offset);
+ assert (offset <= a.length);
+
+ last_offset += 1;
+ while (last_offset < offset) {
+ int m = last_offset + ((offset - last_offset) >> 1);
+ if (lower_than (a.list[a.index + m], key)) {
+ last_offset = m + 1;
+ } else {
+ offset = m;
+ }
+ }
+
+ assert (last_offset == offset);
+ return offset;
+ }
+
+ private int gallop_rightmost (G key, Slice<G> a, int hint) {
+ #if DEBUG
+ message ("Galop rightmost in (%d, %d), hint=%d", a.index, a.length, hint);
+ #endif
+ assert (0 <= hint);
+ assert (hint < a.length);
+
+ int p = a.index + hint;
+ int last_offset = 0;
+ int offset = 1;
+ if (lower_than_or_equal_to (a.list[p], key)) {
+ int max_offset = a.length - hint;
+ while (offset < max_offset) {
+ if (lower_than_or_equal_to (a.list[p + offset], key)) {
+ last_offset = offset;
+ offset <<= 1;
+ offset++;
+ } else {
+ break;
+ }
+ }
+
+ if (offset > max_offset) {
+ offset = max_offset;
+ }
+
+ last_offset = hint + last_offset;
+ offset = hint + offset;
+ } else {
+ int max_offset = hint + 1;
+ while (offset < max_offset) {
+ if (lower_than_or_equal_to (a.list[p - offset], key)) {
+ break;
+ } else {
+ last_offset = offset;
+ offset <<= 1;
+ offset++;
+ }
+ }
+
+ if (offset > max_offset) {
+ offset = max_offset;
+ }
+
+ int temp_last_offset = last_offset;
+ int temp_offset = offset;
+ last_offset = hint - temp_offset;
+ offset = hint - temp_last_offset;
+ }
+
+ assert (-1 <= last_offset);
+ assert (last_offset < offset);
+ assert (offset <= a.length);
+
+ last_offset += 1;
+ while (last_offset < offset) {
+ int m = last_offset + ((offset - last_offset) >> 1);
+ if (lower_than_or_equal_to (a.list[a.index + m], key)) {
+ last_offset = m + 1;
+ } else {
+ offset = m;
+ }
+ }
+
+ assert (last_offset == offset);
+ return offset;
+ }
+
+ private void merge_low (owned Slice<G> a, owned Slice<G> b) {
+ #if DEBUG
+ message ("Merge low (%d, %d) (%d, %d)", a.index, a.length, b.index, b.length);
+ #endif
+ assert (a.length > 0);
+ assert (b.length > 0);
+ assert (a.index + a.length == b.index);
+
+ int minimum_gallop = this.minimum_gallop;
+ int dest = a.index;
+ a.copy ();
+
+ try {
+ list[dest++] = b.pop_first ();
+ if (a.length == 1 || b.length == 0) {
+ return;
+ }
+
+ while (true) {
+ int a_count = 0;
+ int b_count = 0;
+
+ while (true) {
+ if (lower_than (b.peek_first (), a.peek_first ())) {
+ list[dest++] = b.pop_first ();
+ if (b.length == 0) {
+ return;
+ }
+
+ b_count++;
+ a_count = 0;
+ if (b_count >= minimum_gallop) {
+ break;
+ }
+ } else {
+ list[dest++] = a.pop_first ();
+ if (a.length == 1) {
+ return;
+ }
+
+ a_count++;
+ b_count = 0;
+ if (a_count >= minimum_gallop) {
+ break;
+ }
+ }
+ }
+
+ minimum_gallop++;
+
+ while (true) {
+ minimum_gallop -= (minimum_gallop > 1 ? 1 : 0);
+ this.minimum_gallop = minimum_gallop;
+
+ a_count = gallop_rightmost (b.peek_first (), a, 0);
+ a.merge_in (list, a.index, dest, a_count);
+ dest += a_count;
+ a.shorten_start (a_count);
+ if (a.length <= 1) {
+ return;
+ }
+
+ list[dest++] = b.pop_first ();
+ if (b.length == 0) {
+ return;
+ }
+
+ b_count = gallop_leftmost (a.peek_first (), b, 0);
+ b.merge_in (list, b.index, dest, b_count);
+ dest += b_count;
+ b.shorten_start (b_count);
+ if (b.length == 0) {
+ return;
+ }
+
+ list[dest++] = a.pop_first ();
+ if (a.length == 1) {
+ return;
+ }
+
+ if (a_count < MINIMUM_GALLOP && b_count < MINIMUM_GALLOP) {
+ break;
+ }
+ }
+
+ minimum_gallop++;
+ this.minimum_gallop = minimum_gallop;
+ }
+ } finally {
+ assert (a.length >= 0);
+ assert (b.length >= 0);
+ b.merge_in (list, b.index, dest, b.length);
+ a.merge_in (list, a.index, dest + b.length, a.length);
+ }
+ }
+
+ private void merge_high (owned Slice<G> a, owned Slice<G> b) {
+ #if DEBUG
+ message ("Merge high (%d, %d) (%d, %d)", a.index, a.length, b.index, b.length);
+ #endif
+ assert (a.length > 0);
+ assert (b.length > 0);
+ assert (a.index + a.length == b.index);
+
+ int minimum_gallop = this.minimum_gallop;
+ int dest = b.index + b.length;
+ b.copy ();
+
+ try {
+ list[--dest] = a.pop_last ();
+ if (a.length == 0 || b.length == 1) {
+ return;
+ }
+
+ while (true) {
+ int a_count = 0;
+ int b_count = 0;
+
+ while (true) {
+ if (lower_than (b.peek_last (), a.peek_last ())) {
+ list[--dest] = a.pop_last ();
+ if (a.length == 0) {
+ return;
+ }
+
+ a_count++;
+ b_count = 0;
+ if (a_count >= minimum_gallop) {
+ break;
+ }
+ } else {
+ list[--dest] = b.pop_last ();
+ if (b.length == 1) {
+ return;
+ }
+
+ b_count++;
+ a_count = 0;
+ if (b_count >= minimum_gallop) {
+ break;
+ }
+ }
+ }
+
+ minimum_gallop++;
+
+ while (true) {
+ minimum_gallop -= (minimum_gallop > 1 ? 1 : 0);
+ this.minimum_gallop = minimum_gallop;
+
+ int k = gallop_rightmost (b.peek_last (), a, a.length - 1);
+ a_count = a.length - k;
+ a.merge_in_reversed (list, a.index + k, dest - a_count, a_count);
+ dest -= a_count;
+ a.shorten_end (a_count);
+ if (a.length == 0) {
+ return;
+ }
+
+ list[--dest] = b.pop_last ();
+ if (b.length == 1) {
+ return;
+ }
+
+ k = gallop_leftmost (a.peek_last (), b, b.length - 1);
+ b_count = b.length - k;
+ b.merge_in_reversed (list, b.index + k, dest - b_count, b_count);
+ dest -= b_count;
+ b.shorten_end (b_count);
+ if (b.length <= 1) {
+ return;
+ }
+
+ list[--dest] = a.pop_last ();
+ if (a.length == 0) {
+ return;
+ }
+
+ if (a_count < MINIMUM_GALLOP && b_count < MINIMUM_GALLOP) {
+ break;
+ }
+ }
+
+ minimum_gallop++;
+ this.minimum_gallop = minimum_gallop;
+ }
+ } finally {
+ assert (a.length >= 0);
+ assert (b.length >= 0);
+ a.merge_in_reversed (list, a.index, dest - a.length, a.length);
+ b.merge_in_reversed (list, b.index, dest - a.length - b.length, b.length);
+ }
+ }
+
+ [Compact]
+ private class Slice<G> {
+
+ public void** list;
+ public void** new_list;
+ public int index;
+ public int length;
+
+ public Slice (void** list, int index, int length) {
+ this.list = list;
+ this.index = index;
+ this.length = length;
+ }
+
+ ~Slice () {
+ if (new_list != null)
+ free (new_list);
+ }
+
+ public void copy () {
+ new_list = Memory.dup (&list[index], (uint) sizeof (G) * length);
+ list = new_list;
+ index = 0;
+ }
+
+ public inline void merge_in (void** dest_array, int index, int dest_index, int count) {
+ Memory.move (&dest_array[dest_index], &list[index], sizeof (G) * count);
+ }
+
+ public inline void merge_in_reversed (void** dest_array, int index, int dest_index, int
count) {
+ Memory.move (&dest_array[dest_index], &list[index], sizeof (G) * count);
+ }
+
+ public inline void shorten_start (int n) {
+ index += n;
+ length -= n;
+ }
+
+ public inline void shorten_end (int n) {
+ length -= n;
+ }
+
+ public inline void* pop_first () {
+ length--;
+ return list[index++];
+ }
+
+ public inline void* pop_last () {
+ length--;
+ return list[index + length];
+ }
+
+ public inline unowned void* peek_first () {
+ return list[index];
+ }
+
+ public inline unowned void* peek_last () {
+ return list[index + length - 1];
+ }
+
+ public void reverse () {
+ int low = index;
+ int high = index + length - 1;
+ while (low < high) {
+ swap (low++, high--);
+ }
+ }
+
+ private inline void swap (int i, int j) {
+ void* temp = list[i];
+ list[i] = list[j];
+ list[j] = temp;
+ }
+ }
+}
+
diff --git a/gee/traversable.vala b/gee/traversable.vala
new file mode 100644
index 0000000..5589622
--- /dev/null
+++ b/gee/traversable.vala
@@ -0,0 +1,379 @@
+/* traversable.vala
+ *
+ * Copyright (C) 2011-2012 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 {
+ public delegate A FoldFunc<A, G> (owned G g, owned A a);
+ public delegate bool ForallFunc<G> (owned G g);
+ public delegate Lazy<A>? UnfoldFunc<A> ();
+ public delegate Traversable.Stream StreamFunc<G, A> (Traversable.Stream state, owned Lazy<G>? g, out
Lazy<A>? lazy);
+ public delegate A MapFunc<A, G> (owned G g);
+ public delegate bool Predicate<G> (G g);
+}
+
+/**
+ * It's a common interface for {@link Iterator} and {@link Iterable}. It
+ * provides a fast, high level functions.
+ *
+ * ''{@link Iterator} implementation:'' Please note that most of the functions
+ * affect the state of the iterator by moving it forward.
+ * Even if the iterator is {@link BidirIterator} it ''must not''
+ * rewind the state.
+ *
+ * ''{@link Iterable} implementation:'' validy ({@link Iterator.valid})
+ * of returned iterator is the same as for invalid
+ * iterator. In other words the following code is semantically equivalent:
+ *
+ * {{{
+ * var x = iterable.function (args);
+ * var x = iterable.iterator ().function(args);
+ * }}}
+ *
+ * @since 0.7.0
+ */
+[GenericAccessors]
+public interface Vala.Traversable<G> : Object {
+ /**
+ * Apply function to each element returned by iterator untill last element
+ * or function return ''false''.
+ *
+ * ''{@link Iterator} implementation:'' Operation moves the iterator
+ * to last element in iteration or the first element that returned ''false''.
+ * If iterator points at some element it will be included in iteration.
+ *
+ * @return ''false'' if the argument returned ''false'' at last invocation and
+ * ''true'' otherwise.
+ */
+ public new abstract bool foreach (ForallFunc<G> f);
+
+ /**
+ * Stream function is an abstract function allowing writing many
+ * operations.
+ *
+ * The stream function accepts three parameter:
+ *
+ * 1. state. It is usually the last returned value from function but
+ * it may be {@link Stream.END} when {@link Stream.CONTINUE} was
+ * returned and there was no more elements.
+ * 1. input. It is valid only if first argument is
+ * {@link Stream.CONTINUE}
+ * 1. output. It is valid only if result is Stream.YIELD
+ *
+ * It may return one of 3 results:
+ *
+ * 1. {@link Stream.YIELD}. It means that value was yielded and can
+ * be passed to outgoing iterator.
+ * 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.
+ *
+ * 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.
+ *
+ * Note: In {@link Iterator} implementation: if iterator is
+ * {@link Iterator.valid} the current value should be fed
+ * immediately to function if during initial call function returns
+ * {@link Stream.CONTINUE}. The parent iterator cannot be used before
+ * the functions return {@link Stream.END} afterwards it points on the
+ * last element consumed.
+ *
+ * @param f function generating stream
+ * @return iterator containing values yielded by stream
+ */
+ public virtual Iterator<A> stream<A> (owned StreamFunc<G, A> f) {
+ Iterator<G>? self;
+ 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);
+ } else if ((iself = this as Iterable<G>) != null) {
+ return iself.iterator().stream<A> ((owned) f);
+ } else {
+ assert_not_reached ();
+ }
+ }
+
+ /**
+ * Standard aggregation function.
+ *
+ * It takes a function, seed and first element, returns the new seed and
+ * progress to next element when the operation repeats.
+ *
+ * Note: Default implementation uses {@link foreach}.
+ *
+ * Note: In {@link Iterator} implementation operation moves the
+ * iterator to last element in iteration. If iterator is
+ * {@link Iterator.valid} the current element will be considered
+ * as well.
+ *
+ */
+ public virtual A fold<A> (FoldFunc<A, G> f, owned A seed)
+ {
+ this.foreach ((item) => {seed = f ((owned) item, (owned) seed); return true; });
+ return (owned) seed;
+ }
+
+ /**
+ * Produces an iterator pointing at elements generated by function passed.
+ *
+ * Iterator is lazy evaluated but value is force-evaluated when
+ * iterator moves to next element. ({@link Iterator.next})
+ *
+ * Note: Default implementation uses {@link stream}.
+ *
+ * Note: In {@link Iterator} implementation if the parent iterator is
+ * {@link Iterator.valid} so is the returned one. Using the parent
+ * iterator is not allowed before the inner iterator {@link Iterator.next}
+ * return false and then it points on its last element.
+ * The resulting iterator is {@link Iterator.valid} if the parent
+ * iterator is.
+ *
+ * @param f Mapping function
+ * @return Iterator listing mapped value
+ */
+ public virtual Iterator<A> map<A> (MapFunc<A, G> f) {
+ return stream<A>((state, item, out val) => {
+ switch (state) {
+ case Stream.YIELD:
+ val = null;
+ return Stream.CONTINUE;
+ case Stream.CONTINUE:
+ val = new Lazy<A>(() => {
+ A tmp = item.get ();
+ item = null;
+ return (f ((owned)tmp));
+ });
+ return Stream.YIELD;
+ case Stream.END:
+ val = null;
+ return Stream.END;
+ default:
+ assert_not_reached ();
+ }
+ });
+ }
+
+ /**
+ * Creates a new iterator that is initially pointing to seed. Then
+ * subsequent values are obtained after applying the function to previous
+ * value and the subsequent items.
+ *
+ * The resulting iterator is always valid and it contains the seed value.
+ *
+ * Note: Default implementation uses {@link stream}.
+ *
+ * Note: When the method is called on {@link Iterator} using the parent
+ * iterator is not allowed befor the inner iterator
+ * {@link Iterator.next} return false and then it points on its last
+ * element. The resulting iterator is {@link Iterator.valid}.
+ *
+ * @param f Folding function
+ * @param seed original seed value
+ * @return Iterator containing values of subsequent values of seed
+ */
+ public virtual Iterator<A> scan<A> (FoldFunc<A, G> f, owned A seed) {
+ bool seed_emitted = false;
+ return stream<A>((state, item, out val) => {
+ switch (state) {
+ case Stream.YIELD:
+ if (seed_emitted) {
+ val = null;
+ return Stream.CONTINUE;
+ } else {
+ val = new Lazy<A>.from_value (seed);
+ seed_emitted = true;
+ return Stream.YIELD;
+ }
+ case Stream.CONTINUE:
+ val = new Lazy<A> (() => {
+ A tmp = item.get ();
+ item = null;
+ seed = f ((owned) tmp, (owned) seed);
+ return seed;
+ });
+ return Stream.YIELD;
+ case Stream.END:
+ val = null;
+ return Stream.END;
+ default:
+ assert_not_reached ();
+ }
+ });
+ }
+
+ /**
+ * Creates a new iterator that contains only values that fullfills the
+ * predicate.
+ *
+ * Note: When the method is called on {@link Iterator} using the parent
+ * iterator is not allowed befor the inner iterator
+ * {@link Iterator.next} return false and then it points on its last
+ * element. The resulting iterator is {@link Iterator.valid} if parent
+ * iterator is {@link Iterator.valid} and value it is pointing on
+ * fullfills the predicate.
+ *
+ * @param f Folding function
+ * @return Iterator containing values of subsequent values of seed
+ */
+ public virtual Iterator<G> filter (owned Predicate<G> pred) {
+ return stream<G> ((state, item, out val) => {
+ switch (state) {
+ case Stream.YIELD:
+ val = null;
+ return Stream.CONTINUE;
+ case Stream.CONTINUE:
+ G g = item.get ();
+ if (pred (g)) {
+ val = item;
+ return Stream.YIELD;
+ } else {
+ val = null;
+ return Stream.CONTINUE;
+ }
+ case Stream.END:
+ val = null;
+ return Stream.END;
+ default:
+ assert_not_reached ();
+ };
+ });
+ }
+
+ /**
+ * Creates a new iterator which contains elements from iterable. The
+ * first argument states the offset i.e. number of elements the iterator
+ * skips by default.
+ *
+ * Note: In {@link Iterator} implementation resulting iterator is
+ * {@link Iterator.valid} when parent iterator is
+ * {@link Iterator.valid} and the offset is 0. Using the parent
+ * iterator is not allowed before the inner iterator
+ * {@link Iterator.next} return false and then it points on its last
+ * element.
+ *
+ * @param offset the offset to first element the iterator is pointing to
+ * @param length maximum number of elements iterator may return. Negative
+ * value means that the number is unbounded
+ */
+ public virtual Iterator<G> chop (int offset, int length = -1) {
+ assert (offset >= 0);
+ return stream<G> ((state, item, out val) => {
+ switch (state) {
+ case Stream.YIELD:
+ val = null;
+ if (offset > 0) {
+ return Stream.CONTINUE;
+ } else if (length > 0) {
+ return length != 0 ? Stream.CONTINUE : Stream.END;
+ } else if (length == 0) {
+ return Stream.END;
+ } else {
+ return Stream.CONTINUE;
+ }
+ case Stream.CONTINUE:
+ if (offset == 0) {
+ val = item;
+ length--;
+ return Stream.YIELD;
+ } else {
+ val = null;
+ offset--;
+ return Stream.CONTINUE;
+ }
+ case Stream.END:
+ val = null;
+ return Stream.END;
+ default:
+ assert_not_reached ();
+ };
+ });
+ }
+
+
+ /**
+ * The type of the elements in this collection.
+ */
+ public virtual Type element_type { get { return typeof (G); } }
+
+ public enum Stream {
+ YIELD,
+ CONTINUE,
+ END
+ }
+
+}
+
diff --git a/gee/treemap.vala b/gee/treemap.vala
new file mode 100644
index 0000000..bba4809
--- /dev/null
+++ b/gee/treemap.vala
@@ -0,0 +1,1914 @@
+/* treemap.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+using GLib;
+
+/**
+ * Left-leaning red-black tree implementation of the {@link Map} interface.
+ *
+ * This implementation is especially well designed for large quantity of
+ * data. The (balanced) tree implementation insure that the set and get
+ * methods are in logarithmic complexity.
+ *
+ * @see HashMap
+ */
+public class Vala.TreeMap<K,V> : Vala.AbstractBidirSortedMap<K,V> {
+ /**
+ * {@inheritDoc}
+ */
+ public override int size {
+ get { return _size; }
+ }
+
+ public override bool read_only {
+ get { return false; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Set<K> keys {
+ owned get {
+ var keys = _keys;
+ if (_keys == null) {
+ keys = new KeySet<K,V> (this);
+ _keys = keys;
+ keys.add_weak_pointer ((void**) (&_keys));
+ }
+ return keys;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Collection<V> values {
+ owned get {
+ var values = _values;
+ if (_values == null) {
+ values = new ValueCollection<K,V> (this);
+ _values = values;
+ values.add_weak_pointer ((void**) (&_values));
+ }
+ return values;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Set<Map.Entry<K,V>> entries {
+ owned get {
+ var entries = _entries;
+ if (_entries == null) {
+ entries = new EntrySet<K,V> (this);
+ _entries = entries;
+ entries.add_weak_pointer ((void**) (&_entries));
+ }
+ return entries;
+ }
+ }
+
+ /**
+ * The keys' comparator function.
+ */
+ [CCode (notify = false)]
+ public CompareDataFunc<K> key_compare_func { private set; get; }
+
+ /**
+ * The values' equality testing function.
+ */
+ [CCode (notify = false)]
+ public EqualDataFunc<V> value_equal_func { private set; get; }
+
+ private int _size = 0;
+
+ private weak SortedSet<K> _keys;
+ private weak Collection<V> _values;
+ private weak SortedSet<Map.Entry<K,V>> _entries;
+
+ /**
+ * Constructs a new, empty tree map sorted according to the specified
+ * comparator function.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param key_compare_func an optional key comparator function
+ * @param value_equal_func an optional values equality testing function
+ */
+ public TreeMap (owned CompareDataFunc<K>? key_compare_func = null, owned EqualDataFunc<V>?
value_equal_func = null) {
+ if (key_compare_func == null) {
+ key_compare_func = Functions.get_compare_func_for (typeof (K));
+ }
+ 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;
+ }
+
+ ~TreeMap () {
+ clear ();
+ }
+
+ private void rotate_right (ref Node<K, V> root) {
+ Node<K,V> pivot = (owned) root.left;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.left = (owned) pivot.right;
+ pivot.right = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private void rotate_left (ref Node<K, V> root) {
+ Node<K,V> pivot = (owned) root.right;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.right = (owned) pivot.left;
+ pivot.left = (owned) root;
+ root = (owned) pivot;
+ }
+
+ private bool is_red (Node<K, V>? n) {
+ return n != null && n.color == Node.Color.RED;
+ }
+
+ private bool is_black (Node<K, V>? n) {
+ return n == null || n.color == Node.Color.BLACK;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool has_key (K key) {
+ weak Node<K, V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return true;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool has (K key, V value) {
+ V? own_value = get (key);
+ return (own_value != null && value_equal_func (own_value, value));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override V? get (K key) {
+ weak Node<K, V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return cur.value;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ private bool set_to_node (ref Node<K, V>? node, K key, V value, out V? old_value, Node<K, V>? prev,
Node<K, V>? next) {
+ if (node == null) {
+ old_value = null;
+ node = new Node<K,V> (key, value, prev, next);
+ if (prev == null) {
+ first = node;
+ }
+ if (next == null) {
+ last = node;
+ }
+ _size++;
+ return true;
+ }
+
+ int cmp = key_compare_func (key, node.key);
+ bool changed;
+ if (cmp == 0) {
+ if (value_equal_func (value, node.value)) {
+ old_value = null;
+ changed = false;
+ } else {
+ old_value = (owned) node.value;
+ node.value = value;
+ changed = true;
+ }
+ } else if (cmp < 0) {
+ changed = set_to_node (ref node.left, key, value, out old_value, node.prev, node);
+ } else {
+ changed = set_to_node (ref node.right, key, value, out old_value, node, node.next);
+ }
+
+ fix_up (ref node);
+ return changed;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void set (K key, V value) {
+ V old_value;
+ set_to_node (ref root, key, value, out old_value, null, null);
+ root.color = Node.Color.BLACK;
+ stamp++;
+ }
+
+ private void move_red_left (ref Node<K, V> root) {
+ root.flip ();
+ if (is_red (root.right.left)) {
+ rotate_right (ref root.right);
+ rotate_left (ref root);
+ root.flip ();
+ }
+ }
+
+ private void move_red_right (ref Node<K, V> root) {
+ root.flip ();
+ if (is_red (root.left.left)) {
+ rotate_right (ref root);
+ root.flip ();
+ }
+ }
+
+ private void fix_removal (ref Node<K,V> node, out K? key = null, out V? value = null) {
+ Node<K,V> n = (owned) node;
+ key = (owned) n.key;
+ value = (owned) n.value;
+ if (n.prev != null) {
+ n.prev.next = n.next;
+ } else {
+ first = n.next;
+ }
+ if (n.next != null) {
+ n.next.prev = n.prev;
+ } else {
+ last = n.next;
+ }
+ n.value = null;
+ node = null;
+ _size--;
+ }
+
+ private void remove_minimal (ref Node<K,V> node, out K key, out V value) {
+ if (node.left == null) {
+ fix_removal (ref node, out key, out value);
+ return;
+ }
+
+ if (is_black (node.left) && is_black (node.left.left)) {
+ move_red_left (ref node);
+ }
+
+ remove_minimal (ref node.left, out key, out value);
+
+ fix_up (ref node);
+ }
+
+ private bool remove_from_node (ref Node<K, V>? node, K key, out V? value, out unowned Node<K, V>?
prev = null, out unowned Node<K, V>? next = null) {
+ if (node == null) {
+ value = null;
+ next = null;
+ prev = null;
+ return false;
+ } else if (key_compare_func (key, node.key) < 0) {
+ weak Node<K,V> left = node.left;
+ if (left == null) {
+ value = null;
+ next = null;
+ prev = null;
+ return false;
+ }
+ if (node.left != null && is_black (left) && is_black (left.left)) {
+ move_red_left (ref node);
+ }
+ bool r = remove_from_node (ref node.left, key, out value, out prev, out next);
+ fix_up (ref node);
+ return r;
+ } else {
+ if (is_red (node.left)) {
+ rotate_right (ref node);
+ }
+
+ weak Node<K,V>? r = node.right;
+ if (key_compare_func (key, node.key) == 0 && r == null) {
+ prev = node.prev;
+ next = node.next;
+ fix_removal (ref node, null, out value);
+ return true;
+ }
+ if (is_black (r) && r != null && is_black (r.left)) {
+ move_red_right (ref node);
+ }
+ if (key_compare_func (key, node.key) == 0) {
+ value = (owned) node.value;
+ prev = node.prev;
+ next = node;
+ remove_minimal (ref node.right, out node.key, out node.value);
+ fix_up (ref node);
+ return true;
+ } else {
+ bool re = remove_from_node (ref node.right, key, out value, out prev, out
next);
+ fix_up (ref node);
+ return re;
+ }
+ }
+ }
+
+ private void fix_up (ref Node<K,V> node) {
+ if (is_black (node.left) && is_red (node.right)) {
+ rotate_left (ref node);
+ }
+ if (is_red (node.left) && is_red (node.left.left)) {
+ rotate_right (ref node);
+ }
+ if (is_red (node.left) && is_red (node.right)) {
+ node.flip ();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool unset (K key, out V? value = null) {
+ bool b = remove_from_node (ref root, key, out value);
+
+ if (root != null) {
+ root.color = Node.Color.BLACK;
+ }
+ stamp++;
+ return b;
+ }
+
+ private inline void clear_subtree (owned Node<K,V> node) {
+ node.key = null;
+ node.value = null;
+ if (node.left != null)
+ clear_subtree ((owned) node.left);
+ if (node.right != null)
+ clear_subtree ((owned) node.right);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear () {
+ if (root != null) {
+ clear_subtree ((owned) root);
+ first = last = null;
+ }
+ _size = 0;
+ stamp++;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedMap<K,V> head_map (K before) {
+ return new SubMap<K,V> (this, new Range<K,V>.head (this, before));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedMap<K,V> tail_map (K after) {
+ return new SubMap<K,V> (this, new Range<K,V>.tail (this, after));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedMap<K,V> sub_map (K after, K before) {
+ return new SubMap<K,V> (this, new Range<K,V> (this, after, before));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedSet<K> ascending_keys {
+ owned get {
+ var keys = _keys;
+ if (_keys == null) {
+ keys = new KeySet<K,V> (this);
+ _keys = keys;
+ keys.add_weak_pointer (&_keys);
+ }
+ return keys;
+ }
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedSet<Map.Entry<K,V>> ascending_entries {
+ owned get {
+ var entries = _entries;
+ if (_entries == null) {
+ entries = new EntrySet<K,V> (this);
+ _entries = entries;
+ entries.add_weak_pointer (&_entries);
+ }
+ return entries;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.MapIterator<K,V> map_iterator () {
+ return new MapIterator<K,V> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.BidirMapIterator<K,V> bidir_map_iterator () {
+ return new MapIterator<K,V> (this);
+ }
+
+ [Compact]
+ private class Node<K, V> {
+ public enum Color {
+ RED,
+ BLACK;
+
+ public Color flip () {
+ if (this == RED) {
+ return BLACK;
+ } else {
+ return RED;
+ }
+ }
+ }
+
+ public Node (owned K key, owned V value, Node<K,V>? prev, Node<K,V>? next) {
+ this.key = (owned) key;
+ this.value = (owned) value;
+ this.color = Color.RED;
+ this.prev = prev;
+ this.next = next;
+ if (prev != null) {
+ prev.next = this;
+ }
+ if (next != null) {
+ next.prev = this;
+ }
+ }
+
+ public void flip () {
+ color = color.flip ();
+ if (left != null) {
+ left.color = left.color.flip ();
+ }
+ if (right != null) {
+ right.color = right.color.flip ();
+ }
+ }
+
+ public K key;
+ public V value;
+ public Color color;
+ public Node<K, V>? left;
+ public Node<K, V>? right;
+ public weak Node<K, V>? prev;
+ public weak Node<K, V>? next;
+ public unowned Map.Entry<K,V>? entry;
+ }
+
+ private Node<K, V>? root = null;
+ private weak Node<K, V>? first = null;
+ private weak Node<K, V>? last = null;
+ private int stamp = 0;
+
+ private inline K min (K a, K b) {
+ return key_compare_func (a, b) <= 0 ? a : b;
+ }
+
+ private inline K max (K a, K b) {
+ return key_compare_func (a, b) > 0 ? a : b;
+ }
+
+ private inline unowned Node<K,V>? find_node (K key) {
+ unowned Node<K,V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return cur;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ private inline unowned Node<K,V>? find_nearest (K key) {
+ unowned Node<K,V>? cur = root;
+ while (cur != null) {
+ int res = key_compare_func (key, cur.key);
+ if (res == 0) {
+ return cur;
+ } else if (res < 0) {
+ if (cur.left == null)
+ return cur;
+ cur = cur.left;
+ } else {
+ if (cur.right == null)
+ return cur;
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ private class Entry<K,V> : Map.Entry<K,V> {
+ private unowned Node<K,V> _node;
+
+ public static Map.Entry<K,V> entry_for<K,V> (Node<K,V> node) {
+ Map.Entry<K,V> result = node.entry;
+ if (result == null) {
+ result = new Entry<K,V> (node);
+ node.entry = result;
+ result.add_weak_pointer ((void**) (&node.entry));
+ }
+ return result;
+ }
+
+ public Entry (Node<K,V> node) {
+ _node = node;
+ }
+
+ public override K key { get { return _node.key; } }
+
+ public override V value {
+ get { return _node.value; }
+ set { _node.value = value; }
+ }
+
+ public override bool read_only { get { return false; } }
+ }
+
+ private inline unowned Node<K,V>? find_lower (K key) {
+ unowned Node<K,V>? node = find_nearest (key);
+ if (node == null)
+ return null;
+ return key_compare_func (key, node.key) <= 0 ? node.prev : node;
+ }
+
+ private inline unowned Node<K,V>? find_higher (K key) {
+ unowned Node<K,V>? node = find_nearest (key);
+ if (node == null)
+ return null;
+ return key_compare_func (key, node.key) >= 0 ? node.next : node;
+ }
+
+ private inline unowned Node<K,V>? find_floor (K key) {
+ unowned Node<K,V>? node = find_nearest (key);
+ if (node == null)
+ return null;
+ return key_compare_func (key, node.key) < 0 ? node.prev : node;
+ }
+
+ private inline unowned Node<K,V>? find_ceil (K key) {
+ unowned Node<K,V>? node = find_nearest (key);
+ if (node == null)
+ return null;
+ return key_compare_func (key, node.key) > 0 ? node.next : node;
+ }
+
+ private inline K? lift_null_key (Node<K,V>? node) {
+ return node != null ? node.key : null;
+ }
+
+ private class Range<K,V> {
+ public Range (TreeMap<K,V> map, K after, K before) {
+ this.map = map;
+ if (map.key_compare_func (after, before) < 0) {
+ this.after = after;
+ this.before = before;
+ type = RangeType.BOUNDED;
+ } else {
+ type = RangeType.EMPTY;
+ }
+ }
+
+ public Range.head (TreeMap<K,V> map, K before) {
+ this.map = map;
+ this.before = before;
+ type = RangeType.HEAD;
+ }
+
+ public Range.tail (TreeMap<K,V> map, K after) {
+ this.map = map;
+ this.after = after;
+ type = RangeType.TAIL;
+ }
+
+ public Range.empty (TreeMap<K,V> map) {
+ this.map = map;
+ type = RangeType.EMPTY;
+ }
+
+ public Range<K,V> cut_head (K after) {
+ switch (type) {
+ case RangeType.HEAD:
+ return new Range<K,V> (map, after, before);
+ case RangeType.TAIL:
+ return new Range<K,V>.tail (map, map.max (after, this.after));
+ case RangeType.EMPTY:
+ return this;
+ case RangeType.BOUNDED:
+ var _after = map.max (after, this.after);
+ return new Range<K,V> (map, _after, before);
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public Range<K,V> cut_tail (K before) {
+ switch (type) {
+ case RangeType.HEAD:
+ return new Range<K,V>.head (map, map.min (before, this.before));
+ case RangeType.TAIL:
+ return new Range<K,V> (map, after, before);
+ case RangeType.EMPTY:
+ return this;
+ case RangeType.BOUNDED:
+ var _before = map.min (before, this.before);
+ return new Range<K,V> (map, after, _before);
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public Range<K,V> cut (K after, K before) {
+ if (type == RangeType.EMPTY)
+ return this;
+ var _before = (type == RangeType.HEAD || type == RangeType.BOUNDED) ?
+ map.min (before, this.before) : before;
+ var _after = (type == RangeType.TAIL || type == RangeType.BOUNDED) ?
+ map.max (after, this.after) : after;
+ return new Range<K,V> (map, _after, _before);
+ }
+
+ public bool in_range (K key) {
+ return type == RangeType.EMPTY ? false : compare_range(key) == 0;
+ }
+
+ public int compare_range (K key) {
+ switch (type) {
+ case RangeType.HEAD:
+ return map.key_compare_func (key, before) < 0 ? 0 : 1;
+ case RangeType.TAIL:
+ return map.key_compare_func (key, after) >= 0 ? 0 : -1;
+ case RangeType.EMPTY:
+ return 0; // For simplicity - please make sure it does not break anything
+ case RangeType.BOUNDED:
+ return map.key_compare_func (key, after) >= 0 ?
+ (map.key_compare_func (key, before) < 0 ? 0 : 1) : -1;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public bool empty_submap () {
+ switch (type) {
+ case RangeType.HEAD:
+ return map.first == null || !in_range (map.first.key);
+ case RangeType.TAIL:
+ return map.last == null || !in_range (map.last.key);
+ case RangeType.EMPTY:
+ return true;
+ case RangeType.BOUNDED:
+ return first () == null;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public unowned Node<K,V>? first () {
+ switch (type) {
+ case RangeType.EMPTY:
+ return null;
+ case RangeType.HEAD:
+ return map.first;
+ default:
+ return map.find_floor (after);
+ }
+ }
+
+ public unowned Node<K,V>? last () {
+ switch (type) {
+ case RangeType.EMPTY:
+ return null;
+ case RangeType.TAIL:
+ return map.last;
+ default:
+ return map.find_lower (before);
+ }
+ }
+
+ private new TreeMap<K,V> map;
+ private K after;
+ private K before;
+ private RangeType type;
+ }
+
+ private enum RangeType {
+ HEAD,
+ TAIL,
+ EMPTY,
+ BOUNDED
+ }
+
+ private class SubMap<K,V> : AbstractBidirSortedMap<K,V> {
+ public override int size { get { return keys.size; } }
+ public bool is_empty { get { return keys.is_empty; } }
+
+ public SubMap (TreeMap<K,V> map, Range<K,V> range) {
+ this.map = map;
+ this.range = range;
+ }
+
+ private weak SortedSet<K>? _keys;
+ public override Set<K> keys {
+ owned get {
+ var keys = _keys;
+ if (_keys == null) {
+ keys = new SubKeySet<K,V> (map, range);
+ _keys = keys;
+ keys.add_weak_pointer(&_keys);
+ }
+ return keys;
+ }
+ }
+
+ private weak Collection<K>? _values;
+ public override Collection<V> values {
+ owned get {
+ var values = _values;
+ if (_values == null) {
+ values = new SubValueCollection<K,V> (map, range);
+ _values = values;
+ values.add_weak_pointer(&_values);
+ }
+ return values;
+ }
+ }
+
+ private weak SortedSet<Entry<K,V>>? _entries;
+ public override Set<Entry<K,V>> entries {
+ owned get {
+ var entries = _entries;
+ if (_entries == null) {
+ entries = new SubEntrySet<K,V> (map, range);
+ _entries = entries;
+ entries.add_weak_pointer(&_entries);
+ }
+ return entries;
+ }
+ }
+
+ public override bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public override bool has_key (K key) {
+ return range.in_range (key) && map.has_key (key);
+ }
+
+ public override bool has (K key, V value) {
+ return range.in_range (key) && map.has (key, value);
+ }
+
+ public override new V? get (K key) {
+ return range.in_range (key) ? map.get (key) : null;
+ }
+
+ public override void set (K key, V value) {
+ if (range.in_range (key))
+ map.set (key, value);
+ }
+
+ public override bool unset (K key, out V? value = null) {
+ value = null;
+ return range.in_range (key) && map.unset (key, out value);
+ }
+
+ public override void clear () {
+ for (var iterator = map_iterator (); iterator.next ();)
+ iterator.unset ();
+ }
+
+ public override 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);
+ }
+
+ public override SortedMap<K,V> head_map (K before) {
+ return new SubMap<K,V> (map, range.cut_tail (before));
+ }
+
+ public override SortedMap<K,V> tail_map (K after) {
+ return new SubMap<K,V> (map, range.cut_head (after));
+ }
+
+ public override SortedMap<K,V> sub_map (K after, K before) {
+ return new SubMap<K,V> (map, range.cut (after, before));
+ }
+
+ public override SortedSet<K> ascending_keys {
+ owned get {
+ var keys = _keys;
+ if (_keys == null) {
+ keys = new SubKeySet<K,V> (map, range);
+ _keys = keys;
+ keys.add_weak_pointer(&_keys);
+ }
+ return keys;
+ }
+ }
+
+ public override SortedSet<K> ascending_entries {
+ owned get {
+ var entries = _entries;
+ if (_entries == null) {
+ entries = new SubEntrySet<K,V> (map, range);
+ _entries = entries;
+ entries.add_weak_pointer(&_entries);
+ }
+ return _entries;
+ }
+ }
+
+ private TreeMap<K,V> map;
+ private Range<K,V> range;
+ }
+
+ private class KeySet<K,V> : AbstractBidirSortedSet<K> {
+ private TreeMap<K,V> _map;
+
+ public KeySet (TreeMap<K,V> map) {
+ _map = map;
+ }
+
+ public override Iterator<K> iterator () {
+ return new KeyIterator<K,V> (_map);
+ }
+
+ public override int size {
+ get { return _map.size; }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public override bool add (K key) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (K key) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (K key) {
+ return _map.has_key (key);
+ }
+
+ public override K first () {
+ assert (_map.first != null);
+ return _map.first.key;
+ }
+
+ public override K last () {
+ assert (_map.last != null);
+ return _map.last.key;
+ }
+
+ public override BidirIterator<K> bidir_iterator () {
+ return new KeyIterator<K,V> (_map);
+ }
+
+ public override SortedSet<K> head_set (K before) {
+ return new SubKeySet<K,V> (_map, new Range<K,V>.head (_map, before));
+ }
+
+ public override SortedSet<K> tail_set (K after) {
+ return new SubKeySet<K,V> (_map, new Range<K,V>.tail (_map, after));
+ }
+
+ public override SortedSet<K> sub_set (K after, K before) {
+ return new SubKeySet<K,V> (_map, new Range<K,V> (_map, after, before));
+ }
+
+ public override Iterator<K>? iterator_at (K item) {
+ weak Node<K,V>? node = _map.find_node (item);
+ if (node == null)
+ return null;
+ return new KeyIterator<K,V>.pointing (_map, node);
+ }
+
+ public override K? lower (K item) {
+ return _map.lift_null_key (_map.find_lower (item));
+ }
+
+ public override K? higher (K item) {
+ return _map.lift_null_key (_map.find_higher (item));
+ }
+
+ public override K? floor (K item) {
+ return _map.lift_null_key (_map.find_floor (item));
+ }
+
+ public override K? ceil (K item) {
+ return _map.lift_null_key (_map.find_ceil (item));
+ }
+ }
+
+ private class SubKeySet<K,V> : AbstractBidirSortedSet<K> {
+ [CCode (notify = false)]
+ public TreeMap<K,V> map { private set; get; }
+ [CCode (notify = false)]
+ public Range<K,V> range { private set; get; }
+
+ public SubKeySet (TreeMap<K,V> map, Range<K,V> range) {
+ this.map = map;
+ this.range = range;
+ }
+
+ public override Iterator<K> iterator () {
+ return new SubKeyIterator<K,V> (map, range);
+ }
+
+ public override int size {
+ get {
+ var i = 0;
+ Vala.Iterator<K> iterator = iterator ();
+ while (iterator.next ())
+ i++;
+ return i;
+ }
+ }
+
+ public override bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public bool is_empty { get { return range.empty_submap (); } }
+
+ public override bool add (K key) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (K key) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (K key) {
+ return range.in_range(key) && map.has_key (key);
+ }
+
+ public override BidirIterator<K> bidir_iterator () {
+ return new SubKeyIterator<K,V> (map, range);
+ }
+
+ public override K first () {
+ weak Node<K,V>? _first = range.first ();
+ assert (_first != null);
+ return _first.key;
+ }
+
+ public override K last () {
+ weak Node<K,V>? _last = range.last ();
+ assert (_last != null);
+ return _last.key;
+ }
+
+ public override SortedSet<K> head_set (K before) {
+ return new SubKeySet<K,V> (map, range.cut_tail (before));
+ }
+
+ public override SortedSet<K> tail_set (K after) {
+ return new SubKeySet<K,V> (map, range.cut_head (after));
+ }
+
+ public override SortedSet<K> sub_set (K after, K before) {
+ return new SubKeySet<K,V> (map, range.cut (after, before));
+ }
+
+ public override Iterator<K>? iterator_at (K key) {
+ if (!range.in_range (key))
+ return null;
+ weak Node<K,V>? n = map.find_node (key);
+ if (n == null)
+ return null;
+ return new SubKeyIterator<K,V>.pointing (map, range, n);
+ }
+
+ public override K? lower (K key) {
+ var res = range.compare_range (key);
+ if (res > 0)
+ return last ();
+ var l = map.lift_null_key (map.find_lower (key));
+ return l != null && range.in_range (l) ? l : null;
+ }
+
+ public override K? higher (K key) {
+ var res = range.compare_range (key);
+ if (res < 0)
+ return first ();
+ var h = map.lift_null_key (map.find_higher (key));
+ return h != null && range.in_range (h) ? h : null;
+ }
+
+ public override K? floor (K key) {
+ var res = range.compare_range (key);
+ if (res > 0)
+ return last ();
+ var l = map.lift_null_key (map.find_floor (key));
+ return l != null && range.in_range (l) ? l : null;
+ }
+
+ public override K? ceil (K key) {
+ var res = range.compare_range (key);
+ if (res < 0)
+ return first ();
+ var h = map.lift_null_key (map.find_ceil (key));
+ return h != null && range.in_range (h) ? h : null;
+ }
+ }
+
+ private class ValueCollection<K,V> : AbstractCollection<V> {
+ private TreeMap<K,V> _map;
+
+ public ValueCollection (TreeMap<K,V> map) {
+ _map = map;
+ }
+
+ public override Iterator<V> iterator () {
+ return new ValueIterator<K,V> (_map);
+ }
+
+ public override int size {
+ get { return _map.size; }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public override bool add (V key) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (V key) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (V key) {
+ Iterator<V> it = iterator ();
+ while (it.next ()) {
+ if (_map.value_equal_func (key, it.get ())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private class SubValueCollection<K,V> : AbstractCollection<V> {
+ [CCode (notify = false)]
+ public TreeMap<K,V> map { private set; get; }
+ [CCode (notify = false)]
+ public Range<K,V> range { private set; get; }
+
+ public SubValueCollection (TreeMap<K,V> map, Range<K,V> range) {
+ this.map = map;
+ this.range = range;
+ }
+
+ public override Iterator<V> iterator () {
+ return new SubValueIterator<K,V> (map, range);
+ }
+
+ public override bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public override int size {
+ get {
+ var i = 0;
+ Vala.Iterator<V> iterator = iterator ();
+ while (iterator.next ())
+ i++;
+ return i;
+ }
+ }
+
+ public bool is_empty { get { return range.empty_submap (); } }
+
+ public override bool add (V key) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (V key) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (V key) {
+ Iterator<V> it = iterator ();
+ while (it.next ()) {
+ if (map.value_equal_func (key, it.get ())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private class EntrySet<K,V> : AbstractBidirSortedSet<Map.Entry<K, V>> {
+ private TreeMap<K,V> _map;
+
+ public EntrySet (TreeMap<K,V> map) {
+ _map = map;
+ }
+
+ public override Iterator<Map.Entry<K, V>> iterator () {
+ return new EntryIterator<K,V> (_map);
+ }
+
+ public override int size {
+ get { return _map.size; }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public override bool add (Map.Entry<K, V> entry) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (Map.Entry<K, V> entry) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (Map.Entry<K, V> entry) {
+ return _map.has (entry.key, entry.value);
+ }
+
+ public override Map.Entry<K, V>/*?*/ first () {
+ assert (_map.first != null);
+ return Entry.entry_for<K,V> (_map.first);
+ }
+
+ public override Map.Entry<K, V>/*?*/ last () {
+ assert (_map.last != null);
+ return Entry.entry_for<K,V> (_map.last);
+ }
+
+ public override BidirIterator<Map.Entry<K, V>> bidir_iterator () {
+ return new EntryIterator<K,V> (_map);
+ }
+
+ public override SortedSet<Map.Entry<K, V>> head_set (Map.Entry<K, V> before) {
+ return new SubEntrySet<K,V> (_map, new Range<K,V>.head (_map, before.key));
+ }
+
+ public override SortedSet<Map.Entry<K, V>> tail_set (Map.Entry<K, V> after) {
+ return new SubEntrySet<K,V> (_map, new Range<K,V>.tail (_map, after.key));
+ }
+
+ public override SortedSet<K> sub_set (Map.Entry<K, V> after, Map.Entry<K, V> before) {
+ return new SubEntrySet<K,V> (_map, new Range<K,V> (_map, after.key, before.key));
+ }
+
+ public override Iterator<Map.Entry<K, V>>? iterator_at (Map.Entry<K, V> item) {
+ weak Node<K,V>? node = _map.find_node (item.key);
+ if (node == null || !_map.value_equal_func (node.value, item.value))
+ return null;
+ return new EntryIterator<K,V>.pointing (_map, node);
+ }
+
+ public override Map.Entry<K, V>/*?*/ lower (Map.Entry<K, V> item) {
+ weak Node<K,V>? l = _map.find_lower (item.key);
+ return l != null ? Entry.entry_for<K,V> (l) : null;
+ }
+
+ public override Map.Entry<K, V>/*?*/ higher (Map.Entry<K, V> item) {
+ weak Node<K,V>? l = _map.find_higher (item.key);
+ return l != null ? Entry.entry_for<K,V> (l) : null;
+ }
+
+ public override Map.Entry<K, V>/*?*/ floor (Map.Entry<K, V> item) {
+ weak Node<K,V>? l = _map.find_floor (item.key);
+ return l != null ? Entry.entry_for<K,V> (l) : null;
+ }
+
+ public override Map.Entry<K, V>/*?*/ ceil (Map.Entry<K, V> item) {
+ weak Node<K,V>? l = _map.find_ceil (item.key);
+ return l != null ? Entry.entry_for<K,V> (l) : null;
+ }
+ }
+
+ private class SubEntrySet<K,V> : AbstractBidirSortedSet<Map.Entry<K,V>> {
+ [CCode (notify = false)]
+ public TreeMap<K,V> map { private set; get; }
+ [CCode (notify = false)]
+ public Range<K,V> range { private set; get; }
+
+ public SubEntrySet (TreeMap<K,V> map, Range<K,V> range) {
+ this.map = map;
+ this.range = range;
+ }
+
+ public override Iterator<Map.Entry<K,V>> iterator () {
+ return new SubEntryIterator<K,V> (map, range);
+ }
+
+ public override int size {
+ get {
+ var i = 0;
+ Vala.Iterator<Map.Entry<K,V>> iterator = iterator ();
+ while (iterator.next ())
+ i++;
+ return i;
+ }
+ }
+
+ public override bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public bool is_empty { get { return range.empty_submap (); } }
+
+ public override bool add (Map.Entry<K,V> entry) {
+ assert_not_reached ();
+ }
+
+ public override void clear () {
+ assert_not_reached ();
+ }
+
+ public override bool remove (Map.Entry<K,V> entry) {
+ assert_not_reached ();
+ }
+
+ public override bool contains (Map.Entry<K,V> entry) {
+ return range.in_range(entry.key) && map.has (entry.key, entry.value);
+ }
+
+ public override BidirIterator<K> bidir_iterator () {
+ return new SubEntryIterator<K,V> (map, range);
+ }
+
+ public override Map.Entry<K,V> first () {
+ weak Node<K,V>? _first = range.first ();
+ assert (_first != null);
+ return Entry.entry_for<K,V> (_first);
+ }
+
+ public override Map.Entry<K,V> last () {
+ weak Node<K,V>? _last = range.last ();
+ assert (_last != null);
+ return Entry.entry_for<K,V> (_last);
+ }
+
+ public override SortedSet<K> 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) {
+ 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) {
+ return new SubEntrySet<K,V> (map, range.cut (after.key, before.key));
+ }
+
+ public override Iterator<Map.Entry<K,V>>? iterator_at (Map.Entry<K,V> entry) {
+ if (!range.in_range (entry.key))
+ return null;
+ weak Node<K,V>? n = map.find_node (entry.key);
+ if (n == null || !map.value_equal_func (n.value, entry.value))
+ return null;
+ return new SubEntryIterator<K,V>.pointing (map, range, n);
+ }
+
+ public override Map.Entry<K,V>/*?*/ lower (Map.Entry<K,V> entry) {
+ var res = range.compare_range (entry.key);
+ if (res > 0)
+ return last ();
+ weak Node<K,V>? l = map.find_lower (entry.key);
+ return l != null && range.in_range (l.key) ? Entry.entry_for<K,V> (l) : null;
+ }
+
+ public override Map.Entry<K,V>/*?*/ higher (Map.Entry<K,V> entry) {
+ var res = range.compare_range (entry.key);
+ if (res < 0)
+ return first ();
+ weak Node<K,V>? h = map.find_higher (entry.key);
+ return h != null && range.in_range (h.key) ? Entry.entry_for<K,V> (h) : null;
+ }
+
+ public override Map.Entry<K,V>/*?*/ floor (Map.Entry<K,V> entry) {
+ var res = range.compare_range (entry.key);
+ if (res > 0)
+ return last ();
+ weak Node<K,V>? l = map.find_floor (entry.key);
+ return l != null && range.in_range (l.key) ? Entry.entry_for<K,V> (l) : null;
+ }
+
+ public override Map.Entry<K,V>/*?*/ ceil (Map.Entry<K,V> entry) {
+ var res = range.compare_range (entry.key);
+ if (res < 0)
+ return first ();
+ weak Node<K,V>? h = map.find_ceil (entry.key);
+ return h != null && range.in_range (h.key) ? Entry.entry_for<K,V> (h) : null;
+ }
+ }
+
+ private class NodeIterator<K, V> : Object {
+ protected TreeMap<K,V> _map;
+
+ // concurrent modification protection
+ protected int stamp;
+
+ protected bool started = false;
+
+ internal weak Node<K, V>? current;
+ protected weak Node<K, V>? _next;
+ protected weak Node<K, V>? _prev;
+
+ public NodeIterator (TreeMap<K,V> map) {
+ _map = map;
+ this.stamp = _map.stamp;
+ }
+
+ public NodeIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+ _map = map;
+ stamp = _map.stamp;
+ this.current = current;
+ }
+
+ public bool next () {
+ assert (stamp == _map.stamp);
+ if (current != null) {
+ if (current.next != null) {
+ current = current.next;
+ return true;
+ } else {
+ return false;
+ }
+ } else if (_next == null && _prev == null) {
+ current = _map.first;
+ started = true;
+ return current != null;
+ } else {
+ current = _next;
+ if (current != null) {
+ _next = null;
+ _prev = null;
+ }
+ return current != null;
+ }
+ }
+
+ public bool has_next () {
+ assert (stamp == _map.stamp);
+ return (current == null && _next == null && _prev == null && _map.first != null) ||
+ (current == null && _next != null) ||
+ (current != null && current.next != null);
+ }
+
+ public bool first () {
+ assert (stamp == _map.stamp);
+ current = _map.first;
+ _next = null;
+ _prev = null;
+ return current != null; // on false it is null anyway
+ }
+
+ public bool previous () {
+ assert (stamp == _map.stamp);
+ if (current != null) {
+ if (current.prev != null) {
+ current = current.prev;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if (_prev != null) {
+ current = _prev;
+ _next = null;
+ _prev = null;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public bool has_previous () {
+ assert (stamp == _map.stamp);
+ return (current == null && _prev != null) ||
+ (current != null && current.prev != null);
+ }
+
+ public bool last () {
+ assert (stamp == _map.stamp);
+ current = _map.last;
+ _next = null;
+ _prev = null;
+ return current != null; // on false it is null anyway
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public void unset () {
+ assert (stamp == _map.stamp);
+ assert (current != null);
+ V value;
+ bool success = _map.remove_from_node (ref _map.root, current.key, out value, out
_prev, out _next);
+ assert (success);
+ if (_map.root != null)
+ _map.root.color = Node.Color.BLACK;
+ current = null;
+ stamp++;
+ _map.stamp++;
+ assert (stamp == _map.stamp);
+ }
+
+ public virtual bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public bool valid {
+ get {
+ return current != null;
+ }
+ }
+
+ internal unowned Node<K,V>? safe_next_get () {
+ return (current != null) ? current.next : _next;
+ }
+
+ internal unowned Node<K,V>? safe_previous_get () {
+ return (current != null) ? current.prev : _prev;
+ }
+ }
+
+ private class SubNodeIterator<K,V> : Object {
+ public SubNodeIterator (TreeMap<K,V> map, Range<K,V> range) {
+ _map = map;
+ this.range = range;
+ }
+
+ public SubNodeIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+ _map = map;
+ this.range = range;
+ this.iterator = new NodeIterator<K,V>.pointing (_map, node);
+ }
+
+ public bool next () {
+ if (iterator != null) {
+ weak Node<K,V>? node= iterator.safe_next_get ();
+ if (node != null && range.in_range (node.key)) {
+ assert (iterator.next ());
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return first ();
+ }
+ }
+
+ public bool has_next () {
+ if (iterator != null) {
+ weak Node<K,V>? node = iterator.safe_next_get ();
+ return node != null && range.in_range (node.key);
+ } else {
+ return range.first () != null;
+ }
+ }
+
+ public virtual bool first () {
+ weak Node<K,V>? node = range.first ();
+ if (node == null)
+ return false;
+ iterator = iterator_pointing_at (node);
+ return true;
+ }
+
+ public bool previous () {
+ if (iterator == null)
+ return false;
+ weak Node<K,V>? node;
+ if ((node = iterator.safe_previous_get ()) != null && range.in_range (node.key)) {
+ assert (iterator.previous ());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_previous () {
+ if (iterator == null)
+ return false;
+ weak Node<K,V>? node;
+ return (node = iterator.safe_previous_get ()) != null && range.in_range (node.key);
+ }
+
+ public virtual bool last () {
+ weak Node<K,V>? node = range.last ();
+ if (node == null)
+ return false;
+ iterator = iterator_pointing_at (node);
+ return true;
+ }
+
+ public void remove () {
+ assert (valid);
+ iterator.remove ();
+ }
+
+ public void unset () {
+ assert (valid);
+ iterator.unset ();
+ }
+
+ public virtual bool read_only {
+ get {
+ return true;
+ }
+ }
+
+ public bool valid {
+ get {
+ return iterator != null && iterator.valid;
+ }
+ }
+
+ protected virtual NodeIterator<K,V> iterator_pointing_at (Node<K,V> node) {
+ return new NodeIterator<K,V>.pointing (_map, node);
+ }
+
+ protected new TreeMap<K,V> _map;
+ protected Range<K,V> range;
+ protected NodeIterator<K,V>? iterator = null;
+ }
+
+ private class KeyIterator<K,V> : NodeIterator<K, V>, Traversable<K>, Vala.Iterator<K>,
BidirIterator<K> {
+ public KeyIterator (TreeMap<K,V> map) {
+ base (map);
+ }
+
+ public KeyIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+ base.pointing (map, current);
+ }
+
+ public new K get () {
+ assert (stamp == _map.stamp);
+ assert (current != null);
+ return current.key;
+ }
+
+ public bool foreach (ForallFunc<K> f) {
+ if (current != null) {
+ if (!f (current.key)) {
+ return false;
+ }
+ current = current.next;
+ } else if (_next == null) {
+ current = _map.first;
+ started = true;
+ } else {
+ current = _next;
+ if (current != null) {
+ _next = null;
+ _prev = null;
+ }
+ }
+ for (; current != null; current = current.next) {
+ if (!f (current.key)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private class SubKeyIterator<K,V> : SubNodeIterator<K,V>, Traversable<K>, Vala.Iterator<K>,
BidirIterator<K> {
+ public SubKeyIterator (TreeMap<K,V> map, Range<K,V> range) {
+ base (map, range);
+ }
+
+ public SubKeyIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+ base.pointing (map, range, node);
+ }
+
+ public new K get () {
+ assert (valid);
+ return iterator.current.key;
+ }
+
+ public bool foreach (ForallFunc<K> f) {
+ if (valid) {
+ if (!f (iterator.current.key)) {
+ return false;
+ }
+ }
+ while (iterator.next ()) {
+ if (!f (iterator.current.key)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private class ValueIterator<K,V> : NodeIterator<K,V>, Traversable<V>, Vala.Iterator<V>,
Vala.BidirIterator<V> {
+ public ValueIterator (TreeMap<K,V> map) {
+ base (map);
+ }
+
+ public ValueIterator.pointing (TreeMap<K,V> map, Node<K,V> current) {
+ base.pointing (map, current);
+ }
+
+ public new V get () {
+ assert (stamp == _map.stamp);
+ assert (valid);
+ return current.value;
+ }
+
+ public bool foreach (ForallFunc<V> f) {
+ if (current != null) {
+ if (!f (current.value)) {
+ return false;
+ }
+ current = current.next;
+ } else if (_next == null) {
+ current = _map.first;
+ started = true;
+ } else {
+ current = _next;
+ if (current != null) {
+ _next = null;
+ _prev = null;
+ }
+ }
+ for (; current != null; current = current.next) {
+ if (!f (current.value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private class SubValueIterator<K,V> : SubNodeIterator<K,V>, Traversable<V>, Vala.Iterator<V>,
BidirIterator<V> {
+ public SubValueIterator (TreeMap<K,V> map, Range<K,V> range) {
+ base (map, range);
+ }
+
+ public SubValueIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+ base.pointing (map, range, node);
+ }
+
+ public new V get () {
+ assert (valid);
+ return iterator.current.value;
+ }
+
+ public bool foreach (ForallFunc<V> f) {
+ if (valid) {
+ if (!f (iterator.current.key)) {
+ return false;
+ }
+ }
+ while (iterator.next ()) {
+ if (!f (iterator.current.key)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ 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>> {
+ public EntryIterator (TreeMap<K,V> map) {
+ base (map);
+ }
+
+ public EntryIterator.pointing (TreeMap<K,V> map, Node<K,V> node) {
+ base.pointing (map, node);
+ }
+
+ public new Map.Entry<K,V> get () {
+ assert (stamp == _map.stamp);
+ assert (valid);
+ return Entry.entry_for<K,V> (current);
+ }
+
+ public new void remove () {
+ unset ();
+ }
+
+ public bool foreach (ForallFunc<Map.Entry<K, V>> f) {
+ if (current != null) {
+ if (!f (Entry.entry_for<K,V> (current))) {
+ return false;
+ }
+ current = current.next;
+ } else if (_next == null) {
+ current = _map.first;
+ started = true;
+ } else {
+ current = _next;
+ if (current != null) {
+ _next = null;
+ _prev = null;
+ }
+ }
+ for (; current != null; current = current.next) {
+ if (!f (Entry.entry_for<K,V> (current))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ 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>> {
+ public SubEntryIterator (TreeMap<K,V> map, Range<K,V> range) {
+ base (map, range);
+ }
+
+ public SubEntryIterator.pointing (TreeMap<K,V> map, Range<K,V> range, Node<K,V> node) {
+ base.pointing (map, range, node);
+ }
+
+ public new Map.Entry<K,V> get () {
+ assert (iterator != null);
+ return Entry.entry_for<K,V> (iterator.current);
+ }
+
+ public new void remove () {
+ unset ();
+ }
+
+ public bool foreach (ForallFunc<Map.Entry<K, V>> f) {
+ if (valid) {
+ if (!f (Entry.entry_for<K,V> (iterator.current))) {
+ return false;
+ }
+ }
+ while (iterator.next ()) {
+ if (!f (Entry.entry_for<K,V> (iterator.current))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private class MapIterator<K,V> : NodeIterator<K,V>, Vala.MapIterator<K,V>, BidirMapIterator<K,V> {
+ public MapIterator (TreeMap<K,V> map) {
+ base (map);
+ }
+
+ public K get_key () {
+ assert (stamp == _map.stamp);
+ assert (valid);
+ return current.key;
+ }
+
+ public V get_value () {
+ assert (stamp == _map.stamp);
+ assert (valid);
+ return current.value;
+ }
+
+ public void set_value (V value) {
+ assert (stamp == _map.stamp);
+ assert (valid);
+ current.value = value;
+ }
+
+ public override bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool mutable {
+ get {
+ return true;
+ }
+ }
+ }
+
+ private class SubMapIterator<K,V> : SubNodeIterator<K,V>, Vala.MapIterator<K,V>,
BidirMapIterator<K,V> {
+ public SubMapIterator (TreeMap<K,V> map, Range<K,V> range) {
+ base (map, range);
+ }
+
+ public K get_key () {
+ assert (valid);
+ return iterator.current.key;
+ }
+
+ public V get_value () {
+ assert (valid);
+ return iterator.current.value;
+ }
+
+ public void set_value (V value) {
+ assert (valid);
+ iterator.current.value = value;
+ }
+
+ public override bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool mutable {
+ get {
+ return true;
+ }
+ }
+ }
+}
diff --git a/gee/treemultimap.vala b/gee/treemultimap.vala
new file mode 100644
index 0000000..452dd97
--- /dev/null
+++ b/gee/treemultimap.vala
@@ -0,0 +1,63 @@
+/* treemultimap.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Left-leaning red-black tree implementation of the {@link MultiMap}
+ * interface.
+ */
+public class Vala.TreeMultiMap<K,V> : AbstractMultiMap<K,V> {
+ public CompareDataFunc<K> key_compare_func {
+ get { return ((TreeMap<K, Set<V>>) _storage_map).key_compare_func; }
+ }
+
+ [CCode (notify = false)]
+ public CompareDataFunc<V> value_compare_func { private set; get; }
+
+ /**
+ * Constructs a new, empty tree multimap.
+ *
+ * If not provided, the functions parameters are requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param key_compare_func an optional key comparator function
+ * @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))));
+ if (value_compare_func == null) {
+ value_compare_func = Functions.get_compare_func_for (typeof (V));
+ }
+ this.value_compare_func = value_compare_func;
+ }
+
+ protected override Collection<V> create_value_storage () {
+ return new TreeSet<V> (_value_compare_func);
+ }
+
+ protected override MultiSet<K> create_multi_key_set () {
+ return new TreeMultiSet<K> (key_compare_func);
+ }
+
+ protected override EqualDataFunc<V> get_value_equal_func () {
+ return Functions.get_equal_func_for (typeof (V));
+ }
+}
diff --git a/gee/treemultiset.vala b/gee/treemultiset.vala
new file mode 100644
index 0000000..992d96d
--- /dev/null
+++ b/gee/treemultiset.vala
@@ -0,0 +1,43 @@
+/* treemultiset.vala
+ *
+ * Copyright (C) 2009 Didier Villevalois
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Didier 'Ptitjes Villevalois <ptitjes free fr>
+ */
+
+/**
+ * Left-leaning red-black tree implementation of the {@link MultiSet}
+ * interface.
+ */
+public class Vala.TreeMultiSet<G> : AbstractMultiSet<G> {
+ public CompareDataFunc<G> compare_func {
+ get { return ((TreeMap<G, int>) _storage_map).key_compare_func; }
+ }
+
+ /**
+ * Constructs a new, empty tree multi set.
+ *
+ * If not provided, the function parameter is requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param compare_func an optional element comparator function
+ */
+ public TreeMultiSet (owned CompareDataFunc<G>? compare_func = null) {
+ base (new TreeMap<G, int> (compare_func));
+ }
+}
diff --git a/gee/treeset.vala b/gee/treeset.vala
new file mode 100644
index 0000000..0ea02aa
--- /dev/null
+++ b/gee/treeset.vala
@@ -0,0 +1,1162 @@
+/* treeset.vala
+ *
+ * Copyright (C) 2009-2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+using GLib;
+
+/**
+ * Left-leaning red-black tree implementation of the {@link Set} interface.
+ *
+ * This implementation is especially well designed for large quantity of
+ * data. The (balanced) tree implementation insure that the set and get
+ * methods are in logarithmic complexity. For a linear implementation see
+ * {@link HashSet}.
+ *
+ * @see HashSet
+ */
+public class Vala.TreeSet<G> : AbstractBidirSortedSet<G> {
+ /**
+ * {@inheritDoc}
+ */
+ public override int size {
+ get {return _size;}
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool read_only {
+ get { return false; }
+ }
+
+ /**
+ * The elements' comparator function.
+ */
+ [CCode (notify = false)]
+ public CompareDataFunc<G> compare_func { private set; get; }
+
+ private int _size = 0;
+
+ /**
+ * Constructs a new, empty tree set sorted according to the specified
+ * comparator function.
+ *
+ * If not provided, the function parameter is requested to the
+ * {@link Functions} function factory methods.
+ *
+ * @param compare_func an optional element comparator function
+ */
+ public TreeSet (owned CompareDataFunc<G>? compare_func = null) {
+ if (compare_func == null) {
+ compare_func = Functions.get_compare_func_for (typeof (G));
+ }
+ this.compare_func = compare_func;
+ }
+
+ ~TreeSet () {
+ clear ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool contains (G item) {
+ weak Node<G>? cur = root;
+ while (cur != null) {
+ int res = compare_func (item, cur.key);
+ if (res == 0) {
+ return true;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return false;
+ }
+
+ private inline void rotate_right (ref Node<G> root) {
+ Node<G> pivot = (owned) root.left;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.left = (owned) pivot.right;
+ pivot.right = (owned) root;
+ root = (owned) pivot;
+#if DEBUG
+ stdout.printf (dump ("after rotate right on %s".printf ((string)root.right.key)));
+#endif
+ }
+
+ private inline void rotate_left (ref Node<G> root) {
+ Node<G> pivot = (owned) root.right;
+ pivot.color = root.color;
+ root.color = Node.Color.RED;
+ root.right = (owned) pivot.left;
+ pivot.left = (owned) root;
+ root = (owned) pivot;
+#if DEBUG
+ stdout.printf (dump ("after rotate left on %s".printf ((string)root.left.key)));
+#endif
+ }
+
+ private inline bool is_red (Node<G>? n) {
+ return n != null && n.color == Node.Color.RED;
+ }
+
+ private inline bool is_black (Node<G>? n) {
+ return n == null || n.color == Node.Color.BLACK;
+ }
+
+ private inline void fix_up (ref Node<G> node) {
+#if DEBUG
+ var n = (string)node.key;
+#endif
+ if (is_black (node.left) && is_red (node.right)) {
+ rotate_left (ref node);
+ }
+ if (is_red (node.left) && is_red (node.left.left)) {
+ rotate_right (ref node);
+ }
+ if (is_red (node.left) && is_red (node.right)) {
+ node.flip ();
+ }
+#if DEBUG
+ stdout.printf (dump ("after fix up on %s".printf (n)));
+#endif
+ }
+
+ private bool add_to_node (ref Node<G>? node, owned G item, Node<G>? prev, Node<G>? next) {
+#if DEBUG
+ if (node != null)
+ stdout.printf ("Adding %s to %s\n".printf ((string) item, (string) node.key));
+#endif
+ if (node == null) {
+ node = new Node<G> ((owned) item, prev, next);
+ if (prev == null) {
+ _first = node;
+ }
+ if (next == null) {
+ _last = node;
+ }
+ _size++;
+ return true;
+ }
+
+ int cmp = compare_func (item, node.key);
+ if (cmp == 0) {
+ fix_up (ref node);
+ return false;
+ } else if (cmp < 0) {
+ bool r = add_to_node (ref node.left, item, node.prev, node);
+ fix_up (ref node);
+ return r;
+ } else {
+ bool r = add_to_node (ref node.right, item, node, node.next);
+ fix_up (ref node);
+ return r;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * If the element already exists in the set it will not be added twice.
+ */
+ public override bool add (G item) {
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ bool r = add_to_node (ref root, item, null, null);
+ root.color = Node.Color.BLACK;
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ stamp++;
+ return r;
+ }
+
+ private inline void move_red_left (ref Node<G> root) {
+#if DEBUG
+ var n = (string)root.key;
+#endif
+ root.flip ();
+ if (is_red (root.right.left)) {
+ rotate_right (ref root.right);
+ rotate_left (ref root);
+ root.flip ();
+ }
+#if DEBUG
+ stdout.printf (dump ("after red left on %s".printf (n)));
+#endif
+ }
+
+ private inline void move_red_right (ref Node<G> root) {
+#if DEBUG
+ var n = (string)root.key;
+#endif
+ root.flip ();
+ if (is_red (root.left.left)) {
+ rotate_right (ref root);
+ root.flip ();
+ }
+#if DEBUG
+ stdout.printf (dump ("after red right on %s".printf (n)));
+#endif
+ }
+
+ private inline void fix_removal (ref Node<G> node, out G? key = null) {
+ Node<G> n = (owned)node;
+ key = (owned) n.key;
+ if (n.prev != null) {
+ n.prev.next = n.next;
+ } else {
+ _first = n.next;
+ }
+ if (n.next != null) {
+ n.next.prev = n.prev;
+ } else {
+ _last = n.prev;
+ }
+ node = null;
+ _size--;
+ }
+
+ private void remove_minimal (ref Node<G> node, out G key) {
+ if (node.left == null) {
+ fix_removal (ref node, out key);
+ return;
+ }
+
+ if (is_black (node.left) && is_black (node.left.left)) {
+ move_red_left (ref node);
+ }
+
+ remove_minimal (ref node.left, out key);
+
+ fix_up (ref node);
+ }
+
+ private bool remove_from_node (ref Node<G>? node, G item, out unowned Node<G>? prev = null, out
unowned Node<G>? next = null) {
+#if DEBUG
+ stdout.printf ("Removing %s from %s\n", (string)item, node != null ? (string)node.key : null);
+#endif
+ if (node == null) {
+ prev = null;
+ next = null;
+ return false;
+ } else if (compare_func (item, node.key) < 0) {
+ weak Node<G> left = node.left;
+ if (left == null) {
+ prev = null;
+ next = null;
+ return false;
+ }
+ if (is_black (left) && is_black (left.left)) {
+ move_red_left (ref node);
+ }
+ bool r = remove_from_node (ref node.left, item, out prev, out next);
+ fix_up (ref node);
+ return r;
+ } else {
+ if (is_red (node.left)) {
+ rotate_right (ref node);
+ }
+
+ weak Node<G>? r = node.right;
+ if (compare_func (item, node.key) == 0 && r == null) {
+ prev = node.prev;
+ next = node.next;
+ fix_removal (ref node, null);
+ return true;
+ }
+ if (is_black (r) && r != null && is_black (r.left)) {
+ move_red_right (ref node);
+ }
+ if (compare_func (item, node.key) == 0) {
+ prev = node.prev;
+ next = node;
+ remove_minimal (ref node.right, out node.key);
+ fix_up (ref node);
+ return true;
+ } else {
+ bool re = remove_from_node (ref node.right, item, out prev, out next);
+ fix_up (ref node);
+ return re;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool remove (G item) {
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ bool b = remove_from_node (ref root, item);
+ if (root != null) {
+ root.color = Node.Color.BLACK;
+ }
+#if CONSISTENCY_CHECKS
+ check ();
+#endif
+ stamp++;
+ return b;
+ }
+
+ private inline void clear_subtree (owned Node<G> node) {
+ node.key = null;
+ if (node.left != null)
+ clear_subtree ((owned) node.left);
+ if (node.right != null)
+ clear_subtree ((owned) node.right);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void clear () {
+ if (root != null) {
+ clear_subtree ((owned) root);
+ _first = _last = null;
+ }
+ _size = 0;
+ stamp++;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G> iterator () {
+ return new Iterator<G> (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override BidirIterator<G> bidir_iterator () {
+ return new Iterator<G> (this);
+ }
+
+ private inline G? lift_null_get (Node<G>? node) {
+ return node != null ? node.key : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G first () {
+ assert (_first != null);
+ return _first.key;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G last () {
+ assert (_last != null);
+ return _last.key;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedSet<G> head_set (G before) {
+ return new SubSet<G>.head (this, before);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedSet<G> tail_set (G after) {
+ return new SubSet<G>.tail (this, after);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override SortedSet<G> sub_set (G after, G before) {
+ return new SubSet<G> (this, after, before);
+ }
+
+ private inline unowned Node<G>? find_node (G item) {
+ weak Node<G>? cur = root;
+ while (cur != null) {
+ int res = compare_func (item, cur.key);
+ if (res == 0) {
+ return cur;
+ } else if (res < 0) {
+ cur = cur.left;
+ } else {
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override Vala.Iterator<G>? iterator_at (G item) {
+ weak Node<G>? node = find_node (item);
+ return node != null ? new Iterator<G>.pointing (this, node) : null;
+ }
+
+ private inline unowned Node<G>? find_nearest (G item) {
+ weak Node<G>? cur = root;
+ while (cur != null) {
+ int res = compare_func (item, cur.key);
+ if (res == 0) {
+ return cur;
+ } else if (res < 0) {
+ if (cur.left == null)
+ return cur;
+ cur = cur.left;
+ } else {
+ if (cur.right == null)
+ return cur;
+ cur = cur.right;
+ }
+ }
+ return null;
+ }
+
+ private inline unowned Node<G>? find_lower (G item) {
+ weak Node<G>? node = find_nearest (item);
+ if (node == null)
+ return null;
+ return compare_func (item, node.key) <= 0 ? node.prev : node;
+ }
+
+ private inline unowned Node<G>? find_higher (G item) {
+ weak Node<G>? node = find_nearest (item);
+ if (node == null)
+ return null;
+ return compare_func (item, node.key) >= 0 ? node.next : node;
+ }
+
+ private inline unowned Node<G>? find_floor (G item) {
+ weak Node<G>? node = find_nearest (item);
+ if (node == null)
+ return null;
+ return compare_func (item, node.key) < 0 ? node.prev : node;
+ }
+
+ private inline unowned Node<G>? find_ceil (G item) {
+ weak Node<G>? node = find_nearest (item);
+ if (node == null)
+ return null;
+ return compare_func (item, node.key) > 0 ? node.next : node;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? lower (G item) {
+ return lift_null_get (find_lower (item));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? higher (G item) {
+ return lift_null_get (find_higher (item));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? floor (G item) {
+ return lift_null_get (find_floor (item));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override G? ceil (G item) {
+ return lift_null_get (find_ceil (item));
+ }
+
+#if CONSISTENCY_CHECKS
+ public inline void check () {
+ check_subtree (root);
+ assert (root == null || root.color == Node.Color.BLACK);
+#if DEBUG
+ stdout.printf ("%s\n", dump ());
+#endif
+ }
+
+ private inline uint check_subtree (Node<G>? node) {
+ if (node == null)
+ return 0;
+ assert (! (is_black (node.left) && is_red (node.right))); // Check left-leaning
+ assert (! (is_red (node) && is_red (node.left))); // Check red property
+ uint l = check_subtree (node.left);
+ uint r = check_subtree (node.right);
+ assert (l == r);
+ return l + (node.color == Node.Color.BLACK ? 1 : 0);
+ }
+#endif
+#if DEBUG
+ public string dump (string? when = null) {
+ return "TreeSet dump%s:\n%s".printf (when == null ? "" : (" " + when), dump_node (root));
+ }
+
+ private inline string dump_node (Node<G>? node, uint depth = 0) {
+ if (node != null)
+ return dump_node (node.left, depth + 1) +
+ "%s%s%p(%s)\033[0m\n".printf (string.nfill (depth, ' '),
+ node.color == Node.Color.RED ? "\033[0;31m" : "",
+ node, (string)node.key) +
+ dump_node (node.right, depth + 1);
+ return "";
+ }
+#endif
+
+ [Compact]
+ private class Node<G> {
+ public enum Color {
+ RED,
+ BLACK;
+
+ public Color flip () {
+ if (this == RED) {
+ return BLACK;
+ } else {
+ return RED;
+ }
+ }
+ }
+
+ public Node (owned G node, Node<G>? prev, Node<G>? next) {
+ this.key = (owned) node;
+ this.color = Color.RED;
+ this.prev = prev;
+ this.next = next;
+ if (prev != null) {
+ prev.next = this;
+ }
+ if (next != null) {
+ next.prev = this;
+ }
+ }
+
+ public void flip () {
+ color = color.flip ();
+ if (left != null) {
+ left.color = left.color.flip ();
+ }
+ if (right != null) {
+ right.color = right.color.flip ();
+ }
+ }
+
+ public G key;
+ public Color color;
+ public Node<G>? left;
+ public Node<G>? right;
+ public weak Node<G>? prev;
+ public weak Node<G>? next;
+ }
+
+ private class Iterator<G> : Object, 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;
+ }
+
+ public Iterator.pointing (TreeSet<G> set, Node<G> current) {
+ this._set = set;
+ this._current = current;
+ this.stamp = set.stamp;
+ this.started = true;
+ }
+
+ public bool next () {
+ assert (stamp == _set.stamp);
+ if (_current != null) {
+ if (_current.next != null) {
+ _current = _current.next;
+ return true;
+ } else {
+ return false;
+ }
+ } else if (!started) {
+ _current = _set._first;
+ started = true;
+ return _current != null;
+ } else {
+ _current = _next;
+ if (_current != null) {
+ _next = null;
+ _prev = null;
+ }
+ return _current != null;
+ }
+ }
+
+ public bool has_next () {
+ assert (stamp == _set.stamp);
+ return (!started && _set._first != null) ||
+ (_current == null && _next != null) ||
+ (_current != null && _current.next != null);
+ }
+
+ public bool first () {
+ assert (stamp == _set.stamp);
+ _current = _set._first;
+ _next = null;
+ _prev = null;
+ started = true;
+ return _current != null; // on false it is null anyway
+ }
+
+ public bool previous () {
+ assert (stamp == _set.stamp);
+ if (_current != null) {
+ if (_current.prev != null) {
+ _current = _current.prev;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if (_prev != null) {
+ _current = _prev;
+ _next = null;
+ _prev = null;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public bool has_previous () {
+ assert (stamp == _set.stamp);
+ return (_current == null && _prev != null) ||
+ (_current != null && _current.prev != null);
+ }
+
+ public bool last () {
+ assert (stamp == _set.stamp);
+ _current = _set._last;
+ _next = null;
+ _prev = null;
+ started = true;
+ return _current != null; // on false it is null anyway
+ }
+
+ public new G get () {
+ assert (stamp == _set.stamp);
+ assert (_current != null);
+ return _current.key;
+ }
+
+ public void remove () {
+ assert (stamp == _set.stamp);
+ assert (_current != null);
+ bool success = _set.remove_from_node (ref _set.root, _current.key, out _prev, out
_next);
+ assert (success);
+ if (_set.root != null)
+ _set.root.color = Node.Color.BLACK;
+ _current = null;
+ assert (stamp++ == _set.stamp++);
+ }
+
+ internal bool safe_next_get (out G val) {
+ if (_current != null) {
+ val = _set.lift_null_get (_current.next);
+ return _current.next != null;
+ } else {
+ val = _set.lift_null_get (_next);
+ return _next != null;
+ }
+ }
+
+ internal bool safe_previous_get (out G val) {
+ if (_current != null) {
+ val = _set.lift_null_get (_current.prev);
+ return _current.prev != null;
+ } else {
+ val = _set.lift_null_get (_prev);
+ return _next != null;
+ }
+ }
+
+ public bool valid {
+ get {
+ assert (stamp == _set.stamp);
+ return _current != null;
+ }
+ }
+
+ public bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ assert (stamp == _set.stamp);
+ unowned Node<G>? current = _current, next;
+ if (current != null) {
+ if (!f (current.key)) {
+ return false;
+ }
+ next = current.next;
+ } else if (!started) {
+ next = _set._first;
+ if (next != null) {
+ started = true;
+ }
+ } else {
+ next = _next;
+ if (next != null) {
+ _next = null;
+ _prev = null;
+ }
+ }
+ while (next != null) {
+ if (!f (next.key)) {
+ _current = next;
+ return false;
+ }
+ current = next;
+ next = current.next;
+ }
+ _current = current;
+ return true;
+ }
+
+ private weak Node<G>? _current = null;
+ private weak Node<G>? _next = null;
+ private weak Node<G>? _prev = null;
+ private bool started = false;
+ }
+
+ private inline G min (G a, G b) {
+ return compare_func (a, b) <= 0 ? a : b;
+ }
+
+ private inline G max (G a, G b) {
+ return compare_func (a, b) > 0 ? a : b;
+ }
+
+ private class Range<G> {
+ public Range (TreeSet<G> set, G after, G before) {
+ this.set = set;
+ if (set.compare_func (after, before) < 0) {
+ this.after = after;
+ this.before = before;
+ type = RangeType.BOUNDED;
+ } else {
+ type = RangeType.EMPTY;
+ }
+ }
+
+ public Range.head (TreeSet<G> set, G before) {
+ this.set = set;
+ this.before = before;
+ type = RangeType.HEAD;
+ }
+
+ public Range.tail (TreeSet<G> set, G after) {
+ this.set = set;
+ this.after = after;
+ type = RangeType.TAIL;
+ }
+
+#if false
+ public Range.empty (TreeSet<G> set) {
+ this.set = set;
+ type = RangeType.EMPTY;
+ }
+#endif
+
+ public Range<G> cut_head (G after) {
+ switch (type) {
+ case RangeType.HEAD:
+ return new Range<G> (set, after, before);
+ case RangeType.TAIL:
+ return new Range<G>.tail (set, set.max (after, this.after));
+ case RangeType.EMPTY:
+ return this;
+ case RangeType.BOUNDED:
+ var _after = set.max (after, this.after);
+ return new Range<G> (set, _after, before);
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public Range<G> cut_tail (G before) {
+ switch (type) {
+ case RangeType.HEAD:
+ return new Range<G>.head (set, set.min (before, this.before));
+ case RangeType.TAIL:
+ return new Range<G> (set, after, before);
+ case RangeType.EMPTY:
+ return this;
+ case RangeType.BOUNDED:
+ var _before = set.min (before, this.before);
+ return new Range<G> (set, after, _before);
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public Range<G> cut (G after, G before) {
+ if (type == RangeType.EMPTY)
+ return this;
+ var _before = type != RangeType.TAIL ? set.min (before, this.before) : before;
+ var _after = type != RangeType.HEAD ? set.max (after, this.after) : after;
+ return new Range<G> (set, _after, _before);
+ }
+
+ public bool in_range (G item) {
+ return type == RangeType.EMPTY ? false : compare_range (item) == 0;
+ }
+
+ public int compare_range (G item) {
+ switch (type) {
+ case RangeType.HEAD:
+ return set.compare_func (item, before) < 0 ? 0 : 1;
+ case RangeType.TAIL:
+ return set.compare_func (item, after) >= 0 ? 0 : -1;
+ case RangeType.EMPTY:
+ return 0; // For simplicity - please make sure it does not break anything
+ case RangeType.BOUNDED:
+ return set.compare_func (item, after) >= 0 ?
+ (set.compare_func (item, before) < 0 ? 0 : 1) : -1;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public bool empty_subset () {
+ switch (type) {
+ case RangeType.HEAD:
+ return set._first == null || !in_range (set._first.key);
+ case RangeType.TAIL:
+ return set._last == null || !in_range (set._last.key);
+ case RangeType.EMPTY:
+ return true;
+ case RangeType.BOUNDED:
+ return first () == null;
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public unowned Node<G>? first () {
+ switch (type) {
+ case RangeType.EMPTY:
+ return null;
+ case RangeType.HEAD:
+ return set._first;
+ default:
+ return set.find_floor (after);
+ }
+ }
+
+ public unowned Node<G>? last () {
+ switch (type) {
+ case RangeType.EMPTY:
+ return null;
+ case RangeType.TAIL:
+ return set._last;
+ default:
+ return set.find_lower (before);
+ }
+ }
+
+ private new TreeSet<G> set;
+ private G after;
+ private G before;
+ private RangeType type;
+ }
+
+ private enum RangeType {
+ HEAD,
+ TAIL,
+ EMPTY,
+ BOUNDED
+ }
+
+ private class SubSet<G> : AbstractBidirSortedSet<G> {
+ public SubSet (TreeSet<G> set, G after, G before) {
+ this.set = set;
+ this.range = new Range<G> (set, after, before);
+ }
+
+ public SubSet.head (TreeSet<G> set, G before) {
+ this.set = set;
+ this.range = new Range<G>.head (set, before);
+ }
+
+ public SubSet.tail (TreeSet<G> set, G after) {
+ this.set = set;
+ this.range = new Range<G>.tail (set, after);
+ }
+
+ public SubSet.from_range (TreeSet<G> set, Range<G> range) {
+ this.set = set;
+ this.range = range;
+ }
+
+ public override int size {
+ get {
+ var i = 0;
+ Vala.Iterator<G> iterator = iterator ();
+ while (iterator.next ())
+ i++;
+ return i;
+ }
+ }
+
+ public override bool read_only {
+ get { return true; }
+ }
+
+ public bool is_empty {
+ get {
+ return range.empty_subset ();
+ }
+ }
+
+ public override bool contains (G item) {
+ return range.in_range (item) && set.contains (item);
+ }
+
+ public override bool add (G item) {
+ return range.in_range (item) && set.add (item);
+ }
+
+ public override bool remove (G item) {
+ return range.in_range (item) && set.remove (item);
+ }
+
+ public override void clear () {
+ var iter = iterator ();
+ while (iter.next ()) {
+ iter.remove ();
+ }
+ }
+
+ public override Vala.Iterator<G> iterator () {
+ return new SubIterator<G> (set, range);
+ }
+
+ public override BidirIterator<G> bidir_iterator () {
+ return new SubIterator<G> (set, range);
+ }
+
+ public override G first () {
+ weak Node<G>? _first = range.first ();
+ assert (_first != null);
+ return _first.key;
+ }
+
+ public override G last () {
+ weak Node<G>? _last = range.last ();
+ assert (_last != null);
+ return _last.key;
+ }
+
+ public override SortedSet<G> head_set (G before) {
+ return new SubSet<G>.from_range (set, range.cut_tail (before));
+ }
+
+ public override SortedSet<G> tail_set (G after) {
+ return new SubSet<G>.from_range (set, range.cut_head (after));
+ }
+
+ public override SortedSet<G> sub_set (G after, G before) {
+ return new SubSet<G>.from_range (set, range.cut (after, before));
+ }
+
+ public override Vala.Iterator<G>? iterator_at (G item) {
+ if (!range.in_range (item))
+ return null;
+ weak Node<G>? n = set.find_node (item);
+ if (n == null)
+ return null;
+ return new SubIterator<G>.pointing (set, range, n);
+ }
+
+ public override G? lower (G item) {
+ var res = range.compare_range (item);
+ if (res > 0)
+ return last ();
+ var l = set.lower (item);
+ return l != null && range.in_range (l) ? l : null;
+ }
+
+ public override G? higher (G item) {
+ var res = range.compare_range (item);
+ if (res < 0)
+ return first ();
+ var h = set.higher (item);
+ return h != null && range.in_range (h) ? h : null;
+ }
+
+ public override G? floor (G item) {
+ var res = range.compare_range (item);
+ if (res > 0)
+ return last ();
+ var l = set.floor (item);
+ return l != null && range.in_range (l) ? l : null;
+ }
+
+ public override G? ceil (G item) {
+ var res = range.compare_range (item);
+ if (res < 0)
+ return first ();
+ var h = set.ceil (item);
+ return h != null && range.in_range (h) ? h : null;
+ }
+
+ private new TreeSet<G> set;
+ private Range<G> range;
+ }
+
+ private class SubIterator<G> : Object, Traversable<G>, Vala.Iterator<G>, BidirIterator<G> {
+ public SubIterator (TreeSet<G> set, Range<G> range) {
+ this.set = set;
+ this.range = range;
+ }
+
+ public SubIterator.pointing (TreeSet<G> set, Range<G> range, Node<G> node) {
+ this.set = set;
+ this.range = range;
+ this.iterator = new Iterator<G>.pointing (set, node);
+ }
+
+ public bool next () {
+ if (iterator != null) {
+ G next;
+ if (iterator.safe_next_get (out next) && range.in_range (next)) {
+ assert (iterator.next ());
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return first ();
+ }
+ }
+
+ public bool has_next () {
+ if (iterator != null) {
+ G next;
+ return (iterator.safe_next_get (out next) && range.in_range (next));
+ } else {
+ return range.first () != null;
+ }
+ }
+
+ public bool first () {
+ weak Node<G>? node = range.first ();
+ if (node == null)
+ return false;
+ iterator = new Iterator<G>.pointing (set, node);
+ return true;
+ }
+
+ public bool previous () {
+ if (iterator == null)
+ return false;
+ G prev;
+ if (iterator.safe_previous_get (out prev) && range.in_range (prev)) {
+ assert (iterator.previous ());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_previous () {
+ if (iterator == null)
+ return false;
+ G prev;
+ return iterator.safe_previous_get (out prev) && range.in_range (prev);
+ }
+
+ public bool last () {
+ weak Node<G>? node = range.last ();
+ if (node == null)
+ return false;
+ iterator = new Iterator<G>.pointing (set, node);
+ return true;
+ }
+
+ public new G get () {
+ assert (iterator != null);
+ return iterator.get ();
+ }
+
+ public void remove () {
+ assert (iterator != null);
+ iterator.remove ();
+ }
+
+ public bool read_only {
+ get {
+ return false;
+ }
+ }
+
+ public bool valid {
+ get {
+ return iterator.valid;
+ }
+ }
+
+ public bool foreach(ForallFunc<G> f) {
+ if(valid) {
+ if (!f(get())) {
+ return false;
+ }
+ }
+ while(next()) {
+ if (!f(get())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private new TreeSet<G> set;
+ private Range<G> range;
+ private 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;
+}
diff --git a/gee/unfolditerator.vala b/gee/unfolditerator.vala
new file mode 100644
index 0000000..b513f05
--- /dev/null
+++ b/gee/unfolditerator.vala
@@ -0,0 +1,102 @@
+/* unfolditerator.vala
+ *
+ * Copyright (C) 2011 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2 gmail com>
+ */
+
+internal class Vala.UnfoldIterator<G> : Object, Traversable<G>, Iterator<G> {
+ public UnfoldIterator (owned UnfoldFunc<G> func, owned Lazy<G>? current = null) {
+ _current = (owned)current;
+ _func = (owned)func;
+ _end = false;
+ }
+
+ public bool next () {
+ if (has_next ()) {
+ if (_current != null)
+ _current.eval ();
+ _current = (owned)_next;
+ return true;
+ }
+ return false;
+ }
+
+ public bool has_next () {
+ if (_end)
+ return false;
+ if (_next != null)
+ return true;
+ _next = _func ();
+ if (_next == null)
+ _end = true;
+ return _next != null;
+ }
+
+ public new G 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; } }
+
+ public bool foreach (ForallFunc<G> f) {
+ if (_current != null) {
+ if (!f (_current.value)) {
+ return false;
+ }
+ }
+ if (_next != null) {
+ _current = (owned)_next;
+ if (!f (_current.value)) {
+ return false;
+ }
+ } else if (_end) {
+ return true;
+ }
+ if (_current == null) {
+ _current = _func ();
+ if (_current == null) {
+ _end = true;
+ return true;
+ } else {
+ if (!f (_current.value)) {
+ return false;
+ }
+ }
+ }
+ while ((_next = _func ()) != null) {
+ _current = (owned)_next;
+ if (!f (_current.value)) {
+ return false;
+ }
+ }
+ _end = true;
+ return true;
+ }
+
+ private UnfoldFunc<G> _func;
+ private Lazy<G>? _current;
+ private Lazy<G>? _next;
+ private bool _end;
+}
diff --git a/vala/valaattribute.vala b/vala/valaattribute.vala
index f1ef73f..889517c 100644
--- a/vala/valaattribute.vala
+++ b/vala/valaattribute.vala
@@ -34,7 +34,7 @@ public class Vala.Attribute : CodeNode {
/**
* Contains all specified attribute arguments.
*/
- public Vala.Map<string,string> args = new HashMap<string,string> (str_hash, str_equal);
+ public Map<string,string> args = new HashMap<string,string> ();
/**
* Creates a new attribute.
@@ -73,7 +73,7 @@ public class Vala.Attribute : CodeNode {
* @return true if the argument has been found, false otherwise
*/
public bool has_argument (string name) {
- return args.contains (name);
+ return args.has_key (name);
}
/**
diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala
index ddb9fdf..1f68a84 100644
--- a/vala/valacodecontext.vala
+++ b/vala/valacodecontext.vala
@@ -209,9 +209,9 @@ public class Vala.CodeContext {
private List<string> c_source_files = new ArrayList<string> ();
private Namespace _root = new Namespace (null);
- private List<string> packages = new ArrayList<string> (str_equal);
+ private List<string> packages = new ArrayList<string> ();
- private Set<string> defines = new HashSet<string> (str_hash, str_equal);
+ private Set<string> defines = new HashSet<string> ();
static StaticPrivate context_stack_key = StaticPrivate ();
diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala
index 5413ed4..319b761 100644
--- a/vala/valacodenode.vala
+++ b/vala/valacodenode.vala
@@ -192,7 +192,7 @@ public abstract class Vala.CodeNode {
public void remove_attribute_argument (string attribute, string argument) {
var a = get_attribute (attribute);
if (a != null) {
- a.args.remove (argument);
+ a.args.unset (argument);
if (a.args.size == 0) {
attributes.remove (a);
}
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 1d83a20..14e385a 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1647,7 +1647,7 @@ public class Vala.CodeWriter : CodeVisitor {
iter = iter.next ();
var keys = new GLib.Sequence<string> ();
- foreach (var key in attr.args.get_keys ()) {
+ foreach (var key in attr.args.keys) {
if (key == "cheader_filename" && sym is Namespace) {
continue;
}
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index 9f94a42..9652c15 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -367,7 +367,7 @@ public class Vala.FlowAnalyzer : CodeVisitor {
phi.set (block, 0);
}
- foreach (Variable variable in assign.get_keys ()) {
+ foreach (Variable variable in assign.keys) {
counter++;
foreach (BasicBlock block in assign.get (variable)) {
work_list.add (block);
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 742868c..047c505 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -118,7 +118,7 @@ public class Vala.GirParser : CodeVisitor {
add_child (child);
}
// merge arguments and take precedence
- foreach (var key in metadata.args.get_keys ()) {
+ foreach (var key in metadata.args.keys) {
args[key] = metadata.args[key];
}
}
@@ -140,7 +140,7 @@ public class Vala.GirParser : CodeVisitor {
public SourceReference source_reference;
public bool used = false;
- public Vala.Map<ArgumentType,Argument> args = new HashMap<ArgumentType,Argument> ();
+ public Map<ArgumentType,Argument> args = new HashMap<ArgumentType,Argument> ();
public ArrayList<Metadata> children = new ArrayList<Metadata> ();
public Metadata (string pattern, string? selector = null, SourceReference? source_reference =
null) {
@@ -181,7 +181,7 @@ public class Vala.GirParser : CodeVisitor {
}
public bool has_argument (ArgumentType key) {
- return args.contains (key);
+ return args.has_key (key);
}
public Expression? get_expression (ArgumentType arg) {
@@ -508,7 +508,7 @@ public class Vala.GirParser : CodeVisitor {
public Metadata metadata = Metadata.empty;
public SourceReference source_reference = null;
public ArrayList<Node> members = new ArrayList<Node> (); // guarantees fields order
- public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>>
(str_hash, str_equal);
+ public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>> ();
public GirComment comment;
public Symbol symbol;
@@ -551,7 +551,7 @@ public class Vala.GirParser : CodeVisitor {
var nodes = scope[node.name];
nodes.remove (node);
if (nodes.size == 0) {
- scope.remove (node.name);
+ scope.unset (node.name);
}
members.remove (node);
node.parent = null;
@@ -651,7 +651,7 @@ public class Vala.GirParser : CodeVisitor {
}
}
- if (prefix == null && girdata != null && (girdata.contains ("c:symbol-prefix") ||
girdata.contains("c:symbol-prefixes"))) {
+ if (prefix == null && girdata != null && (girdata.has_key ("c:symbol-prefix") ||
girdata.has_key ("c:symbol-prefixes"))) {
/* Use the prefix in the gir. We look up prefixes up to the root.
If some node does not have girdata, we ignore it as i might be
a namespace created due to reparenting. */
@@ -1270,8 +1270,8 @@ public class Vala.GirParser : CodeVisitor {
Node current;
Node old_current;
- Set<string> provided_namespaces = new HashSet<string> (str_hash, str_equal);
- HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol>
(unresolved_symbol_hash, unresolved_symbol_equal);
+ Set<string> provided_namespaces = new HashSet<string> ();
+ HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol> ((a)
=> {return unresolved_symbol_hash(a);}, (a, b) => {return unresolved_symbol_equal(a, b);});
ArrayList<UnresolvedSymbol> unresolved_gir_symbols = new ArrayList<UnresolvedSymbol> ();
ArrayList<DataType> unresolved_type_arguments = new ArrayList<DataType> ();
@@ -3380,7 +3380,7 @@ public class Vala.GirParser : CodeVisitor {
return;
}
- foreach (var arg_type in metadata.args.get_keys ()) {
+ foreach (var arg_type in metadata.args.keys) {
var arg = metadata.args[arg_type];
if (!arg.used) {
// if metadata is used and argument is not, then it's a unexpected argument
diff --git a/vala/valamarkupreader.vala b/vala/valamarkupreader.vala
index 556853d..60423f2 100644
--- a/vala/valamarkupreader.vala
+++ b/vala/valamarkupreader.vala
@@ -41,7 +41,7 @@ public class Vala.MarkupReader : Object {
int line;
int column;
- Map<string,string> attributes = new HashMap<string,string> (str_hash, str_equal);
+ Map<string,string> attributes = new HashMap<string,string> ();
bool empty_element;
public MarkupReader (string filename) {
@@ -71,8 +71,8 @@ public class Vala.MarkupReader : Object {
* @return map of current attributes
*/
public Map<string,string> get_attributes () {
- var result = new HashMap<string,string> (str_hash, str_equal);
- foreach (var key in attributes.get_keys ()) {
+ var result = new HashMap<string,string> ();
+ foreach (var key in attributes.keys) {
result.set (key, attributes.get (key));
}
return result;
diff --git a/vala/valascope.vala b/vala/valascope.vala
index a2a946b..d77ed9c 100644
--- a/vala/valascope.vala
+++ b/vala/valascope.vala
@@ -58,7 +58,7 @@ public class Vala.Scope {
public void add (string? name, Symbol sym) {
if (name != null) {
if (symbol_table == null) {
- symbol_table = new HashMap<string,Symbol> (str_hash, str_equal);
+ symbol_table = new HashMap<string,Symbol> ();
} else if (lookup (name) != null) {
owner.error = true;
if (owner.name == null && owner.parent_symbol == null) {
@@ -82,7 +82,7 @@ public class Vala.Scope {
}
public void remove (string name) {
- symbol_table.remove (name);
+ symbol_table.unset (name);
}
/**
diff --git a/vala/valaswitchstatement.vala b/vala/valaswitchstatement.vala
index c583f8d..9c382be 100644
--- a/vala/valaswitchstatement.vala
+++ b/vala/valaswitchstatement.vala
@@ -118,7 +118,7 @@ public class Vala.SwitchStatement : CodeNode, Statement {
expression.target_type = expression.value_type.copy ();
expression.target_type.nullable = false;
- var labelset = new HashSet<string> (str_hash, str_equal);
+ var labelset = new HashSet<string> ();
foreach (SwitchSection section in sections) {
section.check (context);
diff --git a/vala/valausedattr.vala b/vala/valausedattr.vala
index 14cdd97..0df1c1a 100644
--- a/vala/valausedattr.vala
+++ b/vala/valausedattr.vala
@@ -27,7 +27,7 @@ using GLib;
* Code visitor to warn about unused attributes
*/
public class Vala.UsedAttr : CodeVisitor {
- public Vala.Map<string,Vala.Set<string>> marked = new HashMap<string,Vala.Set<string>> (str_hash,
str_equal);
+ public Vala.Map<string,Vala.Set<string>> marked = new HashMap<string,Vala.Set<string>> ();
const string[] valac_default_attrs = {
"CCode", "type_signature", "default_value", "set_value_function", "type_id", "cprefix",
"cheader_filename",
@@ -101,7 +101,7 @@ public class Vala.UsedAttr : CodeVisitor {
public void mark (string attribute, string? argument) {
var set = marked.get (attribute);
if (set == null) {
- set = new HashSet<string> (str_hash, str_equal);
+ set = new HashSet<string> ();
marked.set (attribute, set);
}
@@ -127,7 +127,7 @@ public class Vala.UsedAttr : CodeVisitor {
if (set == null) {
Report.warning (attr.source_reference, "attribute `%s' never
used".printf (attr.name));
} else {
- foreach (var arg in attr.args.get_keys()) {
+ foreach (var arg in attr.args.keys) {
if (!set.contains (arg)) {
Report.warning (attr.source_reference, "argument `%s'
never used".printf (arg));
}
diff --git a/vapigen/valagidlparser.vala b/vapigen/valagidlparser.vala
index 731ea26..b879edd 100644
--- a/vapigen/valagidlparser.vala
+++ b/vapigen/valagidlparser.vala
@@ -51,7 +51,7 @@ public class Vala.GIdlParser : CodeVisitor {
* @param context a code context
*/
public void parse (CodeContext context) {
- cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
+ cname_type_map = new HashMap<string,TypeSymbol> ();
this.context = context;
context.accept (this);
@@ -88,7 +88,7 @@ public class Vala.GIdlParser : CodeVisitor {
}
private void visit_type (TypeSymbol t) {
- if (!cname_type_map.contains (get_cname (t))) {
+ if (!cname_type_map.has_key (get_cname (t))) {
cname_type_map[get_cname (t)] = t;
}
}
@@ -104,8 +104,8 @@ public class Vala.GIdlParser : CodeVisitor {
current_source_file = source_file;
- codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
- codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash,
(EqualFunc<PatternSpec>) PatternSpec.equal);
+ codenode_attributes_map = new HashMap<string,string> ();
+ codenode_attributes_patterns = new HashMap<PatternSpec*,string> ();
if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
try {
@@ -1586,9 +1586,9 @@ public class Vala.GIdlParser : CodeVisitor {
current_data_type = cl;
- current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
- var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
- var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
+ current_type_symbol_set = new HashSet<string> ();
+ var current_type_func_map = new HashMap<string,weak IdlNodeFunction> ();
+ var current_type_vfunc_map = new HashMap<string,string> ();
foreach (weak IdlNode member in node.members) {
if (member.type == IdlNodeTypeId.FUNCTION) {
@@ -1602,7 +1602,7 @@ public class Vala.GIdlParser : CodeVisitor {
foreach (weak IdlNode member in node.members) {
if (member.type == IdlNodeTypeId.FUNCTION) {
// Ignore if vfunc (handled below)
- if (!current_type_vfunc_map.contains (member.name)) {
+ if (!current_type_vfunc_map.has_key (member.name)) {
var m = parse_function ((IdlNodeFunction) member);
if (m != null) {
cl.add_method (m);
@@ -1708,9 +1708,9 @@ public class Vala.GIdlParser : CodeVisitor {
current_data_type = iface;
- current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
- var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
- var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
+ current_type_symbol_set = new HashSet<string> ();
+ var current_type_func_map = new HashMap<string,weak IdlNodeFunction> ();
+ var current_type_vfunc_map = new HashMap<string,string> ();
foreach (weak IdlNode member in node.members) {
if (member.type == IdlNodeTypeId.FUNCTION) {
@@ -1724,7 +1724,7 @@ public class Vala.GIdlParser : CodeVisitor {
foreach (weak IdlNode member in node.members) {
if (member.type == IdlNodeTypeId.FUNCTION) {
// Ignore if vfunc (handled below)
- if (!current_type_vfunc_map.contains (member.name)) {
+ if (!current_type_vfunc_map.has_key (member.name)) {
var m = parse_function ((IdlNodeFunction) member, true);
if (m != null) {
iface.add_method (m);
@@ -2987,7 +2987,7 @@ public class Vala.GIdlParser : CodeVisitor {
var dot_required = (-1 != codenode.index_of_char ('.'));
var colon_required = (-1 != codenode.index_of_char (':'));
- var pattern_specs = codenode_attributes_patterns.get_keys ();
+ var pattern_specs = codenode_attributes_patterns.keys;
foreach (PatternSpec* pattern in pattern_specs) {
var pspec = codenode_attributes_patterns[pattern];
diff --git a/vapigen/valavapicheck.vala b/vapigen/valavapicheck.vala
index 509645f..52c57ad 100644
--- a/vapigen/valavapicheck.vala
+++ b/vapigen/valavapicheck.vala
@@ -38,7 +38,7 @@ class Vala.VAPICheck : Object {
private void parse_gidl () {
_scope = new ArrayList<string> ();
- _symbols = new HashSet<string> (str_hash, str_equal);
+ _symbols = new HashSet<string> ();
try {
foreach (weak IdlModule module in Idl.parse_file (gidl.filename)) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]