[vala/wip/gee: 95/98] Update internal gee from libgee 0.8.8+d531caa9



commit 3da14aa5bce72c6d5f7eedea5eed00df3716b8f1
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 4be48a0..fe823dc 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) {
@@ -342,7 +342,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");
@@ -362,7 +362,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");
@@ -713,7 +713,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;
                
@@ -724,7 +724,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");
@@ -2295,7 +2295,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++;
                        }
@@ -4602,7 +4602,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) {
@@ -4614,7 +4614,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_"));
                        }
@@ -4748,7 +4748,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;
                                                }
@@ -4765,7 +4765,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 7150c4e..f1120ae 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 c047a52..101eb95 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -83,7 +83,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) {
@@ -125,7 +125,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_"));
                        }
@@ -665,7 +665,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;
                                        }
@@ -682,7 +682,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 f28fe86..8e3a9b0 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -211,8 +211,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;
 
@@ -236,7 +236,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);
@@ -248,7 +248,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);
@@ -454,7 +454,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);
 
@@ -854,8 +854,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);
                }
@@ -1047,7 +1047,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;
                                }
@@ -1245,8 +1245,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);
 
@@ -1266,7 +1266,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 a077b4a..73e86ea 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -169,7 +169,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"));
@@ -361,8 +361,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;
@@ -378,8 +378,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;
@@ -404,7 +404,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);
@@ -417,7 +417,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);
@@ -463,12 +463,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 {
@@ -494,8 +494,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);
 
@@ -516,8 +516,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);
 
@@ -546,7 +546,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*"));
 
@@ -739,7 +739,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);
 
@@ -749,7 +749,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 a0151f6..c757c3e 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);
 
@@ -891,7 +891,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);
 
@@ -915,7 +915,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"));
@@ -940,7 +940,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 c252b2d..5e656f0 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 (unowned 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 (unowned 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);
@@ -1365,7 +1365,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 8945d07..813d79f 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -385,7 +385,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> ();
 
                if (m.printf_format) {
                        vdeclarator.modifiers |= CCodeModifiers.PRINTF;
@@ -1510,7 +1510,7 @@ public class Vala.GTypeModule : GErrorModule {
                string cast_args = "%s *".printf (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, null, 
null, direction);
 
@@ -1519,7 +1519,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 4484c05..0b6a0aa 100644
--- a/vala/valacodecontext.vala
+++ b/vala/valacodecontext.vala
@@ -204,9 +204,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 8c0e688..3872b9b 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1644,7 +1644,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 5ed041a..d905554 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;
@@ -553,7 +553,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;
@@ -653,7 +653,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. */
@@ -1277,8 +1277,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> ();
 
@@ -3450,7 +3450,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 63b7104..7c177f5 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",
@@ -103,7 +103,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);
                }
 
@@ -129,7 +129,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 86239f4..965a303 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);
@@ -2985,7 +2985,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]