diff --git a/CHANGES b/CHANGES
index be6bf8855c8d6c5b2fd967e85d5244c893a4eb66..bb0375adfc61852119803d07ee4782c35016cf05 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,12 @@ Changes since Pike 7.8 (scratch area for future release notes)
 
 o decode_value now throws the error object Error.DecodeError. Useful
   to catch format errors in the decode string.
+o Added ADT.CritBit module
+  Mapping-like key-sorted data structures for string, int and float-keys
+  (ADT.CritBit.Tree, ADT.CritBit.IntTree, ADT.CritBit.FloatTree). Implemented
+  in C.
+
+  
 
 
 Changes since Pike 7.8.352 (third 7.8 release):
diff --git a/lib/modules/ADT.pmod/CritBit.pmod b/lib/modules/ADT.pmod/CritBit.pmod
new file mode 100644
index 0000000000000000000000000000000000000000..d965b30b2d0c389d9c28bab63cc5670bcd96970d
--- /dev/null
+++ b/lib/modules/ADT.pmod/CritBit.pmod
@@ -0,0 +1,323 @@
+#pike __REAL_VERSION__
+
+//! @ignore
+#if !constant (ADT._CritBit)
+constant this_program_does_not_exist = 1;
+#else
+
+inherit ADT._CritBit;
+//! @endignore
+
+//! Creates a CritBit tree for keys of type @expr{type@}. If no argument is given,
+//! an instance of @[ADT.CritBit.StringTree] is returned. Supported types are @expr{"string"@},
+//! @expr{"int"@}, @expr{"float"@}, @expr{"ipv4"@} and @expr{Calendar.TimeRange@}.
+object Tree(void|string|program|mapping type) {
+    switch (type) {
+    case Calendar.TimeRange:
+	return DateTree();
+    case "int": 
+	return IntTree();
+    case "ipv4":
+	return IPv4Tree();
+    case "string":
+    case 0:
+	return StringTree();
+    case "float":
+	return FloatTree();
+    default:
+	if (mappingp(type))
+	    return StringTree(type);
+
+	error("No tree available for type %O\n", type);
+    }
+}
+
+string iptosortable(string ip) {
+    int a, b, c, d, e, i;
+    string s;
+
+    switch (sscanf(ip, "%d.%d.%d.%d/%d", a, b, c, d, e)) {
+    case 4:
+	e = 32;
+    case 5:
+	e = max(0, min(32, e));
+	s = sprintf("%c%c%c%c", a, b, c, d);
+	sscanf(s, "%4c", i);
+	i &= ~(0xffffffff >> e);
+	s = sprintf("%4c%c%c%c%c%c", i, a, b, c, d, e);
+
+	break;
+    default:
+	error("NON-ip %O got passed to iptoint.\n", ip);
+    }
+
+
+    return s;
+}
+
+//! Sorts an ARRAY OF IPv4-Adresses (and optional netmasks) given in dotted
+//! decimal representation with the /23 netmask notation.
+//!
+//! @example
+//! 	@code
+//!> array(string) a = ({ "127.0.0.121",
+//!>	 "127.0.0.0/16",
+//!>	 "127.0.0.1/8",
+//!>	 "127.0.0.0/8",
+//!>	 "128.0.0.0/1",
+//!>	 "192.168.21.3",
+//!>	 "8.8.8.8" });
+//!> write("%O\n", CritBit.sort_ipv4(a));
+//!({ /* 7 elements */
+//!	"8.8.8.8",
+//!	"127.0.0.0/8",
+//! 	"127.0.0.0/16",
+//! 	"127.0.0.1/8",
+//! 	"127.0.0.121",
+//! 	"128.0.0.0/1",
+//! 	"192.168.21.3"
+//!})
+//! 	@endcode
+//! @
+array(string) sort_ipv4(array(string) a, array ... data) {
+    array b = map(a, iptosortable);
+
+    sort(b, a, @data);
+
+    return a;
+}
+
+string get_ipv4(int ip, void|int prefix) {
+    string ret;
+
+    if (undefinedp(prefix)) prefix = 32;
+    prefix = min(32, max(prefix, 0));
+    ip &= ~(0xffffffff >> prefix);
+    ret = sprintf("%d.%d.%d.%d",
+		  (ip & 0xff000000) >> 24,
+		  (ip & 0xff0000) >> 16,
+		  (ip & 0xff00) >> 8,
+		  (ip & 0xff));
+    if (prefix != 32) {
+	ret += sprintf("/%d", prefix);
+    }
+
+    return ret;
+}
+
+//! This module offers CritBit tree implementations for different
+//! key types.
+//! @note
+//! 	These CritBit trees support prefixes as proper keys. Hence
+//! 	they should really be called Tries.
+
+//!
+class DateTree {
+    inherit IntTree;
+    mapping(int:Calendar.TimeRange) backwards = ([]);
+
+    //! Encodes a Calendar.TimeRange object into unix timestanp.
+    int encode_key(object|int o) {
+	if (objectp(o) && Program.inherits(object_program(o),
+					   Calendar.TimeRange)) {
+	    int t = o->unix_time();
+	    backwards[t] = o;
+	    return t;
+	}
+	return o;
+    }
+
+    //! Decodes an integer back to a @[Calendar.TimeRange] object. Keeps
+    //! a mapping of all keys stored in the tree to transform back.
+    int|object decode_key(int i) {
+	return has_index(backwards, i)
+	    ? backwards[i]
+	    : Calendar.Second("unix", i);
+    }
+
+    //! Copy callback to also clone backwards
+    this_program copy() {
+	this_program t = ::copy();
+	t->backwards = copy_value(backwards);
+	return t;
+    }
+
+    mixed _m_delete(mixed o) {
+	mixed v = ::_m_delete(o);
+	m_delete(backwards, decode_key(o));
+	return v;
+    }
+}
+
+//! Data structure representing a set of disjunct @[ADT.Interval] objects. Can be thought
+//! of as an interval with gaps.
+class RangeSet {
+    object tree;
+
+    //! Create a RangeSet from a given tree program.
+    void create(function|object|program tree) {
+	this_program::tree = objectp(tree) ? tree : tree();
+    }
+
+    mixed `[](mixed key) {
+	if (objectp(key) && Program.inherits(object_program(key), ADT.Interval))
+	    return contains(key);
+	mixed next = tree[key];
+	if (!undefinedp(next)) return next->contains(key);
+	next = tree->next(key);
+
+	if (next) {
+	    object interval = tree[next];
+	    return interval->contains(key);
+	}
+
+	return UNDEFINED;
+    }
+
+    int(0..1) overlaps(mixed o) {
+	if (objectp(o)) {
+	    if (Program.inherits(object_program(o), ADT.Interval)) {
+		ADT.Interval r = tree[o->b->x];
+		if (!r) {
+		    mixed next = tree->next(o->b->x);
+		    if (next) r = tree[next];
+		}
+		if (!r) return 0;
+		return r->overlaps(o);
+	    } else if (Program.inherits(object_program(o), this_program)) {
+		// TODO
+	    }
+	}
+	return 0;
+    }
+
+    int(0..1) contains(mixed o) {
+	if (objectp(o)) {
+	    if (Program.inherits(object_program(o), ADT.Interval)) {
+		ADT.Interval r = tree[o->b->x];
+		if (!r) {
+		    mixed next = tree->next(o->b->x);
+		    if (next) r = tree[next];
+		}
+		if (!r) return 0;
+		return r->contains(o);
+	    } else if (Program.inherits(object_program(o), this_program)) {
+		// TODO
+	    }
+	}
+	return 0;
+    }
+
+    mixed `[]=(mixed i, mixed v) {
+	if (objectp(i) && Program.inherits(object_program(i), ADT.Interval)) {
+	    merge(i);
+	    return v;
+	} else error("Bad key type: %t. Expects an instance of type ADT.Interval.\n", i);
+    }
+
+    array(mixed) _indices() {
+	return values(tree);
+    }
+
+    void merge(mixed i) {
+	werror("merge(%O)\n", i);
+	array a = values(tree[i->a->x..i->b->x]);
+	mixed next = tree->next(i->b->x);
+
+	if (!undefinedp(next)) a += ({ tree[next] });
+
+	werror("all: %O\n", a);
+	a = filter(a, i->touches);
+	werror("filtered: %O\n", a);
+
+	if (sizeof(a)) {
+	    i |= a[0];
+	    if (sizeof(a) > 1)
+		i |= a[sizeof(a)-1];
+	    foreach (a;; mixed b) m_delete(tree, b->b->x);
+	}
+
+	tree[i->b->x] = i;
+    }
+
+    this_program `|(object o) {
+	this_program new = this_program(tree->copy());
+	if (Program.inherits(object_program(o), this_program)) {
+	    foreach (indices(o); ; mixed i) new->merge(i);
+	} else {
+	    new->merge(o);
+	}
+	return new;
+    }
+
+    string _sprintf(int type) {
+	if (type == 'O') {
+	    array a = indices(this);
+	    return sprintf("{%s}", map(a, Function.curry(sprintf)("%O"))*", ");
+	}
+
+	return 0;
+    }
+}
+
+class MultiRangeSet {
+    // mapping from left/right boundary to interval
+    object tree;
+    int|float max_len;
+
+    void create(function|program|object tree) {
+	this_program::tree = objectp(tree) ? tree : tree();
+    }
+
+    mixed `[](mixed key) {
+
+	if (!objectp(key) || !Program.inherits(object_program(key),
+					       ADT.Interval)) {
+	    key = ADT.Interval(key, key);
+	}
+
+	return contains(key);
+    }
+
+    mixed contains(mixed key) {
+	array ret = ({});
+
+	foreach (tree->Iterator(tree, -1, key->b->x);
+		 ; object i) {
+	    if (key->a - i[0]->a > max_len) break;
+	    ret += filter(i, i->contains(key));
+	}
+
+	return ret;
+    }
+
+    mixed overlaps(mixed key) {
+	array ret = ({});
+
+	foreach (tree->Iterator(tree, -1, key->b->x);
+		 ; array(object) i) {
+	    if (key->a - i[0]->a > max_len) {
+		werror("stopping early.\n");
+		break;
+	    }
+
+	    ret += filter(i, i->overlaps(key));
+	}
+
+	return ret;
+    }
+
+    mixed `[]=(mixed i, mixed v) {
+	max_len = max(sizeof(i), max_len);
+	if (v) i->val = v;
+	if (tree[i->a->x])
+	    tree[i->a->x] += ({ i });
+	else tree[i->a->x] = ({ i });
+    }
+
+    string _sprintf(int type) {
+	return sprintf("%O", values(tree));
+    }
+}
+
+#endif	// constant (@module@)
diff --git a/lib/modules/ADT.pmod/Interval.pike b/lib/modules/ADT.pmod/Interval.pike
new file mode 100644
index 0000000000000000000000000000000000000000..55f18192c848497b3b012869654d3e30b413520f
--- /dev/null
+++ b/lib/modules/ADT.pmod/Interval.pike
@@ -0,0 +1,252 @@
+class Boundary(mixed x) {
+    int (0..1) `<(object b) {
+	if (!objectp(b) || !Program.inherits(object_program(b), Boundary)) {
+	    return x < b;
+	}
+	return x < b->x;
+    }
+
+    int (0..1) `>(object b) {
+	if (!objectp(b) || !Program.inherits(object_program(b), Boundary)) {
+	    return x > b;
+	}
+	return x > b->x;
+    }
+
+    string _sprintf(int type) {
+	return sprintf("%O", x);
+    }
+
+    int unix_time() {
+	return x->unix_time();
+    }
+
+    int `ux() {
+	return unix_time();
+    }
+
+    mixed `-(object b) {
+	if (intp(x) || floatp(x)) {
+	    return x - b->x;
+	} else if (stringp(x)) {
+	    error("lets see how we do this ;) \n");
+	}
+    }
+}
+
+class Open {
+    inherit Boundary;
+
+    int (0..1) `==(object b) {
+	return objectp(b) && Program.inherits(object_program(b), Open)
+		&& b->x == x;
+    }
+
+    int (0..1) `<(mixed b) {
+	if (!objectp(b) || !Program.inherits(object_program(b), Boundary)) {
+	    return x <= b;
+	}
+	return ::`<(b);
+    }
+
+    int (0..1) `>(mixed b) {
+	if (!objectp(b) || !Program.inherits(object_program(b), Boundary)) {
+	    return x >= b;
+	}
+	return ::`>(b);
+    }
+
+    int(0..1) overlaps(object b) {
+	if (this > b) return 1;
+	return 0;
+    }
+
+    int(0..1) touches(object b) {
+	werror("%O touches %-O == %d\n", this, b, overlaps(b) || (this->x == b->x && Program.inherits(object_program(b), Closed)));
+	return overlaps(b) || (this->x == b->x && Program.inherits(object_program(b), Closed));
+    }
+
+    string _sprintf(int type, mapping info) {
+	if (info->flag_left) {
+	    return sprintf("(%O", x);
+	}
+	return sprintf("%O)", x);
+    }
+
+    Boundary `~() {
+	return Closed(x);
+    }
+}
+
+class Closed {
+    inherit Boundary;
+
+    int (0..1) `==(object b) {
+	return objectp(b) && Program.inherits(object_program(b), Closed)
+		&& b->x == x;
+    }
+
+    int(0..1) overlaps(object b) {
+	if (this > b || (Program.inherits(object_program(b), Closed) && b == this)) return 1;
+	return 0;
+    }
+
+    int(0..1) touches(object b) {
+	werror("%O touches %-O == %d\n", this, b, this > b);
+	if (this < b) return 0;
+	return 1;
+    }
+    string _sprintf(int type, mapping info) {
+	if (info->flag_left) {
+	    return sprintf("[%O", x);
+	}
+	return sprintf("%O]", x);
+    }
+
+    Boundary `~() {
+	return Open(x);
+    }
+}
+
+Boundary min(Boundary a, Boundary b) {
+    if (a < b) return a;
+    if (b < a) return b;
+
+    if (Program.inherits(object_program(a), Closed)) return a;
+    if (Program.inherits(object_program(b), Closed)) return b;
+    return a;
+}
+
+Boundary max(Boundary a, Boundary b) {
+    if (a == min(a,b)) return b;
+    else return a;
+}
+
+Boundary a, b;
+
+mixed `->start() { return a->x; }
+mixed `->stop() { return b->x; }
+
+mixed `->start=(mixed v) {
+    a = Closed(v);
+    return v;
+}
+mixed `->stop=(mixed v) {
+    b = Closed(v);
+    return v;
+}
+
+string _sprintf(int type) {
+    return sprintf("%-O..%O", a, b);
+}
+
+void create(mixed a, mixed b) {
+    if (!objectp(a) || !Program.inherits(object_program(a), Boundary)) {
+	a = Closed(a);
+    }
+    if (!objectp(b) || !Program.inherits(object_program(b), Boundary)) {
+	b = Closed(b);
+    }
+    if (!b->overlaps(a)) error("Trying to create empty interval.\n");
+    this_program::a = a;
+    this_program::b = b;
+}
+
+int(0..1) `==(mixed i) {
+    return objectp(i) && Program.inherits(object_program(i), this_program) && a == i->a && b == i->b;
+}
+
+//  0	(..)..[..]
+//  1	(..[..)..]
+//  2	[..(..)..]
+//  3	[..(..]..)
+//  4	[..]..(..)
+
+this_program `&(this_program i) {
+    Boundary l, r;
+
+    l = max(a, i->a);
+    r = min(b, i->b);
+
+    if (r->overlaps(l))
+	return clone(l, r);
+    return 0;
+}
+
+int(0..1) overlaps(this_program i) {
+    Boundary l, r;
+
+    l = max(a, i->a);
+    r = min(b, i->b);
+
+    return r->overlaps(l);
+}
+
+int(0..1) touches(this_program i) {
+    Boundary l, r;
+
+    l = max(a, i->a);
+    r = min(b, i->b);
+
+    return r->touches(l);
+}
+
+this_program clone(mixed ... args) {
+    return this_program(@args);
+}
+
+
+this_program `|(this_program i) {
+    if ((this & i)
+    || (b->x <= i->a->x && b->touches(i->a))
+    || (i->b->x <= a->x && i->b->touches(a))) {
+	return clone(min(a, i->a), max(b, i->b));
+    }
+
+    error("%O and %O need to touch.\n", this, i);
+}
+
+this_program `+(this_program i) {
+    return this | i;
+}
+
+this_program `-(this_program interval) {
+    this_program i = interval & this;
+    if (i) {
+	if (i == this) return 0;
+
+	if (a == i->a) {
+	    return clone(~i->b, b);
+	} else if (b == i->b) {
+	    return clone(a, ~i->a);
+	}
+
+	error("%O and %O may not be contained.\n", this, i);
+    }
+    return this;
+}
+
+int|float _sizeof() {
+    return b-a;
+}
+
+int(0..1) contains(mixed x) {
+    if (!objectp(x) || !Program.inherits(object_program(x), ADT.Interval)) {
+	x = this_program(Closed(x), Closed(x));
+    }
+    return !!(this&x);
+}
+
+/* TODO:
+ * implement or remap the api offered by the timerange thing.
+ */
+
+mixed beginning() { return start; }
+mixed end() { return stop; }
+
+mixed cast(string type) {
+    switch (type) {
+    case "array":
+	return ({ start, stop });
+    }
+}
diff --git a/src/post_modules/CritBit/.gitignore b/src/post_modules/CritBit/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3c4d1ab9e1acf44dedc5048cf4ae9163cc50b51d
--- /dev/null
+++ b/src/post_modules/CritBit/.gitignore
@@ -0,0 +1,14 @@
+/Makefile
+/config.log
+/config.status
+/configure
+/critbit_config.h
+/critbit_config.h.in
+/dependencies
+/floattree.c
+/inttree.c
+/make_variables
+/propagated_variables
+/stamp-h
+/stamp-h.in
+/tree.c
diff --git a/src/post_modules/CritBit/Makefile.in b/src/post_modules/CritBit/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..4fa1ec08958ed373753361028c8210ef9d6fac3e
--- /dev/null
+++ b/src/post_modules/CritBit/Makefile.in
@@ -0,0 +1,24 @@
+# $Id$
+
+@make_variables@
+
+VPATH=@srcdir@
+MODNAME=CritBit
+MODDIR=ADT.pmod/
+MODULE_PMOD_IN=
+MODULE_WRAPPER_PREFIX=_
+AUTODOC_SRC_IN=@srcdir@/stringtree.c @srcdir@/floattree.c @srcdir@/inttree.c
+OBJS=glue.o inttree.o stringtree.o floattree.o
+CONFIG_HEADERS=@CONFIG_HEADERS@
+
+@dynamic_module_makefile@
+
+strintree.o: $(SRCDIR)/stringtree.c
+
+inttree.o: $(SRCDIR)/inttree.c
+
+floattree.o: $(SRCDIR)/floattree.c
+
+glue.o: $(SRCDIR)/glue.c
+
+@dependencies@
diff --git a/src/post_modules/CritBit/acconfig.h b/src/post_modules/CritBit/acconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..9442d19df263740408ed629377bbde6efc028bf3
--- /dev/null
+++ b/src/post_modules/CritBit/acconfig.h
@@ -0,0 +1,14 @@
+/*
+|| This file is part of Pike. For copyright information see COPYRIGHT.
+|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
+|| for more information.
+|| $Id$
+*/
+
+#ifndef CRITBIT_CONFIG_H
+#define CRITBIT_CONFIG_H
+
+@TOP@
+@BOTTOM@
+
+#endif
diff --git a/src/post_modules/CritBit/bitvector.h b/src/post_modules/CritBit/bitvector.h
new file mode 100644
index 0000000000000000000000000000000000000000..d98046d9c4799d6e75d2b5838e1d3aa97d170a8d
--- /dev/null
+++ b/src/post_modules/CritBit/bitvector.h
@@ -0,0 +1,323 @@
+#ifndef BITVECTOR_H
+#define BITVECTOR_H
+
+#include "critbit_config.h"
+#define MOD_PRIME
+
+#include <stdint.h>
+
+#if defined(HAS__BITSCANFORWARD) || defined(HAS__BITSCANFORWARD64) || defined(HAS__BITSCANREVERSE) || defined(HAS__BITSCANREVERSE64)
+# include <intrin.h>
+#endif
+
+#if defined(HAS__BYTESWAP_ULONG) || defined(HAS__BYTESWAP_UINT64)
+#include <stdlib.h>
+#endif
+
+#define MASK(type, bits)	(~((~((type)0)) >> (bits)))
+#define BITMASK(type, n)	((type)1 << (type)(sizeof(type)*8 - 1 - (n)))
+#define BITN(type, p, n)	(!!((p) & BITMASK(type, n)))
+
+#define TBITMASK(type, n)	((type)1 << (type)((n)))
+#define TBITN(type, p, n)	(!!((p) & TBITMASK(type, n)))
+
+#if 1
+# define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
+static const char logTable[256] = {
+    0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+    LT(5), LT(6), LT(6), LT(7), LT(7), LT(7), LT(7),
+    LT(8), LT(8), LT(8), LT(8), LT(8), LT(8), LT(8), LT(8)
+};
+# undef LT
+#endif
+
+static const unsigned char LMultiplyDeBruijnBitPosition32[33] =
+{
+    32,
+    31, 22, 30, 21, 18, 10, 29,  2,
+    20, 17, 15, 13,  9,  6, 28,  1,
+    23, 19, 11,  3, 16, 14,  7, 24,
+    12,  4,  8, 25,  5, 26, 27,  0,
+/*
+     0,  1, 28,  2, 29, 14, 24,  3,
+    30, 22, 20, 15, 25, 17,  4,  8,
+    31, 27, 13, 23, 21, 19, 16,  7,
+    26, 12, 18,  6, 11,  5, 10,  9
+*/
+};
+static const unsigned char TMultiplyDeBruijnBitPosition32[33] =
+{
+    32,
+    31, 30,  3, 29,  2, 17,  7, 28,
+     1,  9, 11, 16,  6, 14, 27, 23,
+     0,  4, 18,  8, 10, 12, 15, 24,
+     5, 19, 13, 25, 20, 26, 21, 22
+};
+static const unsigned char LMultiplyDeBruijnBitPosition64[65] = {
+    64,
+};
+static const unsigned char TMultiplyDeBruijnBitPosition64[65] = {
+    64,
+     0, 63,  5, 62,  4, 16, 10, 61,
+     3, 24, 15, 36,  9, 30, 21, 60,
+     2, 12, 26, 23, 14, 45, 35, 43,
+     8, 33, 29, 52, 20, 49, 41, 59,
+     1,  6, 17, 11, 25, 37, 31, 22,
+    13, 27, 46, 44, 34, 53, 50, 42,
+     7, 18, 38, 32, 28, 47, 54, 51,
+    19, 39, 48, 55, 40, 56, 57, 58
+};
+/* maps 2^n - 1 -> n
+ * returns 32 is none is set.
+ */
+static inline uint32_t leading_bit_pos32(uint32_t v) {
+    return LMultiplyDeBruijnBitPosition32[!!v + (((uint32_t)((v) * 0x07C4ACDDU)) >> 27)];
+}
+static inline uint32_t trailing_bit_pos32(uint32_t v) {
+    return TMultiplyDeBruijnBitPosition32[!!v + (((uint32_t)((v) * 0x077CB531U)) >> 27)];
+}
+static inline uint64_t leading_bit_pos64(uint64_t v) {
+    /*
+     * v * M == (2*v - 1) * N  + N = v * (2*N)
+     * N = M/2;
+     */
+    const uint64_t N = 0x3F6EAF2CD271461UL;
+
+    return LMultiplyDeBruijnBitPosition64[!!v + (((uint64_t)((v) * N + N)) >> 58)];
+}
+static inline uint64_t trailing_bit_pos64(uint64_t v) {
+    return TMultiplyDeBruijnBitPosition64[!!v + (((uint64_t)((v) * 0x07EDD5E59A4E28C2UL)) >> 58)];
+}
+
+static inline uint32_t round_up32_(uint32_t v) {
+    v |= v >> 1; /* first round down to one less than a power of 2 */
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    return v;
+}
+
+static inline uint32_t round_up32(uint32_t v) {
+    v = round_up32_(v);
+    v++;
+    return v;
+}
+
+static inline uint32_t round_down32(uint32_t v) {
+    v--;
+    return round_up32(v);
+}
+
+static inline uint64_t round_up64_(uint64_t v) {
+    v |= v >> 1; /* first round down to one less than a power of 2 */
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v |= v >> 32;
+    return v;
+}
+
+static inline uint64_t round_up64(uint64_t v) {
+    v = round_up64_(v);
+    v++;
+    return v;
+}
+
+static inline uint64_t round_down64(uint64_t v) {
+    v--;
+    return round_up64(v);
+}
+
+#ifdef HAS___BUILTIN_CLZ
+# define clz32(i) ((uint32_t)(!(i) ? 32 : __builtin_clz((uint32_t)i)))
+#elif defined(HAS__BIT_SCAN_REVERSE)
+# define clz32(i) ((uint32_t)(!(i) ? 32 : _bit_scan_reverse((int)i)))
+#elif defined(HAS___CNTLZ4)
+# define clz32(i) ((uint32_t)__cntlz4(i))
+#elif defined(HAS__BITSCANREVERSE)
+static inline uint32_t clz32(const uint32_t i) {
+    static unsigned long index;
+    if (_BitScanReverse(&index, (unsigned long)i))
+	return (uint32_t)index;
+    return 32;
+}
+#else
+static inline uint32_t clz32(const uint32_t y) {
+#ifdef MOD_PRIME
+    register uint32_t t;
+
+    if ((t = y >> 24)) {
+	return 8 - logTable[t];
+    } else if ((t = y >> 16)) {
+	return 16 - logTable[t];
+    } else if ((t = y >> 8)) {
+	return 24 - logTable[t];
+    } else {
+	return 32 - logTable[y];
+    }
+#else
+    return leading_bit_pos32(round_up32_(y));
+#endif
+}
+#endif
+
+#define clz16(i) ((uint32_t)(!(i) ? 16 : clz32((uint32_t)i)-16))
+#define clz8(i) ((char)(!(i) ? 8 : clz32((uint32_t)i)-24))
+
+#ifdef HAS___BUILTIN_CTZ
+# define ctz32(i) ((uint32_t)(!(i) ? 32 : __builtin_ctz((uint32_t)i)))
+#elif defined(HAS__BIT_SCAN_FORWARD)
+# define ctz32(i) ((uint32_t)(!(i) ? 32 : _bit_scan_forward((int)i)))
+#elif defined(HAS___CNTTZ4)
+# define ctz32(i) ((uint32_t)__cnttz4(i))
+#elif defined(HAS__BITSCANFORWARD)
+static inline uint32_t ctz32(const uint32_t i) {
+    static unsigned long index;
+    if (_BitScanForward(&index, (unsigned long)i))
+	return (uint32_t)index;
+    return 32;
+}
+#else
+static inline uint32_t ctz32(const uint32_t i) {
+#ifdef MOD_PRIME
+    /* this table maps (2^n % 37) to n */
+    static const char ctz32Table[37] = {
+	32, 0, 1, 26, 2, 23, 27, -1, 3, 16, 24, 30, 28, 11, -1, 13, 4, 7, 17,
+	-1, 25, 22, 31, 15, 29, 10, 12, 6, -1, 21, 14, 9, 5, 20, 8, 19, 18
+    };
+    return (uint32_t)ctz32Table[((uint32_t)((int)i & -(int)i))%37];
+#else
+    return trailing_bit_pos32((uint32_t)((int)i & -(int)i));
+#endif
+}
+#endif
+
+#define ctz16(i) ((uint32_t)(!(i) ? 16 : ctz32((uint32_t)i)-16))
+#define ctz8(i) ((char)(!(i) ? 8 : ctz32((uint32_t)i)-24))
+
+#if SIZEOF_LONG == 8 || SIZEOF_LONG_LONG == 8
+
+# if SIZEOF_LONG == 8 && defined(HAS___BUILTIN_CLZL)
+#  define clz64(x)	((uint32_t)(!(x) ? 64\
+			       : __builtin_clzl((unsigned long)(x))))
+# elif SIZEOF_LONG_LONG == 8 && defined(HAS___BUILTIN_CLZLL)
+#  define clz64(x)	((uint32_t)(!(x) ? 64\
+			       : __builtin_clzll((unsigned long long)(x))))
+# elif defined(HAS___CNTLZ8)
+#  define clz64(x)	((uint32_t)__cntlz8(x))
+# elif defined(HAS__BITSCANREVERSE64)
+static inline uint32_t clz64(const uint64_t i) {
+    static unsigned long index;
+    if (_BitScanReverse64(&index, (__int64)i))
+	return (uint32_t)index;
+    return 64;
+}
+# else
+static inline uint32_t clz64(const uint64_t y) {
+#ifdef MOD_PRIME
+    register uint64_t t;
+
+    if ((t = y >> 56)) {
+        return 8 - logTable[t];
+    } else if ((t = y >> 48)) {
+        return 16 - logTable[t];
+    } else if ((t = y >> 40)) {
+        return 24 - logTable[t];
+    } else if ((t = y >> 32)) {
+        return 32 - logTable[t];
+    } else if ((t = y >> 24)) {
+        return 40 - logTable[t];
+    } else if ((t = y >> 16)) {
+        return 48 - logTable[t];
+    } else if ((t = y >> 8)) {
+        return 56 - logTable[t];
+    } else {
+        return 64 - logTable[y];
+    }
+#else
+    /* This code comes from http://graphics.stanford.edu/~seander/bithacks.html */
+    return leading_bit_pos64(round_up64(y));
+# endif
+}
+# endif
+
+# if SIZEOF_LONG == 8 && defined(HAS___BUILTIN_CTZL)
+#  define ctz64(x)	((uint32_t)(!(x) ? 64\
+			       : __builtin_ctzl((unsigned long)(x))))
+/* #  warning __builtin_ctzl used */
+# elif SIZEOF_LONG_LONG == 8 && defined(HAS___BUILTIN_CTZLL)
+#  define ctz64(x)	((uint32_t)(!(x) ? 64\
+			       : __builtin_ctzll((unsigned long long)(x))))
+/* #  warning __builtin_ctzll used */
+# elif defined(HAS___CNTTZ8)
+#  define ctz64(x)	((uint32_t)__cnttz8(x))
+/* #  warning __cnttz8 used */
+# elif defined(HAS__BITSCANFORWARD64)
+static inline uint32_t ctz64(const uint64_t i) {
+    static unsigned long index;
+    if (_BitScanForward64(&index, (__int64)i))
+	return (uint32_t)index;
+    return 64;
+}
+# else
+static inline uint32_t ctz64(const uint64_t i) {
+#ifdef MOD_PRIME
+    /* this table maps (2^n % 67) to n */
+    static const char ctz64Table[67] = {
+	64, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, 63, 13,
+	10, 17, 62, 60, 28, 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, 63, 38, 14,
+	22, 11, 58, 18, 53, 63, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, 52,
+	8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33
+    };
+    return (uint32_t)ctz64Table[((uint64_t)((int64_t)i & -(int64_t)i))%67];
+#else
+    register uint64_t v = (uint64_t)((int64_t)i & -(int64_t)i);
+    return trailing_bit_pos64(v);
+#endif
+}
+# endif
+
+#endif /* SIZEOF_LONG == 8 || SIZEOF_LONG_LONG == 8 */
+
+#define hton8(x)	(x)
+
+#if !(defined(PIKE_BYTEORDER))
+# error "Byte order could not be decided."
+#else
+# if PIKE_BYTEORDER == 1234
+/* # warning "little endian" */
+#  define LBITMASK(type, n)	((type)1 << (type)(n))
+#  define LBITN(type, p, n)	(!!((p) & LBITMASK(type, n)))
+#  ifdef HAS___BUILTIN_BSWAP32
+#   define hton32(x)	__builtin_bswap32(x)
+#  elif defined(HAS__BSWAP)
+#   define hton32(x)	_bswap(x)
+#  elif defined(HAS__BYTESWAP_ULONG)
+#   define hton32(x)	_byteswap_ulong((unsigned long)x)
+#  else
+#   define hton32(x)	((((x) & 0xff000000) >> 24) | (((x) & 0x000000ff) << 24) \
+			 | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8))
+#  endif
+#  ifdef HAS___BUILTIN_BSWAP64
+#   define hton64(x)	__builtin_bswap64(x)
+#  elif defined(HAS__BSWAP64)
+#   define hton64(x)	_bswap64(x)
+#  elif defined(HAS__BYTESWAP_UINT64)
+#   define hton64(x)	_byteswap_uint64((unsigned __int64)x)
+#  else
+#   define hton64(x)	((int64_t)hton32((int)((x) >> 32))\
+	      | (((int64_t)hton32((int)((x) & 0x00000000ffffffff))) << 32))
+#  endif
+# else /* PIKE_BYTEORDER = 1234 */
+/* # warning "big endian" */
+#  define hton64(x)	(x)
+#  define hton32(x)	(x)
+#  define LBITMASK(type, n)	((type)1 << (type)((sizeof(type)	\
+				    - ((type)(n)<<8) - 1)*8 + (type)(n)&7))
+#  define LBITN(type, p, n)	(!!((p) & LBITMASK(type, n)))
+# endif /* PIKE_BYTEORDER == 1234 */
+#endif
+
+#endif /* BITVECTOR_H */
diff --git a/src/post_modules/CritBit/configure.in b/src/post_modules/CritBit/configure.in
new file mode 100644
index 0000000000000000000000000000000000000000..ee27852f26903245c611c799fcdad7c40448a9f9
--- /dev/null
+++ b/src/post_modules/CritBit/configure.in
@@ -0,0 +1,61 @@
+# $Id$
+AC_INIT(glue.c)
+AC_MODULE_INIT()
+AC_CONFIG_HEADER(critbit_config.h)
+define(TEST_BUILTIN, [
+    AC_MSG_CHECKING(for $1)
+    AC_TRY_RUN([
+$3
+unsigned long lint;
+int main(int argc, char **argv) {
+	static volatile int foo = 0;
+	foo = (int)$1($2);
+	return 0;
+}
+	],
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(translit([HAS_$1], [a-z], [A-Z]), 1, [Whether $1 is available])
+    ,
+    AC_MSG_RESULT(no)
+    )
+])
+# GCC builtins
+TEST_BUILTIN(__builtin_clz, 23)
+TEST_BUILTIN(__builtin_clzl, 23)
+TEST_BUILTIN(__builtin_clzll, 23)
+TEST_BUILTIN(__builtin_ctz, 23)
+TEST_BUILTIN(__builtin_ctzl, 23)
+TEST_BUILTIN(__builtin_ctzll, 23)
+TEST_BUILTIN(__builtin_bswap32, 23)
+TEST_BUILTIN(__builtin_bswap64, 23)
+TEST_BUILTIN(__builtin_expect, [argc,0])
+# ICC builtins
+TEST_BUILTIN(_bswap, 23)
+TEST_BUILTIN(_bswap64, 23)
+TEST_BUILTIN(_bit_scan_reverse, 23)
+TEST_BUILTIN(_bit_scan_forward, 23)
+# Visual Studio builtins
+TEST_BUILTIN(_BitScanForward, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanForward64, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanReverse, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanReverse64, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_byteswap_ulong, 23, [
+    #include <stdlib.h>
+])
+TEST_BUILTIN(_byteswap_uint64, 23, [
+    #include <stdlib.h>
+])
+# IBM C builtins
+TEST_BUILTIN(__cntlz4, 23)
+TEST_BUILTIN(__cntlz8, 23)
+TEST_BUILTIN(__cnttz4, 23)
+TEST_BUILTIN(__cnttz8, 23)
+AC_OUTPUT(Makefile,echo FOO >stamp-h)
diff --git a/src/post_modules/CritBit/critbit/critbit.h b/src/post_modules/CritBit/critbit/critbit.h
new file mode 100644
index 0000000000000000000000000000000000000000..28a38e454b6329f85fd3ba9c2e67ec12f99b958b
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/critbit.h
@@ -0,0 +1,23 @@
+#ifndef CB_CRITBIT_H
+#define CB_CRITBIT_H
+#define CONCAT2_(a, b)		a ## ## b
+#define CONCAT2(a, b)		CONCAT2_(a, b)
+#define CONCAT3(a, b, c)	CONCAT2(a, CONCAT2(b, c))
+#define CONCAT4(a, b, c, d)	CONCAT2(a, CONCAT3(b, c, d))
+#define CONCAT5(a, b, c, d, e)	CONCAT2(a, CONCAT4(b, c, d, e))
+
+#ifndef CB_NAMESPACE
+# warn NAMESPACE NOT USED
+#define CB_NAME(name)	CONCAT2(cb_, name)
+#define CB_TYPE(name)	CONCAT3(cb_, name, _t)
+#else
+#define CB_NAME(name)	CONCAT4(cb_, CB_NAMESPACE, _, name)
+#define CB_TYPE(name)	CONCAT5(cb_, CB_NAMESPACE, _, name, _t)
+#endif
+
+typedef struct cb_size {
+    size_t bits;
+    size_t chars;
+} cb_size;
+
+#endif
diff --git a/src/post_modules/CritBit/critbit/float2svalue.h b/src/post_modules/CritBit/critbit/float2svalue.h
new file mode 100644
index 0000000000000000000000000000000000000000..27c30812cf3b48f4e935389133bbfc183b39b394
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/float2svalue.h
@@ -0,0 +1,26 @@
+#ifdef CB_NAMESPACE
+# undef CB_NAMESPACE
+#endif
+#define CB_NAMESPACE	float2svalue
+
+#ifndef CB_INLINE
+# define CB_INLINE
+#else
+# undef CB_INLINE
+# define CB_INLINE inline
+#endif
+
+#ifndef CB_STATIC
+# define CB_STATIC
+#else
+# undef CB_STATIC
+# define CB_STATIC static
+#endif
+
+#ifndef CB_FLOAT2SVALUE_H
+# define CB_FLOAT2SVALUE_H
+# include "critbit.h"
+# include "key_float.h"
+# include "value_svalue.h"
+# include "tree_low.h"
+#endif
diff --git a/src/post_modules/CritBit/critbit/int2svalue.h b/src/post_modules/CritBit/critbit/int2svalue.h
new file mode 100644
index 0000000000000000000000000000000000000000..be46504cfb242e04f9108af1789d6ca4f21874ef
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/int2svalue.h
@@ -0,0 +1,26 @@
+#ifdef CB_NAMESPACE
+# undef CB_NAMESPACE
+#endif
+#define CB_NAMESPACE	int2svalue
+
+#ifndef CB_INLINE
+# define CB_INLINE
+#else
+# undef CB_INLINE
+# define CB_INLINE inline
+#endif
+
+#ifndef CB_STATIC
+# define CB_STATIC
+#else
+# undef CB_STATIC
+# define CB_STATIC static
+#endif
+
+#ifndef CB_INT2SVALUE_H
+# define CB_INT2SVALUE_H
+# include "critbit.h"
+# include "key_int.h"
+# include "value_svalue.h"
+# include "tree_low.h"
+#endif
diff --git a/src/post_modules/CritBit/critbit/key_float.h b/src/post_modules/CritBit/critbit/key_float.h
new file mode 100644
index 0000000000000000000000000000000000000000..26514d196bf665ec3537f860c63552e9f7c32f8a
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/key_float.h
@@ -0,0 +1,108 @@
+#ifndef CB_FLOAT_H
+#define CB_FLOAT_H
+#include <stdint.h>
+#include <math.h>
+#include "bitvector.h"
+
+#if SIZEOF_FLOAT_TYPE == 8
+typedef uint64_t CB_NAME(string);
+typedef uint64_t CB_NAME(char);
+#else
+typedef uint32_t CB_NAME(string);
+typedef uint32_t CB_NAME(char);
+#endif
+
+
+#ifdef cb_char
+# undef cb_char
+#endif
+#define cb_char CB_NAME(char)
+
+#ifdef cb_string
+# undef cb_string
+#endif
+#define cb_string CB_NAME(string)
+
+#ifdef CB_SOURCE
+#if SIZEOF_FLOAT_TYPE == 4
+# define gclz(x) clz32(x)
+#else
+# define gclz(x) clz64(x)
+#endif
+#define bitsof(x)	(sizeof(x)*8)
+#define int2float(x)	(*(FLOAT_TYPE*)&(x))
+#define float2int(x)	(*(cb_char*)&(x))
+
+typedef union {
+    FLOAT_TYPE f;
+    cb_char i;
+} cb_float;
+
+
+static inline cb_string cb_encode_float(const cb_float f) {
+    cb_char str = f.i;
+
+    if (str & MASK(cb_char, 1)) {
+	str = ~str;
+    } else {
+	str |= MASK(cb_char, 1);
+    }
+
+    return str;
+}
+
+static inline FLOAT_TYPE cb_decode_float(cb_char s) {
+    cb_float u;
+    if (s & MASK(cb_char, 1)) {
+	s = (s ^ MASK(cb_char, 1));
+    } else {
+	s = (~s);
+    }
+    u.i = s;
+
+    return u.f;
+}
+
+#define CB_ADD_KEY_REF(x)	do { } while(0)
+#define CB_FREE_KEY(x)		do { } while(0)
+#define CB_SET_KEY(node, x)	do { (node)->key = (x); } while (0)
+
+#define CB_KEY_EQ(k1, k2)			\
+	( (k1).str == (k2).str ||		\
+	  (CB_S_EQ((k1).len, (k2).len) &&	\
+	   (k1).len.bits &&			\
+	   !(((k1).str ^ (k2).str) & MASK(cb_char, (k1).len.bits))))
+#define CB_KEY_LT(k1, k2)			\
+	( (k1).str < (k2).str ||		\
+	  (((k1).str == (k2).str) && CB_LT((k1).len, (k2).len)) )
+
+#define CB_GET_CHAR(str, n)	(str)
+#define CB_WIDTH(s)	(bitsof(cb_string)) /* width in bits */
+#define CB_LENGTH(str)	1
+#define CB_SIZE(key)	((key)->len)
+#define CB_GET_BIT(str, size)			\
+	(BITN(cb_char, CB_GET_CHAR((str), (size).chars), (size).bits))
+#define CB_COUNT_PREFIX(s1, s2, n)		\
+	((size_t)gclz(CB_GET_CHAR((s1), (n)) ^ CB_GET_CHAR((s2), (n))))
+
+static inline cb_size cb_prefix_count_float(const cb_string s1,
+					    const cb_string s2,
+					    const cb_size len,
+					    const cb_size start) {
+    cb_size ret;
+
+    if (s1 == s2) return len;
+
+    ret.chars = 0;
+    ret.bits = (size_t)gclz(s1 ^ s2);
+
+    if (!len.chars) ret.bits = MINIMUM(len.bits, ret.bits);
+
+    return ret;
+}
+
+#define cb_prefix_count	cb_prefix_count_float
+
+#endif
+
+#endif
diff --git a/src/post_modules/CritBit/critbit/key_int.h b/src/post_modules/CritBit/critbit/key_int.h
new file mode 100644
index 0000000000000000000000000000000000000000..db8dc39f1a275a0e83942a9645a86b0bb4f96446
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/key_int.h
@@ -0,0 +1,76 @@
+#ifndef CB_KEY_PIKEINT_H
+#define CB_KEY_PIKEINT_H
+#include <stdint.h>
+#include "bitvector.h"
+
+#if SIZEOF_INT_TYPE == 4
+typedef uint32_t CB_NAME(string);
+typedef uint32_t CB_NAME(char);
+#else
+typedef uint64_t CB_NAME(string);
+typedef uint64_t CB_NAME(char);
+#endif
+
+#ifdef cb_char
+# undef cb_char
+#endif
+#define cb_char CB_NAME(char)
+
+#ifdef cb_string
+# undef cb_string
+#endif
+#define cb_string CB_NAME(string)
+
+#ifdef CB_SOURCE
+#if SIZEOF_INT_TYPE == 4
+# define gclz(x) clz32(x)
+#else
+# define gclz(x) clz64(x)
+#endif
+
+#define CB_INT2UINT(x)	(((cb_char)x) ^ ((cb_char)1 << (sizeof(cb_char)*8 - 1)))
+#define CB_UINT2INT(x)				\
+	((INT_TYPE)((x) ^ ((cb_char)1 << (sizeof(cb_char)*8 - 1))))
+
+#define CB_ADD_KEY_REF(x)	do { } while(0)
+#define CB_FREE_KEY(x)		do { } while(0)
+#define CB_SET_KEY(node, x)	do { (node)->key = (x); } while (0)
+
+#define CB_KEY_EQ(k1, k2)	( (k1).str == (k2).str ||	\
+	  (CB_S_EQ((k1).len, (k2).len) && (k1).len.bits &&	\
+	    !(((k1).str ^ (k2).str) & MASK(cb_char, (k1).len.bits))))
+#define CB_KEY_MATCH(k1, k2)	( (k1).str == (k2).str &&	\
+	  (CB_S_EQ((k1).len, (k2).len) && (k1).len.bits))
+#define CB_KEY_LT(k1, k2)	( (k1).str < (k2).str ||	\
+	  (((k1).str == (k2).str) && CB_LT((k1).len, (k2).len)) )
+
+#define CB_GET_CHAR(str, n)	(str)
+#define CB_WIDTH(s)	(sizeof(cb_char)*8) /* width in byte */
+#define CB_LENGTH(str)	1
+#define CB_SIZE(key)	((key)->len)
+#define CB_GET_BIT(str, size)			\
+	(BITN(cb_char, CB_GET_CHAR((str), (size).chars), (size).bits))
+#define CB_COUNT_PREFIX(s1, s2, n)		\
+	((size_t)gclz(CB_GET_CHAR((s1), (n)) ^ CB_GET_CHAR((s2), (n))))
+
+static inline cb_size cb_prefix_count_integer(const cb_string s1,
+					      const cb_string s2,
+					      const cb_size len,
+					      const cb_size start) {
+    cb_size ret;
+
+    if (s1 == s2) return len;
+
+    ret.chars = 0;
+    ret.bits = (size_t)gclz(s1 ^ s2);
+
+    if (!len.chars) ret.bits = MINIMUM(len.bits, ret.bits);
+
+    return ret;
+}
+
+#define cb_prefix_count	cb_prefix_count_integer
+
+#endif /* CB_SOURCE */
+
+#endif
diff --git a/src/post_modules/CritBit/critbit/key_pikestring.h b/src/post_modules/CritBit/critbit/key_pikestring.h
new file mode 100644
index 0000000000000000000000000000000000000000..724e2347a9425528a2ac9efad7154b8e3122ee7a
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/key_pikestring.h
@@ -0,0 +1,156 @@
+#ifndef CB_KEY_PIKESTRING_H
+#define CB_KEY_PIKESTRING_H
+#include <stdint.h>
+#include "bitvector.h"
+
+typedef struct pike_string * CB_NAME(string);
+typedef p_wchar2 CB_NAME(char);
+
+#ifdef cb_string
+# undef cb_string
+#endif
+#define cb_string CB_NAME(string)
+
+#ifdef cb_char
+# undef cb_char
+#endif
+#define cb_char CB_NAME(char)
+
+#ifdef CB_SOURCE
+#define CB_ADD_KEY_REF(x)	do { if ((x).str) add_ref((x).str); } while(0)
+#define CB_FREE_KEY(x)		do { if ((x).str) free_string((x).str); } while(0)
+#define CB_SET_KEY(node, x)				\
+	do { CB_ADD_KEY_REF(x);				\
+	    CB_FREE_KEY((node)->key); (node)->key = (x); } while(0)
+
+#define CB_KEY_EQ(k1, k2)	(CB_S_EQ((k1).len, (k2).len) && (k1).str == (k2).str)
+#define CB_KEY_LT(k1, k2)				\
+	(CB_LT((k1).len, (k2).len) && my_quick_strcmp((k1).str, (k2).str) < 0)
+
+#define CB_GET_CHAR(s, n)	((cb_char)INDEX_CHARP((s)->str, (n), (s)->size_shift))
+#define CB_WIDTH(s)	(1 << (3 + (s)->size_shift)) /* width in bits */
+#define CB_LENGTH(str)	((str)->len)
+#define CB_SIZE(key)	((key).len)
+#define CB_GET_BIT(str, pos)				\
+	(BITN(cb_char, CB_GET_CHAR((str), (pos).chars), (pos).bits))
+static inline uint32_t CB_COUNT_PREFIX(const cb_string s1, const cb_string s2, const size_t n) {
+    cb_char c;
+    c = CB_GET_CHAR(s1, n);
+    c ^= CB_GET_CHAR(s2, n);
+
+    return clz32(c);
+}
+
+
+static inline cb_size cb_prefix_count_fallback(const cb_string,
+					    const cb_string,
+					    const cb_size,
+					    cb_size);
+
+static inline cb_size cb_prefix_count_wide0(const cb_string s1,
+					    const cb_string s2,
+					    const cb_size len,
+					    cb_size start) {
+    size_t j = start.chars;
+    const unsigned char * p1, * p2;
+
+    p1 = STR0(s1);
+    p2 = STR0(s2);
+
+#if 0
+    asm volatile(
+    "pushf\t\n"
+    "orl $(1<<18), (%esp)\t\n"
+    "popf\t\n"
+  );
+#endif
+
+#define PREFIX(n) do {						\
+    size_t k = j/sizeof(uint ##n ##_t);				\
+    for (;k < len.chars/sizeof(uint ##n ##_t);k++) {		\
+	uint ##n ##_t x = ((uint ##n ##_t *)p1)[k] 		\
+			^ ((uint ##n ##_t *)p2)[k];	    	\
+	if (x) {						\
+	    uint32_t a;						\
+	    a = clz ##n(hton ##n(x));				\
+	    start.chars = k*sizeof(uint ##n ##_t) + a/8;	\
+	    start.bits = 24 + a % 8;				\
+	    return start;					\
+	}							\
+    }								\
+    j = k*sizeof(uint ##n ##_t);				\
+    } while(0)
+#ifdef lzc64
+   PREFIX(64);
+#endif
+   PREFIX(32);
+    PREFIX(8);
+
+#if 0
+    asm volatile(
+    "pushf\t\n"
+    "andl $(~(1<<18)), (%esp)\t\n"
+    "popf\t\n"
+  );
+#endif
+
+    start.chars = j;
+
+    if (len.bits) {
+	uint32_t a = clz8(((p_wchar0*)p1)[j]^((p_wchar0*)p2)[j]);
+	start.bits = MINIMUM(len.bits, 24+a);
+	return start;
+    }
+
+    start.bits = 0;
+    return start;
+}
+
+static inline cb_size cb_prefix_count_widestring(const cb_string s1,
+						 const cb_string s2,
+						 const cb_size len,
+						 const cb_size start) {
+#if 0
+    size_t i;
+    cb_size t, r;
+    unsigned char* chrptr = s1->str;;
+    static volatile cb_string n1, n2;
+    static volatile void* zero = NULL;
+    static volatile cb_size *rp, *tp;
+
+    n1 = s1;
+    n2 = s2;
+
+#endif
+    if (CB_WIDTH(s1) == 8 && 8 == CB_WIDTH(s2))
+	return cb_prefix_count_wide0(s1, s2, len, start);
+#if 0
+	if (!CB_S_EQ(r, t)) {
+	    rp = &r;
+	    tp = &t;
+	    fprintf(stderr, "%p(%p) and %p(%p) have prefix %lu,%lu. should "
+		    + "have %lu,%lu (len: %lu, %lu  start: %lu, %lu)\n",
+		    s1->str, s1, s2->str, s2, t.chars, t.bits, r.chars,
+		    r.bits, len.chars, len.bits, start.chars, start.bits);
+	    fprintf(stderr, "here you die: %p, %lu\n", chrptr,
+		    r.bits/(uint64_t)zero);
+	    fprintf(stderr, "%p %p %p", zero, n1, n2);
+	    n1 = n2 = (void*)(zero = (uint64_t)chrptr ^ (uint64_t)n1
+			      ^ (uint64_t)n2);
+	    fprintf(stderr, "%p %p %p %p %p %p", zero, n1, n2, rp, (void*)rp,
+		    tp, (void*)tp);
+	}
+#endif
+
+
+    return cb_prefix_count_fallback(s1, s2, len, start);
+}
+
+#define	cb_prefix_count	cb_prefix_count_widestring
+
+#undef CB_WIDTH
+#define CB_WIDTH(s)	(32)
+
+#endif /* CB_SOURCE */
+
+#endif
diff --git a/src/post_modules/CritBit/critbit/key_ptr.h b/src/post_modules/CritBit/critbit/key_ptr.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f80ca4b87971faef670ca34bbbf74d6d10eed55
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/key_ptr.h
@@ -0,0 +1,74 @@
+#ifndef CB_KEY_PTR_H
+#define CB_KEY_PTR_H
+#include <stdint.h>
+#include <sys/types.h>
+#include "global.h"
+
+#include "bitvector.h"
+
+#ifndef SIZEOF_CHAR_P
+# error SIZEOF_CHAR_P is not defined.
+#endif
+
+#if SIZEOF_CHAR_P == 8
+# define _VOIDP_TYPE uint64_t
+# define gclz(x) clz64(x)
+#elif SIZEOF_CHAR_P == 4
+# define _VOIDP_TYPE uint32_t
+# define gclz(x) clz32(x)
+#else
+# error UNKNOWN POINTER SIZE
+#endif
+
+typedef _VOIDP_TYPE CB_NAME(char);
+typedef _VOIDP_TYPE CB_NAME(string);
+
+#ifdef cb_char
+# undef cb_char
+#endif
+#define cb_char CB_NAME(char)
+
+#ifdef cb_string
+# undef cb_string
+#endif
+#define cb_string CB_NAME(string)
+
+#define CB_ADD_KEY_REF(x)	do { } while(0)
+#define CB_FREE_KEY(x)		do { } while(0)
+#define CB_SET_KEY(node, x)	do { (node)->key = (x); } while (0)
+
+#define CB_KEY_EQ(k1, k2)	( (k1).str == (k2).str )
+#define CB_KEY_LT(k1, k2)	( (k1).str < (k2).str \
+		  || (((k1).str == (k2).str) && CB_LT((k1).len, (k2).len)) )
+
+#define CB_GET_CHAR(str, n)	(str)
+#define CB_WIDTH(s)	(sizeof(cb_char)*8) /* width in byte */
+#define CB_LENGTH(str)	1
+#define CB_SIZE(key)	((key)->len)
+#define CB_GET_BIT(str, size)		\
+	(BITN(cb_char, CB_GET_CHAR((str), (size).chars), (size).bits))
+#define CB_COUNT_PREFIX(s1, s2, n)	\
+	((size_t)gclz(CB_GET_CHAR((s1), (n)) ^ CB_GET_CHAR((s2), (n))))
+
+#define CB_PRINT_KEY(buf, key)		do \
+	{ string_builder_sprintf((buf), "%p", (void*)((key).str)); } while(0)
+
+static inline cb_size cb_prefix_count_pointer(const cb_string s1,
+					      const cb_string s2,
+					      const cb_size len,
+					      const cb_size start) {
+    cb_size ret;
+
+    if (s1 == s2) return len;
+
+    ret.chars = 0;
+    ret.bits = (size_t)gclz(s1 ^ s2);
+
+    if (!len.chars) ret.bits = MINIMUM(len.bits, ret.bits);
+
+    return ret;
+}
+
+#define cb_prefix_count cb_prefix_count_pointer
+
+#endif /* _CB_KEY_PTR_H */
diff --git a/src/post_modules/CritBit/critbit/string2svalue.c b/src/post_modules/CritBit/critbit/string2svalue.c
new file mode 100644
index 0000000000000000000000000000000000000000..468c3fb63352fcfc29b5c1935decd7fbd8dfc013
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/string2svalue.c
@@ -0,0 +1,4 @@
+#define CB_SOURCE
+
+#include "string2svalue.h"
+#include "tree_low.c"
diff --git a/src/post_modules/CritBit/critbit/string2svalue.h b/src/post_modules/CritBit/critbit/string2svalue.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3a8191a3f4c17787bf63881bfd7fa98832eb3df
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/string2svalue.h
@@ -0,0 +1,26 @@
+#ifdef CB_NAMESPACE
+# undef CB_NAMESPACE
+#endif
+#define CB_NAMESPACE	string2svalue
+
+#ifndef CB_INLINE
+# define CB_INLINE
+#else
+# undef CB_INLINE
+# define CB_INLINE inline
+#endif
+
+#ifndef CB_STATIC
+# define CB_STATIC
+#else
+# undef CB_STATIC
+# define CB_STATIC static
+#endif
+
+#ifndef CB_STRING2SVALUE_H
+# define CB_STRING2SVALUE_H
+# include "critbit.h"
+# include "key_pikestring.h"
+# include "value_svalue.h"
+# include "tree_low.h"
+#endif
diff --git a/src/post_modules/CritBit/critbit/value_ptr.h b/src/post_modules/CritBit/critbit/value_ptr.h
new file mode 100644
index 0000000000000000000000000000000000000000..12a2e81fe06e29cd8e2c4f6ac5e1a24643ab07e4
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/value_ptr.h
@@ -0,0 +1,11 @@
+#ifndef _PTR_VALUE_H
+#define _PTR_VALUE_H
+
+#define CB_SET_VALUE(node, v)	\
+	do { (node)->value = (cb_value)(*(v)); } while (0)
+#define CB_GET_VALUE(node, v)	do { (*(v)) = (node)->value; } while(0)
+#define CB_FREE_VALUE(v)	do {} while(0)
+#define CB_HAS_VALUE(node)	(!!((node)->value))
+#define CB_INIT_VALUE(node)	do { (node)->value = NULL; } while(0)
+#define CB_RM_VALUE(node)	do { CB_INIT_VALUE(node); } while(0)
+#endif /* _PTR_VALUE_H */
diff --git a/src/post_modules/CritBit/critbit/value_svalue.h b/src/post_modules/CritBit/critbit/value_svalue.h
new file mode 100644
index 0000000000000000000000000000000000000000..4cb573db3e7a0096de53a92b633ead1a4e5c0bb5
--- /dev/null
+++ b/src/post_modules/CritBit/critbit/value_svalue.h
@@ -0,0 +1,21 @@
+#ifndef CB_VALUE_SVALUE_H
+#define CB_VALUE_SVALUE_H
+#include "svalue.h"
+
+typedef struct svalue CB_NAME(value);
+
+#ifdef cb_value
+# undef cb_value
+#endif
+#define cb_value CB_NAME(value)
+
+#define CB_SET_VALUE(node, v)	assign_svalue(&((node)->value), (v))
+#define CB_GET_VALUE(node, v)	assign_svalue_no_free((v), &((node)->value))
+#define CB_FREE_VALUE(v)	free_svalue(v)
+#define CB_HAS_VALUE(node)	((node)->value.type != T_VOID)
+#define CB_INIT_VALUE(node)	do { (node)->value.type = T_VOID; } while(0)
+#define CB_RM_VALUE(node)	do { if (CB_HAS_VALUE(node)) \
+    free_svalue(&((node)->value)); CB_INIT_VALUE(node); } while(0)
+#define CB_PUSH_VALUE(v)	push_svalue(&(v))
+
+#endif
diff --git a/src/post_modules/CritBit/floattree.cmod b/src/post_modules/CritBit/floattree.cmod
new file mode 100644
index 0000000000000000000000000000000000000000..fcab48ba508daa4e5cd1f331fb6b087c0259d8b0
--- /dev/null
+++ b/src/post_modules/CritBit/floattree.cmod
@@ -0,0 +1,101 @@
+/* vim:syntax=c
+ */
+#ifdef cmod___CMOD__
+#ifdef __SSE4_2__
+# include <smmintrin.h>
+#endif
+#include "cyclic.h"
+#include "global.h"
+#include "interpret.h"
+#include "mapping.h"
+#include "module.h"
+#include "pike_error.h"
+#include "pike_float.h"
+#include "pike_types.h"
+#include "stralloc.h"
+#include "svalue.h"
+#include "array.h"
+#include "operators.h"
+#include "builtin_functions.h"
+
+#ifdef CB_USE_BLOCK_ALLOC
+# include "tree_block_alloc.h"
+
+static blk_alloc_t allocator;
+
+# define CB_NODE_ALLOC()	alloc_item(allocator)
+# define CB_NODE_FREE(x)	free_item(allocator, (void*)(x))
+#endif
+
+#define CB_SOURCE
+#define CB_STATIC
+#define CB_INLINE
+#define CB_NAMESPACE
+
+#include "critbit/float2svalue.h"
+#define CB_PRINT_KEY(buf, key)			\
+	do { string_builder_sprintf((buf), "%f",\
+				    cb_decode_float((key).str)); } while(0)
+#include "tree_high.c"
+
+#define DEFAULT_CMOD_STORAGE static
+
+DECLARATIONS
+
+/*! @module ADT */
+/*! @module CritBit */
+
+PIKECLASS FloatTree {
+#cmod_define iterator_class Iterator
+#cmod_define tree_class FloatTree
+#cmod_define cmod_OBJ2_TREE OBJ2_FLOATTREE
+#cmod_define T_KEY (PIKE_T_FLOAT|PIKE_T_INT)
+#cmod_define key_ptype float|int
+#cmod_define sample_key 12.0
+#cmod_define sample_keys ({ 80.4, 99.9, 14.2 })
+#cmod_define ordered_keys 14.2, 80.4 and 99.9
+#cmod_define reverse_ordered_keys 99.9, 80.4 and 14.2
+#cmod_define sample_value ({ 4, 5, 6 })
+#cmod_define extra_doc
+
+#define CB_LOW_ASSIGN_SVALUE_KEY(key, s)	do {			      \
+    struct svalue * __ = (s);						      \
+    SET_SVAL(*__, PIKE_T_FLOAT, 0, float_number, cb_decode_float((key).str)); \
+} while(0)
+#define CB_PUSH_KEY(key)	push_float(cb_decode_float((key).str));
+#define CB_STRING_FROM_SVALUE(v)	cb_encode_float((cb_float)	\
+		    (((v)->type == PIKE_T_INT )				\
+		     ? ((FLOAT_TYPE)(v)->u.integer)			\
+		     : (v)->u.float_number))
+#define CB_LOW_KEY_FROM_SVALUE(x) CB_KEY_FROM_STRING(CB_STRING_FROM_SVALUE(x))
+
+#cmod_include "redefine.H"
+
+#cmod_include "tree_header.H"
+#cmod_include "iterator_source.H"
+#undef THIS
+#define THIS THIS_FLOATTREE
+#cmod_include "tree_source.H"
+}
+
+/*! @endmodule */
+/*! @endmodule */
+
+void pike_init_floattree_module(void) {
+#ifdef CB_USE_BLOCK_ALLOC
+    allocator = init_allocator(128, sizeof(cb_node));
+#endif
+    INIT
+}
+
+void pike_exit_floattree_module(void) {
+#ifdef CB_USE_BLOCK_ALLOC
+    free(allocator);
+    allocator = NULL;
+#endif
+    EXIT
+}
+#else
+void pike_exit_floattree_module(void) {}
+void pike_init_floattree_module(void) {}
+#endif
diff --git a/src/post_modules/CritBit/glue.c b/src/post_modules/CritBit/glue.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7aa00fd150fdc7b027640c1c7372d908b73f9e7
--- /dev/null
+++ b/src/post_modules/CritBit/glue.c
@@ -0,0 +1,38 @@
+#include "global.h"
+#include "module.h"
+
+#include "interpret.h"
+#include "svalue.h"
+#include "stralloc.h"
+#include "array.h"
+#include "pike_macros.h"
+#include "program.h"
+#include "stralloc.h"
+#include "object.h"
+#include "pike_types.h"
+#include "pike_error.h"
+#include "builtin_functions.h"
+#include "module_support.h"
+#include "bignum.h"
+#include "operators.h"
+#include "gc.h"
+#include <stdio.h>
+
+extern void pike_init_inttree_module();
+extern void pike_init_tree_module();
+extern void pike_init_floattree_module();
+extern void pike_exit_inttree_module();
+extern void pike_exit_tree_module();
+extern void pike_exit_floattree_module();
+
+PIKE_MODULE_INIT {
+    pike_init_inttree_module();
+    pike_init_tree_module();
+    pike_init_floattree_module();
+}
+
+PIKE_MODULE_EXIT {
+    pike_exit_inttree_module();
+    pike_exit_tree_module();
+    pike_exit_floattree_module();
+}
diff --git a/src/post_modules/CritBit/inttree.cmod b/src/post_modules/CritBit/inttree.cmod
new file mode 100644
index 0000000000000000000000000000000000000000..43bde488b07083c446e0119d6e8afdbe4821d7d8
--- /dev/null
+++ b/src/post_modules/CritBit/inttree.cmod
@@ -0,0 +1,208 @@
+/* vim:syntax=c
+ */
+#ifdef cmod___CMOD__
+#ifdef __SSE4_2__
+# include <smmintrin.h>
+#endif
+#include "cyclic.h"
+#include "global.h"
+#include "interpret.h"
+#include "mapping.h"
+#include "module.h"
+#include "array.h"
+#include "pike_error.h"
+#include "pike_float.h"
+#include "pike_types.h"
+#include "stralloc.h"
+#include "svalue.h"
+#include "array.h"
+#include "operators.h"
+#include "builtin_functions.h"
+
+#ifdef CB_USE_BLOCK_ALLOC
+# include "tree_block_alloc.h"
+
+static blk_alloc_t allocator;
+
+# define CB_NODE_ALLOC()	alloc_item(allocator)
+# define CB_NODE_FREE(x)	free_item(allocator, (void*)(x))
+#endif
+
+#define CB_STATIC
+#define CB_INLINE
+#define CB_SOURCE
+#define CB_NAMESPACE
+
+#include "critbit/int2svalue.h"
+#define CB_PRINT_KEY(buf, key)		do \
+    { string_builder_sprintf((buf), "%d", CB_UINT2INT((key).str)); } while(0)
+#define CB_LOW_ASSIGN_SVALUE_KEY(key, s)	do {			\
+    struct svalue * __ = (s);						\
+    SET_SVAL(*__, PIKE_T_INT, 0, integer, CB_UINT2INT((key).str));	\
+} while(0)
+#define CB_PUSH_KEY(key)	push_int(CB_UINT2INT((key).str));
+#define CB_STRING_FROM_SVALUE(v)	CB_INT2UINT((v)->u.integer)
+#define CB_LOW_KEY_FROM_SVALUE(x) CB_KEY_FROM_STRING(CB_STRING_FROM_SVALUE(x))
+#include "tree_high.c"
+
+#define DEFAULT_CMOD_STORAGE static
+
+DECLARATIONS
+
+/*! @module ADT */
+/*! @module CritBit */
+
+PIKECLASS IntTree {
+#cmod_define iterator_class Iterator
+#cmod_define tree_class IntTree
+#cmod_define cmod_OBJ2_TREE OBJ2_INTTREE
+#cmod_define T_KEY PIKE_T_INT
+#cmod_define key_ptype int
+#cmod_define sval_type integer
+#cmod_define sample_key 12
+#cmod_define sample_keys ({ 1025, 15000, 3 })
+#cmod_define ordered_keys 3, 1025 and 15000
+#cmod_define reverse_ordered_keys 15000, 1025 and 3
+#cmod_define sample_value ({ 1, 2 ,3 })
+#cmod_define extra_doc
+#cmod_include "redefine.H"
+
+#cmod_include "tree_header.H"
+#cmod_include "iterator_source.H"
+#undef THIS
+#define THIS THIS_INTTREE
+#cmod_include "tree_source.H"
+}
+
+#define WASTED_BITS (8*(sizeof(INT_TYPE)-4))
+
+cb_key cb_key_from_ptype_ipv4(struct pike_string * s) {
+    cb_key key;
+    uint32_t a, b, c, d, e;
+
+    key.len.chars = 1;
+    key.len.bits = 0;
+
+    if (s->size_shift || s->len > 18) Pike_error("Malformed ip.\n");
+
+    switch (sscanf((char *)STR0(s), "%3u.%3u.%3u.%3u/%2u", &a, &b, &c, &d, &e))
+    {
+    case 5:
+	if (e > 32) Pike_error("Mask is too big!");
+	key.len.chars = 0;
+	key.len.bits = WASTED_BITS + e;
+    case 4:
+	if (a > 255 || b > 255 || c > 255 || d > 255)
+	    Pike_error("Bad ip.\n");
+	key.str = (INT_TYPE)(a << 24 | b << 16 | c << 8 | d);
+	break;
+    default:
+	Pike_error("Malformed ip.\n");
+    }
+
+    return key;
+}
+
+struct pike_string * cb_ptype_from_key_ipv4(cb_key key) {
+    char buf[19];
+    size_t len;
+
+    uint32_t ip = (uint32_t)key.str;
+
+    if (key.len.bits || !key.len.chars) {
+	len = snprintf(buf, 19, "%u.%u.%u.%u/%u", ip>>24, (ip>>16)&0xff,
+		       (ip>>8)&0xff, ip&0xff, (uint32_t)(key.len.bits
+							 - WASTED_BITS));
+    } else {
+	len = snprintf(buf, 19, "%u.%u.%u.%u", ip>>24, (ip>>16)&0xff,
+		       (ip>>8)&0xff, ip&0xff);
+    }
+
+    return make_shared_binary_string(buf, MINIMUM(19, len));
+}
+
+PIKECLASS IPv4Tree {
+#cmod_define iterator_class Iterator
+#cmod_define tree_class IPv4Tree
+#cmod_define cmod_OBJ2_TREE OBJ2_IPV4TREE
+#cmod_define T_KEY PIKE_T_STRING
+#cmod_define key_ptype string
+#cmod_define sval_type string
+#cmod_define sample_key "127.0.0.0/8"
+#cmod_define sample_keys ({ "10.243.7.1", "127.0.0.1/8", "172.16.5.2" })
+#cmod_define ordered_keys "10.243.7.1", "127.0.0.1/8" and "172.16.5.2"
+#cmod_define reverse_ordered_keys "172.16.5.2", "127.0.0.1/8" and "10.243.7.1"
+#cmod_define sample_value "reject"
+#cmod_define extra_doc
+
+#undef CB_INT2UINT
+#undef CB_UINT2INT
+#define CB_INT2UNIT(x) (x)
+#define CB_UINT2INT(x) (x)
+#undef CB_PUSH_KEY
+#define CB_PUSH_KEY(key) push_string(cb_ptype_from_key_ipv4(key))
+#undef CB_KEY_FROM_PTYPE
+#define CB_KEY_FROM_PTYPE(x)	cb_key_from_ptype_ipv4(x)
+#undef CB_STRING_FROM_SVALUE
+#undef CB_LOW_KEY_FROM_SVALUE
+#undef CB_KEY_FROM_SVALUE
+#define CB_LOW_KEY_FROM_SVALUE(x)		CB_KEY_FROM_PTYPE((x)->u.string)
+#undef CB_LOW_ASSIGN_SVALUE_KEY
+#define CB_LOW_ASSIGN_SVALUE_KEY(key, s) do {				  \
+    struct svalue * __ = s;						  \
+    SET_SVAL(*__, PIKE_T_STRING, 0, string, cb_ptype_from_key_ipv4(key)); \
+} while (0)
+
+#cmod_include "redefine.H"
+
+#cmod_include "tree_header.H"
+#cmod_include "iterator_source.H"
+#undef THIS
+#define THIS THIS_IPV4TREE
+#cmod_include "tree_source.H"
+
+    PIKEFUN int mask(int n) {
+	RETURN MASK(INT_TYPE, n);
+    }
+
+    PIKEFUN int umask(int n) {
+	RETURN MASK(uint64_t, n);
+    }
+
+    PIKEFUN int cmp_key(mixed a, mixed b) {
+	cb_key k1 = CB_KEY_FROM_SVALUE(a);
+	cb_key k2 = CB_KEY_FROM_SVALUE(b);
+	INT_TYPE ret;
+	if (CB_KEY_LT(k1, k2)) {
+	    ret = -1;
+	} else if (CB_KEY_MATCH(k1, k2)) {
+	    ret = 0;
+	} else {
+	    ret = 1;
+	}
+	pop_n_elems(args);
+	push_int(ret);
+    }
+}
+
+/*! @endmodule */
+/*! @endmodule */
+
+void pike_init_inttree_module(void) {
+#ifdef CB_USE_BLOCK_ALLOC
+    allocator = init_allocator(128, sizeof(cb_node));
+#endif
+    INIT
+}
+
+void pike_exit_inttree_module(void) {
+#ifdef CB_USE_BLOCK_ALLOC
+    free(allocator);
+    allocator = NULL;
+#endif
+    EXIT
+}
+#else
+void pike_init_inttree_module(void) {}
+void pike_exit_inttree_module(void) {}
+#endif
diff --git a/src/post_modules/CritBit/iterator_source.H b/src/post_modules/CritBit/iterator_source.H
new file mode 100644
index 0000000000000000000000000000000000000000..7cb5237d654b24e6ca15afa8c8148a79b6fef36f
--- /dev/null
+++ b/src/post_modules/CritBit/iterator_source.H
@@ -0,0 +1,247 @@
+    DOCSTART() @class Iterator
+     *! Iterator class for tree_class trees. Supports iterating over ranges
+     *! with arbitrary stepping and direction.
+     *!
+     *! This is used by default when calling @expr{foreach@} on an object of
+     *! tree_class. In @expr{foreach@} the iterator runs over all elements
+     *! from the first to the last.
+     *!
+     *! @seealso
+     *! 	@[predef::Iterator] for a description of the interface.
+    DOCEND()
+    PIKECLASS iterator_class {
+	CVAR cb_node_t lastnode, tree;
+	CVAR cb_key lastkey;
+	CVAR cb_value lastval;
+	CVAR struct object * ptree;
+	CVAR size_t * revv, lastrev;
+	CVAR INT_TYPE step;
+	CVAR cb_key stop;
+
+	INIT {
+	    THIS->lastval.type = T_VOID;
+	    THIS->ptree = NULL;
+	    THIS->lastnode = NULL;
+	    THIS->step = 1;
+	    THIS->stop.len.chars = 0;
+	    THIS->stop.len.bits = 0;
+	    THIS->stop.str = (cb_string)0;
+	}
+
+	EXIT {
+	    if (THIS->stop.len.chars || THIS->stop.len.bits || THIS->stop.str) {
+		CB_FREE_KEY(THIS->stop);
+	    }
+
+	    if (THIS->lastnode) {
+		CB_FREE_KEY(THIS->lastkey);
+		CB_FREE_VALUE(&THIS->lastval);
+	    }
+	    if (THIS->ptree) {
+		free_object(THIS->ptree);
+		THIS->ptree = NULL;
+	    }
+	}
+
+	static inline int cmod_CONCAT_EVAL(tree_class,_,iterator_class,_step)() {
+	    cb_node_t t;
+	    INT_TYPE c = THIS->step;
+
+	    if (THIS->lastrev == *THIS->revv) {
+		t = THIS->lastnode;
+	    } else {
+		THIS->lastrev = * THIS->revv;
+
+		if (THIS->tree) {
+		    t = cb_index(THIS->tree, THIS->lastkey);
+		    if (t) {
+			THIS->lastnode = t;
+		    } else { /* the last node was removed and freed. */
+			if (c > 0) {
+			    t = cb_find_next(THIS->tree, THIS->lastkey);
+			    c--;
+			} else {
+			    t = cb_find_previous(THIS->tree, THIS->lastkey);
+			    c++;
+			}
+		    }
+		} else {
+		    t = NULL;
+		}
+	    }
+
+	    if (THIS->lastnode) {
+		CB_FREE_KEY(THIS->lastkey);
+		CB_FREE_VALUE(&THIS->lastval);
+	    }
+
+	    if (t) {
+		if (c > 0) {
+		    WALK_FORWARD(t, {
+			if (CB_HAS_VALUE(_)) c--;
+			if (c == 0) break;
+		    });
+		} else if (c < 0) {
+		    WALK_BACKWARD(t, {
+			if (CB_HAS_VALUE(_)) c++;
+			if (c == 0) break;
+		    });
+		    if (t == THIS->tree && !CB_HAS_VALUE(t)) t = NULL;
+		}
+
+		if (t) {
+		    /* check for stop
+		     * TODO: if we know that the lastnode is a parent
+		     * of t, and stop was bigger than both children, then
+		     * we could skip this check. */
+		    if (THIS->stop.len.chars || THIS->stop.len.bits) {
+			if (THIS->step < 0) {
+			    if (CB_KEY_LT(t->key, THIS->stop)) t = NULL;
+			} else {
+			    if (CB_KEY_LT(THIS->stop, t->key)) t = NULL;
+			}
+		    }
+		    if (t) {
+			CB_GET_VALUE(t, &THIS->lastval);
+			THIS->lastkey = t->key;
+			CB_ADD_KEY_REF(THIS->lastkey);
+		    }
+		}
+	    }
+	    THIS->lastnode = t;
+	    return !!t;
+	}
+
+	DOCSTART() @decl void create(tree_class tree, void|int step, @
+	 *!void|mixed start, void|mixed stop)
+	 *! Returns an iterator object that runs from @expr{start@} to
+	 *! @expr{stop@} using a stepsize of @expr{step@}. The arguments
+	 *! default to @expr{1@}, @expr{tree->first()@} and
+	 *! @expr{tree->last()@}, respectively.
+	DOCEND()
+	PIKEFUN void create(object tree, void|int step, void|mixed start,
+			    void|mixed stop) {
+	    cb_node_t t = NULL;
+	    INT32 encode_fun;
+	    if (-1 == low_get_storage(tree->prog, TREE_CLASSIFY(_program))) {
+		SIMPLE_BAD_ARG_ERROR("create", 1, "CritBit." cmod_STRFY_EVAL(tree_class));
+	    }
+	    add_ref(THIS->ptree = tree);
+	    THIS->revv = &(cmod_OBJ2_TREE(tree)->rev);
+	    THIS->tree = cmod_OBJ2_TREE(tree)->tree;
+
+	    THIS->stop.len.chars = 0;
+	    THIS->stop.len.bits = 0;
+
+	    encode_fun = cmod_OBJ2_TREE(tree)->encode_fun;
+
+	    if (THIS->tree) {
+		if (args < 2 || IS_UNDEFINED(step)) {
+		    THIS->step = 1;
+		} else {
+		    THIS->step = step->u.integer;
+		    if (THIS->step == 0)
+			SIMPLE_BAD_ARG_ERROR("create", 2, "int(..-1)|int(1..)");
+		}
+
+		switch (args) {
+		case 4:
+		    if (!IS_UNDEFINED(stop)) {
+			if (encode_fun >= 0) {
+			    push_svalue(stop);
+			    apply_low(tree, encode_fun, 1);
+			    assign_svalue(stop, Pike_sp-1);
+			    pop_stack();
+			    if (!(stop->type & T_KEY))
+				SIMPLE_BAD_ARG_ERROR("create", 4, cmod_STRFY_EVAL(key_ptype));
+			}
+			THIS->stop = CB_LOW_KEY_FROM_SVALUE(stop);
+			CB_ADD_KEY_REF(THIS->stop);
+		    }
+		case 3:
+		    if (!IS_UNDEFINED(start)) {
+			cb_key s;
+			if (encode_fun >= 0) {
+			    push_svalue(start);
+			    apply_low(tree, encode_fun, 1);
+			    assign_svalue(start, Pike_sp-1);
+			    pop_stack();
+			    if (!(start->type & T_KEY))
+				SIMPLE_BAD_ARG_ERROR("create", 3, cmod_STRFY_EVAL(key_ptype));
+			}
+			s = CB_LOW_KEY_FROM_SVALUE(start);
+
+			t = cb_index(THIS->tree, s);
+
+			if (!t) {
+			    t = (THIS->step < 0)
+				? cb_find_previous(THIS->tree, s)
+				: cb_find_next(THIS->tree, s);
+			    if (t && (THIS->stop.len.chars || THIS->stop.len.bits)) {
+				/* check if we ran over stop */
+				if (THIS->step < 0) {
+				    if (CB_KEY_LT(t->key, THIS->stop))
+					t = NULL;
+				} else {
+				    if (CB_KEY_LT(THIS->stop, t->key))
+					t = NULL;
+				}
+			    }
+			}
+		    }
+		case 2:
+		case 1:
+		    if (!t) t = (THIS->step < 0)
+				? cb_find_last(THIS->tree)
+				: cb_find_first(THIS->tree);
+		    break;
+		default:
+		    Pike_error("Too many arguments.\n");
+		}
+
+		if (t) {
+		    CB_GET_VALUE(t, &THIS->lastval);
+		    THIS->lastkey = t->key;
+		    CB_ADD_KEY_REF(THIS->lastkey);
+		}
+		THIS->lastnode = t;
+	    }
+
+	    pop_n_elems(args);
+	}
+
+	PIKEFUN object _get_iterator() {
+	    ref_push_object(Pike_fp->current_object);
+	}
+
+	PIKEFUN int next() {
+	    if(cmod_CONCAT_EVAL(tree_class,_,iterator_class,_step)()) {
+		push_int(1);
+		return;
+	    }
+	    push_undefined();
+	    return;
+	}
+
+	PIKEFUN key_ptype index() {
+	    if (THIS->lastnode) {
+		INT32 fun = cmod_OBJ2_TREE(THIS->ptree)->decode_fun;
+		CB_PUSH_KEY(THIS->lastkey);
+		if (fun >= 0)
+		    apply_low(THIS->ptree, fun, 1);
+	    } else push_undefined();
+	}
+
+	PIKEFUN mixed value() {
+	    if (THIS->lastnode) {
+		CB_PUSH_VALUE(THIS->lastval);
+		return;
+	    }
+	    push_undefined();
+	}
+
+	PIKEFUN int `!() {
+	    push_int(!THIS->lastnode);
+	}
+    }
+    /*! @endclass */
diff --git a/src/post_modules/CritBit/redefine.H b/src/post_modules/CritBit/redefine.H
new file mode 100644
index 0000000000000000000000000000000000000000..4635b5919db3789e7de4e5693e4477d8f4281447
--- /dev/null
+++ b/src/post_modules/CritBit/redefine.H
@@ -0,0 +1,23 @@
+cmod_REDEFINE(iterator_class)
+cmod_REDEFINE(tree_class)
+cmod_REDEFINE(cmod_OBJ2_TREE)
+cmod_REDEFINE(T_KEY)
+cmod_REDEFINE(key_ptype)
+cmod_REDEFINE(sval_type)
+cmod_REDEFINE(sample_key)
+cmod_REDEFINE(sample_keys)
+cmod_REDEFINE(ordered_keys)
+cmod_REDEFINE(reverse_ordered_keys)
+cmod_REDEFINE(sample_value)
+cmod_REDEFINE(extra_doc)
+#ifndef STRFY2
+# define STRFY2(x)	#x
+# ifdef STRFY
+#  undef STRFY
+# endif
+# define STRFY(x...)	STRFY2(x)
+#endif
+#cmod_ifdef TREE_CLASSIFY
+# cmod_undef TREE_CLASSIFY
+#cmod_endif
+#cmod_define TREE_CLASSIFY(x...)	cmod_CONCAT_EVAL(tree_class, ##x)
diff --git a/src/post_modules/CritBit/stringtree.cmod b/src/post_modules/CritBit/stringtree.cmod
new file mode 100644
index 0000000000000000000000000000000000000000..fb19786032e957fc2ba726d9cb2232dd50210164
--- /dev/null
+++ b/src/post_modules/CritBit/stringtree.cmod
@@ -0,0 +1,104 @@
+/* vim:syntax=c
+ */
+#include "cyclic.h"
+#include "global.h"
+#include "interpret.h"
+#include "mapping.h"
+#include "module.h"
+#include "pike_error.h"
+#include "pike_float.h"
+#include "pike_types.h"
+#include "stralloc.h"
+#include "svalue.h"
+#include "array.h"
+#include "operators.h"
+#include "builtin_functions.h"
+
+#ifdef cmod___CMOD__
+
+#define CB_SOURCE
+#define CB_STATIC
+#define CB_INLINE
+#define CB_NAMESPACE
+
+#include "critbit/string2svalue.h"
+
+/* this is only used in pike code! */
+#define CB_PRINT_CHAR(buf, str, n)			\
+    do { string_builder_sprintf((buf), "%c", CB_GET_CHAR(str, n)); } while(0)
+
+#define CB_PRINT_KEY(buf, key)				\
+	do { string_builder_shared_strcat((buf), (key).str); } while(0)
+#define CB_LOW_ASSIGN_SVALUE_KEY(key, s)	do {	\
+    struct pike_string * _key = (key).str;		\
+    struct svalue * _svalue = (s);			\
+    add_ref(_key);					\
+    SET_SVAL(*_svalue, PIKE_T_STRING, 0, string, _key); \
+} while(0)
+#define CB_PUSH_KEY(key)	ref_push_string((key).str)
+#define CB_PUSH_STRING(str)	ref_push_string(str)
+#define CB_STRING_FROM_SVALUE(v)	((v)->u.string)
+#define CB_LOW_KEY_FROM_SVALUE(v)	CB_KEY_FROM_STRING(CB_STRING_FROM_SVALUE(v))
+
+/* #define CB_USE_BLOCK_ALLOC */
+#ifdef CB_USE_BLOCK_ALLOC
+# undef BLOCK_ALLOC_NEXT
+# define BLOCK_ALLOC_NEXT	parent
+# include "block_alloc.h"
+
+BLOCK_ALLOC_FILL_PAGES(cb_node, 2)
+# define CB_NODE_ALLOC()	CONCAT2(alloc_,CB_NAME(node))()
+# define CB_NODE_FREE(x)	CONCAT2(really_free_,CB_NAME(node))(x)
+#endif
+
+#include "tree_high.c"
+
+#define DEFAULT_CMOD_STORAGE static
+
+DECLARATIONS
+
+/*! @module ADT */
+/*! @module CritBit */
+
+PIKECLASS StringTree {
+#cmod_define iterator_class Iterator
+#cmod_define tree_class StringTree
+#cmod_define cmod_OBJ2_TREE OBJ2_STRINGTREE
+#cmod_define T_KEY PIKE_T_STRING
+#cmod_define key_ptype string
+#cmod_define sval_type string
+#cmod_define sample_key "foo"
+#cmod_define sample_keys ({ "fooo", "bar", "ahead" })
+#cmod_define ordered_keys "ahead", "bar" and "foo"
+#cmod_define reverse_ordered_keys "foo", "bar" and "ahead"
+#cmod_define sample_value ({ 7, 8, 9 })
+#cmod_define extra_doc
+#cmod_include "redefine.H"
+
+#cmod_include "tree_header.H"
+#cmod_include "iterator_source.H"
+#undef THIS
+#define THIS THIS_STRINGTREE
+#cmod_include "tree_source.H"
+}
+
+/*! @endmodule */
+/*! @endmodule */
+
+void pike_init_tree_module(void) {
+#ifdef CB_USE_BLOCK_ALLOC
+    CONCAT3(init_, cb_node, _blocks)();
+#endif
+    INIT
+}
+
+void pike_exit_tree_module(void) {
+    EXIT
+}
+
+#else
+void pike_init_tree_module(void) {
+    add_integer_constant("this_program_does_not_exist", 1, 0);
+}
+void pike_exit_tree_module(void) {}
+#endif
diff --git a/src/post_modules/CritBit/testsuite.in b/src/post_modules/CritBit/testsuite.in
new file mode 100644
index 0000000000000000000000000000000000000000..2bd1d8ea46b31c38e3f01dea8d801af46f8e77e7
--- /dev/null
+++ b/src/post_modules/CritBit/testsuite.in
@@ -0,0 +1,192 @@
+START_MARKER
+
+test_true(programp(ADT.CritBit.StringTree))
+test_true(programp(ADT.CritBit.IntTree))
+test_true(programp(ADT.CritBit.FloatTree))
+test_true(programp(ADT.CritBit.IPv4Tree))
+
+define(test_const_loop,[[
+   test_any([[
+	mapping m = GET_SAMPLE();
+	object tree = GET_TREE();
+	function sortfun = GET_SORTFUN();
+	array a = GET_SORTED_A();
+
+	$1
+	return 1;
+    ]], 1)
+]])
+
+define(test_tree_equal,[[
+       test_equal([[$1]], [[$2]])
+       test_equal([[object_program($1)]], [[object_program($2)]])
+]])
+
+define(low_test_tree,[[
+    test_do(add_constant("GET_SAMPLE", lambda() { return all_constants()->THE_SAMPLE; }) )
+    test_do(add_constant("SET_SAMPLE", lambda(mixed m) { add_constant("THE_SAMPLE", m); }) )
+    test_do(add_constant("GET_SORTFUN", lambda() { return all_constants()->THE_SORTFUN; }) )
+    test_do(add_constant("SET_SORTFUN", lambda(mixed m) { add_constant("THE_SORTFUN", m); }) )
+    test_do(add_constant("GET_TREE", lambda() { return all_constants()->THE_TREE; }) )
+    test_do(add_constant("SET_TREE", lambda(mixed m) { add_constant("THE_TREE", m); }) )
+    test_do(add_constant("GET_SORTED_A", lambda() { return all_constants()->THE_SORTED_A; }) )
+    test_do(add_constant("SET_SORTED_A", lambda(mixed m) { add_constant("THE_SORTED_A", m); }) )
+    test_do([[
+	random_seed(4044);
+	SET_SAMPLE( $2 );
+	SET_SORTFUN( $3 );
+	SET_TREE($1(GET_SAMPLE()));
+	SET_SORTED_A($3(indices(GET_SAMPLE())));
+    ]])
+    $4
+    test_do(add_constant("GET_M") )
+    test_do(add_constant("GET_SAMPLE") )
+    test_do(add_constant("GET_SORTFUN") )
+    test_do(add_constant("GET_TREE") )
+    test_do(add_constant("GET_SORTED_A") )
+    test_do(add_constant("SET_M") )
+    test_do(add_constant("SET_SAMPLE") )
+    test_do(add_constant("SET_SORTFUN") )
+    test_do(add_constant("SET_TREE") )
+    test_do(add_constant("SET_SORTED_A") )
+
+    test_do(add_constant("THE_M") )
+    test_do(add_constant("THE_SAMPLE") )
+    test_do(add_constant("THE_SORTFUN") )
+    test_do(add_constant("THE_TREE") )
+    test_do(add_constant("THE_SORTED_A") )
+
+]])
+
+define(test_loop,[[
+    low_test_tree([[$1]], [[$2]], [[$3]], [[
+	test_equal((mapping)GET_TREE(), GET_SAMPLE())
+	test_tree_equal(GET_TREE(), GET_TREE()->get_subtree())
+	test_tree_equal(GET_TREE(), GET_TREE()->copy()))
+	test_tree_equal($1()+GET_TREE(), GET_TREE())
+	test_tree_equal(GET_TREE()+GET_TREE(), GET_TREE())
+	test_tree_equal(GET_TREE()+$1(), GET_TREE()))
+	test_tree_equal(GET_TREE()-GET_TREE(), $1())
+	test_tree_equal(GET_TREE()-$1(), GET_TREE()))
+	test_tree_qual(GET_TREE()[GET_TREE()->first()..GET_TREE()->last()], GET_TREE()))
+	test_const_loop([[
+	    foreach (GET_SAMPLE(); mixed a; mixed b) {
+		if (b != GET_TREE()[a])
+		    error("Value mismatch: (%O : %O) vs (%O : %O)\n", a, b, a, GET_TREE()[a]);
+	    }
+	]])
+	test_const_loop([[
+	    if (sizeof(GET_SAMPLE()) != sizeof(GET_TREE()))
+		error("Size mismatch: %O vs %O\n", sizeof(GET_SAMPLE()), sizeof(GET_TREE()));
+	]])
+	test_const_loop([[
+	    int i;
+	    foreach (tree; mixed key; mixed val) {
+		mixed nth = GET_TREE()->nth(i++)[0];
+		if (nth != key)
+		    error("Key mismatch in nth() vs tree order: (%O : %O) vs (%O : %O)\n", i, key, i, nth);
+	    }
+	]])
+	test_const_loop([[
+	    mixed t = GET_TREE()->first();
+	    foreach (GET_SORTED_A(); int i; mixed key) {
+		if (t != key)
+		    error("Key mismatch in range iterate(): (%O : %O) vs (%O : %O)\n", i, t, i, key);
+		t = GET_TREE()->next(t);
+		if (GET_SAMPLE()[key] != GET_TREE()[key])
+		    error("Value mismatch in order: (%O : %O) vs (%O : %O)\n", key, GET_SAMPLE()[key], key, GET_TREE()[key]);
+		mixed nth = GET_TREE()->nth(i)[0];
+		if (nth != key)
+		    error("Value mismatch in nth(): (%O : %O) vs (%O : %O)\n", i, key, i, nth);
+	    }
+
+	]])
+	test_const_loop([[
+	    void test_range_operator(int step) {
+		int i = (step < 0) ? sizeof(tree)-1 : 0;
+		foreach (tree->Iterator(tree, step); mixed key; mixed value) {
+		    if (GET_SORTED_A()[i] != key)
+			error("Key mismatch in range iterate(): (%O : %O) vs (%O : %O)\n", i, GET_SORTED_A()[i], i, key);
+		    if (GET_SAMPLE()[GET_SORTED_A()[i] ] != value)
+			error("Value mismatch in range iterate(): (%O : %O) vs (%O : %O)\n", i, GET_SAMPLE()[GET_SORTED_A()[i] ], i, value);
+		    i+=step;
+		}
+
+		if (step > 0) test_range_operator(-step);
+	    };
+
+	    foreach (enumerate(40, 13, 1); ; int n) {
+		if (n) test_range_operator(n);
+	    }
+	]])
+	test_const_loop([[
+	    void test_range_operator(int start, int stop, int step) {
+		int i = start;
+
+		if (step == 0) return;
+
+		foreach (tree->Iterator(tree, step, a[start], a[stop]); mixed key; mixed value) {
+		    if (GET_SORTED_A()[i] != key)
+			error("Key mismatch in range iterate(): (%O : %O) vs (%O : %O)\n", i, GET_SORTED_A()[i], i, key);
+		    if (GET_SAMPLE()[GET_SORTED_A()[i] ] != value)
+			error("Value mismatch in range iterate(): (%O : %O) vs (%O : %O)\n", i, GET_SAMPLE()[GET_SORTED_A()[i] ], i, value);
+		    i+=step;
+		}
+
+#if constant(ADT.CritBit.Range)
+		object r = ADT.CritBit.Range(a[start], a[stop]);
+		object rs = ADT.CritBit.RangeSet(object_program(tree));
+		rs[r] = 1;
+		foreach (a;; mixed key) {
+		    if (equal(GET_SORTFUN()(({ key, r.b, r.a}))[1], key)) {
+			if (undefinedp(rs[key])) {
+			    error("RangeSet error. %O not within [%O,%O]\n", key, r.a, r.b);
+			}
+		    } else {
+			if (!undefinedp(rs[key])) {
+			    error("RangeSet error. %O should not be within [%O,%O]\next: %O\n", key, r.a, r.b, rs->tree->next(key));
+			}
+		    }
+		}
+#endif
+	    };
+
+	    for (int i = 0; i < 100; i++) {
+		int start = random(sizeof(a));
+		int stop = start + random(sizeof(a)-start);
+		test_range_operator(start, stop, random(stop-start));
+	    }
+	]])
+    ]])
+    low_test_tree([[$1]], [[$2]], [[$3]], [[
+	test_const_loop([[
+	    foreach (tree; mixed key; mixed val) {
+		if (val != m[key])
+		    error("Key mismatch in random delete. %O : %O vs %O\n", key, val, m[key]);
+		array t = random(tree);
+		m_delete(tree, t[0]);
+		m_delete(m, t[0]);
+		if (!zero_type(tree[t[0] ])) error("m_delete failed in random delete (key: %O)\n", t[0]);
+	    }
+	    if (sizeof(m) != sizeof(tree)) {
+		error("Size mismatch after random delete. %O vs %O\n", sizeof(m), sizeof(tree));
+	    }
+	]])
+    ]])
+]])
+
+define(test_tree, [[
+       test_loop([[$1]], [[$2]], [[$3]])
+       test_loop([[$1]], ([]), [[$3]])
+]])
+
+test_tree(ADT.CritBit.Tree, [[all_constants()+mkmapping(map(allocate(1000, 1000), random_string), enumerate(1000))]], sort)
+test_tree(ADT.CritBit.IntTree, [[mkmapping(enumerate(100)+enumerate(1000, -19, 666)+enumerate(1000, Int.NATIVE_MAX/600, Int.NATIVE_MIN), enumerate(2100))]], sort)
+test_tree(ADT.CritBit.IPv4Tree, [[mkmapping(map(enumerate(100)+enumerate(1000, -19, 666)+enumerate(1000, Int.NATIVE_MAX/600, Int.NATIVE_MIN), lambda (int i) {
+	return ADT.CritBit.get_ipv4(i, (abs(i) % 51) & 31);
+}), enumerate(2100))]], ADT.CritBit.sort_ipv4)
+test_tree(ADT.CritBit.FloatTree, [[mkmapping((array(float))(enumerate(100)+enumerate(1000, -19, 666)+enumerate(1000, Int.NATIVE_MAX/600, Int.NATIVE_MIN)), enumerate(2100))]], sort)
+test_tree(ADT.CritBit.DateTree, [[mkmapping(map(enumerate(2000, time()/3000, 1), Function.curry(Calendar.Second)("unix")), enumerate(2000))]], sort)
+
+
+END_MARKER
diff --git a/src/post_modules/CritBit/tree_header.H b/src/post_modules/CritBit/tree_header.H
new file mode 100644
index 0000000000000000000000000000000000000000..db622bba6e6b9db4b62ebcd670269c5aa2562f5c
--- /dev/null
+++ b/src/post_modules/CritBit/tree_header.H
@@ -0,0 +1,133 @@
+DOCSTART() @class tree_class
+ *! This class implements a CritBit-tree/trie that can be used as a
+ *! mapping-like data structure. Values of @expr{key_ptype@} can be
+ *! used as indices, while any possible type (also @expr{mixed@}) can
+ *! be stored.
+ *!
+ *! CritBit trees are prefixed based search trees that allow for fast random
+ *! access as well as prefix and range based lookups. Keys are stored in
+ *! alphabetical order and can be iterated over using @expr{foreach@}.
+ *! Other than that, it can be used like @expr{mapping(key_ptype:mixed)@}.
+ *!
+ *! @example
+ *! 	@code
+ *!ADT.CritBit.tree_class tree = ADT.CritBit.tree_class();
+ *!key_ptype key1 = sample_key;
+ *!tree[key1] = sample_value;
+ *!tree[key1]; /cmod___SLASH__ now is sample_value
+ *!m_delete(tree, key1); // tree is empty again
+ *!@endcode
+ *! @example
+ *! 	@code
+ *!ADT.CritBit.tree_class tree = ADT.CritBit.tree_class();
+ *!array(key_ptype) a = sample_keys;
+ *!foreach(a; int idx; key_ptype val) {
+ *!	tree[val] = idx;
+ *!}
+ *!foreach(tree; key_ptype key; mixed val) {
+ *!	/cmod___SLASH__ in here the keys will be reached in order ordered_keys.
+ *!}
+ *!@endcode
+ *! @example
+ *! 	@code
+ *!ADT.CritBit.tree_class tree = ADT.CritBit.tree_class();
+ *!array(key_ptype) a = sample_keys;
+ *!foreach (a; int idx; key_ptype val) {
+ *!	tree[val] = idx;
+ *!}
+ *!foreach(ADT.CritBit.TREE_CLASSIFY(.Iterator)(tree, -1); @
+ *!key_ptype key; mixed val) {
+ *!	/cmod___SLASH__ in here the keys will be reached in order reverse_ordered_keys.
+ *!}
+ *!@endcode
+ *! @seealso
+ *! 	@[ADT.CritBit.TREE_CLASSIFY(.Iterator)]
+ DOCEND()
+
+DOCSTART() @decl key_ptype encode_key(mixed o)
+ *! @decl mixed decode_key(key_ptype o)
+ *! These callbacks can be implemented when inheriting tree_class in order
+ *! to allow for arbitrary key types. @[encode_key] is similar to the
+ *! @[lfun::_hash()] callback. This only works as expected when it is possible
+ *! to implement a unique representation for keys. These callbacks are called
+ *! everytime a key is stored or indexed in the tree.
+DOCEND()
+
+    CVAR cb_node_t tree;
+    CVAR size_t rev;
+    CVAR INT32 encode_fun;
+    CVAR INT32 decode_fun;
+    CVAR INT32 copy_fun;
+    CVAR INT32 insert_fun;
+
+
+#undef CB_TRANSFORM_KEY
+#define CB_TRANSFORM_KEY(svalue) {				\
+    if (THIS->encode_fun >= 0) {				\
+	push_svalue(svalue);					\
+	apply_low(Pike_fp->current_object, THIS->encode_fun, 1);\
+	assign_svalue((svalue), Pike_sp-1);			\
+	pop_stack();						\
+    }								\
+} while (0)
+#undef CB_CHECK_KEY
+#define CB_CHECK_KEY(svalue, fun, num)	do {			\
+    CB_TRANSFORM_KEY(svalue);					\
+    if (!((svalue)->type &  T_KEY))   				\
+	SIMPLE_BAD_ARG_ERROR(fun, (num), STRFY(key_ptype));	\
+} while(0)
+#undef CB_PUSH_TRANSFORM_KEY
+#define CB_PUSH_TRANSFORM_KEY(key) do {				\
+    CB_PUSH_KEY(key);						\
+    if (THIS->decode_fun >= 0) {				\
+	apply_low(Pike_fp->current_object, THIS->decode_fun, 1);\
+    }								\
+} while(0)
+
+
+static inline cb_key
+TREE_CLASSIFY(_transform_svalue_to_key)(const struct svalue * s) {
+    cb_key key;
+    if (THIS->encode_fun >= 0) {
+	push_svalue(s);
+	apply_low(Pike_fp->current_object, THIS->encode_fun, 1);
+	if (!(Pike_sp[-1].type & T_KEY))
+	    Pike_error("encode_key() is expected to return type " cmod_STRFY_EVAL(key_ptype) ".\n");
+	key = CB_LOW_KEY_FROM_SVALUE(Pike_sp-1);
+	pop_stack();
+    } else {
+	if (!(s->type & T_KEY)) Pike_error("Expected type " cmod_STRFY_EVAL(key_ptype) ".\n");
+	key = CB_LOW_KEY_FROM_SVALUE(s);
+    }
+    return key;
+}
+cmod_DEFINE_EVAL(CB_KEY_FROM_SVALUE, TREE_CLASSIFY(_transform_svalue_to_key))
+
+static inline void TREE_CLASSIFY(_assign_svalue_key)(const cb_key key,
+						  struct svalue * s) {
+    if (THIS->decode_fun >= 0) {
+	CB_PUSH_KEY(key);
+	apply_low(Pike_fp->current_object, THIS->decode_fun, 1);
+	assign_svalue((s), Pike_sp-1);
+	pop_stack();
+    } else {
+	CB_LOW_ASSIGN_SVALUE_KEY(key, s);
+    }
+}
+cmod_DEFINE_EVAL(CB_ASSIGN_SVALUE_KEY, TREE_CLASSIFY(_assign_svalue_key))
+/*
+ * GCC-BUG!!! we use the inline instead!
+#undef CB_ASSIGN_SVALUE_KEY
+#define CB_ASSIGN_SVALUE_KEY(key, s)	CB_LOW_ASSIGN_SVALUE_KEY(key, s)
+#define CB_ASSIGN_SVALUE_KEY(_key, s) do {			\
+    if (THIS->decode_fun >= 0) {				\
+	CB_PUSH_KEY(_key);					\
+	apply_low(Pike_fp->current_object, THIS->decode_fun, 1);\
+	assign_svalue((s), Pike_sp-1);				\
+	pop_stack();						\
+    } else {							\
+	CB_LOW_ASSIGN_SVALUE_KEY(_key, s);			\
+    }								\
+} while(0)
+*/
+
diff --git a/src/post_modules/CritBit/tree_high.c b/src/post_modules/CritBit/tree_high.c
new file mode 100644
index 0000000000000000000000000000000000000000..5ee5f90468ae5a5285645eb62f61f1a33043a86c
--- /dev/null
+++ b/src/post_modules/CritBit/tree_high.c
@@ -0,0 +1,215 @@
+static inline void cb_print_key(struct string_builder *, const cb_key);
+static inline size_t _low_cb_check_node(cb_node_t node, const char *, int);
+
+#ifdef DEBUG_CHECKS
+# define cb_check_node(node)	do { _low_cb_check_node(node, \
+					    __FILE__, __LINE__); } while (0)
+#else
+# define cb_check_node(node)	do {} while(0)
+#endif
+
+#define CB_FATAL(x)	Pike_error x
+
+#include "tree_low.c"
+
+static inline void cb_debug_print_key(struct string_builder * buf, cb_key key) {
+    cb_size i;
+
+    for (i.chars = 0; i.chars < key.len.chars; i.chars++) {
+#ifdef CB_PRINT_CHAR
+	CB_PRINT_CHAR(buf, key.str, i.chars);
+#else
+	string_builder_sprintf(buf, "(%d, %d) b: ", i.chars, CB_WIDTH(s));
+
+	for (i.bits = 0; i.bits < CB_WIDTH(s); i.bits++) {
+	    string_builder_sprintf(buf, "%d", CB_GET_BIT(key.str, i));
+	}
+	string_builder_putchar(buf, ' ');
+#endif
+    }
+
+    /* string_builder_putchars(buf, ' ', 11-key.len.chars); */
+
+    if (key.len.bits) {
+	i.chars = key.len.chars;
+	i.bits = 0;
+
+	string_builder_sprintf(buf, "(%d, %d) b: ", key.len.chars, key.len.bits);
+
+	for (; CB_LT(i, key.len); CB_INC(i, 0, 1)) {
+	    string_builder_sprintf(buf, "%d", CB_GET_BIT(key.str, i));
+	}
+	string_builder_sprintf(buf, " %d", CB_GET_BIT(key.str, key.len));
+    }
+}
+
+static inline void cb_print_key(struct string_builder * buf, cb_key key) {
+    cb_size i;
+
+    for (i.chars = 0; i.chars < key.len.chars; i.chars++) {
+	for (i.bits = 0; i.bits < CB_WIDTH(s); i.bits++) {
+	    string_builder_putchar(buf, CB_GET_BIT(key.str, i) ? '1' : '0');
+	}
+    }
+
+    /* string_builder_putchars(buf, ' ', 11-key.len.chars); */
+
+    if (key.len.bits) {
+	i.chars = key.len.chars;
+	i.bits = 0;
+
+	for (; CB_LT(i, key.len); CB_INC(i, 0, 1)) {
+	    string_builder_putchar(buf, CB_GET_BIT(key.str, i) ? '1' : '0');
+	}
+    }
+}
+
+static inline void cb_print_node(struct string_builder * buf,
+				 cb_node_t node, int depth) {
+    string_builder_putchars(buf, ' ', depth);
+    string_builder_sprintf(buf, "%x #%lu (%d) --> ", node,
+			   node->size, node->value.type);
+    string_builder_putchars(buf, ' ', MAXIMUM(0, 15-depth));
+    cb_debug_print_key(buf, node->key);
+    if (CB_HAS_VALUE(node)) CB_PRINT_KEY(buf, node->key);
+    string_builder_putchar(buf, '\n');
+}
+
+static inline void cb_print_tree(struct string_builder *buf,
+				 cb_node_t tree, int depth) {
+    cb_print_node(buf, tree, depth);
+#if 0
+    char *spaces = (char*)malloc(depth+1);
+    char fmt[4096] = "%s %";
+    cb_size i;
+    int binary = 0;
+    memset(spaces, ' ', depth);
+    spaces[depth] = 0;
+    if (tree->key.len.bits) {
+	sprintf(fmt, "%%s-> %%.%ds %%0%dd \n",
+		tree->key.len.chars, tree->key.len.bits);
+	i.chars = tree->key.len.chars;
+	i.bits = 0;
+
+	for (; CB_LT(i, tree->key.len); CB_INC(i, 0, 1)) {
+	    binary *= 10;
+	    binary += CB_GET_BIT(tree->key.str, i);
+	}
+	printf(fmt, spaces, tree->key->str, binary);
+    } else {
+	sprintf(fmt, "%%s-> %%.%ds \n", tree->key.len.chars);
+	printf(fmt, spaces, tree->key->str);
+    }
+    free(spaces);
+#endif
+    if (CB_HAS_CHILD(tree, 0)) {
+	string_builder_putchar(buf, 'l');
+	cb_print_tree(buf, CB_CHILD(tree, 0), depth + 1);
+    }
+    if (CB_HAS_CHILD(tree, 1)) {
+	string_builder_putchar(buf, 'r');
+	cb_print_tree(buf, CB_CHILD(tree, 1), depth + 1);
+    }
+}
+
+static inline int cb_print_path(struct string_builder *buf, cb_node_t node,
+				cb_key key, cb_size size, int depth,
+				cb_node_t end) {
+    cb_print_node(buf, node, depth);
+
+    if (node == end) return 0;
+
+    size = cb_prefix_count(node->key.str, key.str,
+			   CB_MIN(node->key.len, key.len), size);
+
+    if (CB_S_EQ(size, key.len)) {
+	if (CB_S_EQ(size, node->key.len)) {
+	    return 1;
+	} else return 0;
+    }
+
+    if (CB_S_EQ(size, node->key.len)) {
+	size_t bit = CB_GET_BIT(key.str, size);
+	if (CB_HAS_CHILD(node, bit))
+	    return cb_print_path(buf, CB_CHILD(node, bit), key, size, depth+1,
+				 end);
+    }
+
+    return 0;
+}
+
+static inline void cb_check(cb_node_t node, cb_node_t last, char *issue) {
+#ifdef DEBUG_CHECKS
+    if (CB_LT(node->key.len, last->key.len)) {
+	printf("ERROR AT %s\n", issue);
+	cb_print_tree(last, 0);
+	printf("[%d, %d] is shorter than [%d, %d]\n", node->key.len.chars,
+	       node->key.len.bits, last->key.len.chars, last->key.len.bits);
+	return;
+    }
+#endif /* DEBUG_CHECKS */
+
+    if (CB_HAS_CHILD(node, 0)) cb_check(CB_CHILD(node, 0), node, issue);
+    if (CB_HAS_CHILD(node, 1)) cb_check(CB_CHILD(node, 1), node, issue);
+}
+
+static inline int cb_rec_check_parents(cb_node_t node) {
+    if (node == NULL) return 0;
+    if (CB_HAS_CHILD(node, 0)) {
+	if (CB_CHILD(node, 0)->parent != node) {
+	    printf("Damaged 0.\n");
+	    return 1;
+	}
+	if (cb_rec_check_parents(CB_CHILD(node, 0))) return 1;
+    }
+    if (CB_HAS_CHILD(node, 1)) {
+	if (CB_CHILD(node, 1)->parent != node) {
+	    printf("Damaged 1.\n");
+	    return 1;
+	}
+	if (cb_rec_check_parents(CB_CHILD(node, 1))) return 1;
+    }
+    return 0;
+}
+
+static inline void cb_aggregate_values(cb_node_t node,
+				       struct array * a, size_t start,
+				       size_t len) {
+    if (CB_HAS_VALUE(node))
+	CB_GET_VALUE(node, ITEM(a)+start++);
+    WALK_FORWARD(node, {
+	if (CB_HAS_VALUE(_)) CB_GET_VALUE(_, ITEM(a)+start++);
+    });
+}
+
+static inline size_t _low_cb_check_node(cb_node_t node,
+					const char *file, int line) {
+    size_t len = 0;
+    if (CB_HAS_CHILD(node, 0)) {
+	if (CB_GET_BIT(CB_CHILD(node, 0)->key.str, node->key.len) != 0) {
+	    Pike_error("%s:%d EVIL DOER FOUND.\n", file, line);
+	}
+	if (CB_LE(CB_CHILD(node, 0)->key.len, node->key.len)) {
+	    Pike_error("%s:%d Child is shorter than parent.\n", file, line);
+	}
+	len += _low_cb_check_node(CB_CHILD(node, 0), file, line);
+    }
+    if (CB_HAS_CHILD(node, 1)) {
+	if (CB_GET_BIT(CB_CHILD(node, 1)->key.str, node->key.len) != 1) {
+	    Pike_error("%s:%d It was the gardener! \n", file, line);
+	}
+	if (CB_LE(CB_CHILD(node, 1)->key.len, node->key.len)) {
+	    Pike_error("%s:%d Child is shorter than parent.\n", file, line);
+	}
+	len += _low_cb_check_node(CB_CHILD(node, 1), file, line);
+    }
+
+    if (len + CB_HAS_VALUE(node) != node->size) {
+	/* Pike_error("Found node with wrong size. is: %p\n", node); */
+	Pike_error("%s:%d Found node with wrong size. is: 0x%08X\n",
+		   file, line, node);
+    }
+
+    return node->size;
+}
+
diff --git a/src/post_modules/CritBit/tree_low.c b/src/post_modules/CritBit/tree_low.c
new file mode 100644
index 0000000000000000000000000000000000000000..09afd9497cd3b58adf1c101a519a3d622b4aab45
--- /dev/null
+++ b/src/post_modules/CritBit/tree_low.c
@@ -0,0 +1,581 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifndef CB_NODE_ALLOC
+# define CB_NODE_ALLOC()	((cb_node_t)malloc(sizeof(cb_node)))
+#endif
+#ifndef CB_NODE_FREE
+# define CB_NODE_FREE(p)	free(p)
+#endif
+
+#ifndef HAS___BUILTIN_EXPECT
+# define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x)	__builtin_expect((x), 1)
+#define unlikely(x)	__builtin_expect((x), 0)
+
+#ifndef cb_check_node
+# define cb_check_node(node)	do {} while(0)
+#endif
+
+#ifndef MAX
+#define MAX(a, b)	((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef CB_FATAL
+# define CB_FATAL(x)	(printf x, exit(4))
+#endif
+
+#ifndef CB_ERROR
+# define CB_ERROR	CB_FATAL
+#endif
+
+#ifndef cb_prefix_count
+# define cb_prefix_count		cb_prefix_count_fallback
+#else
+# undef cb_prefix_count
+# define cb_prefix_count		cb_prefix_count_fallback
+#endif
+
+#ifndef CB_SOURCE
+# define CB_SOURCE
+#endif
+
+static inline cb_node_t cb_zap_node(cb_node_t);
+static inline cb_node_t cb_node_from_string(const cb_key, const cb_value *);
+
+
+static inline cb_key CB_KEY_FROM_STRING(const cb_string string) {
+    cb_key key;
+    /* printf("key from string: %p (%d, %d)\n",
+      string, key.len.chars, key.len.bits); */
+    key.str = string;
+    key.len.chars = CB_LENGTH(string);
+    key.len.bits = 0;
+    return key;
+}
+
+static inline cb_size cb_prefix_count_fallback(const cb_string s1,
+					       const cb_string s2,
+					       const cb_size len,
+					       cb_size start) {
+    size_t i;
+    uint32_t width = MAX(CB_WIDTH(s1), CB_WIDTH(s2));
+
+    for (i = start.chars; i < len.chars; i++) {
+	uint32_t diffbit = CB_COUNT_PREFIX(s1, s2, i);
+	start.bits = 0;
+
+	if (diffbit < width) { /*  are different */
+#ifdef ANNOY_DEBUG
+	    fprintf(stderr, "diff in bit %d (byte %d) %d\n", diffbit, i, __LINE__);
+#endif
+	    start.chars = i;
+	    start.bits = diffbit;
+	    return start;
+	}
+    }
+
+    if (len.bits > start.bits) {
+	uint32_t diffbit = CB_COUNT_PREFIX(s1, s2, len.chars);
+	if (diffbit < len.bits) { /*  are different */
+#ifdef ANNOY_DEBUG
+	    fprintf(stderr, "diff in bit %d (byte %d) %d\n", diffbit, len.chars, __LINE__);
+#endif
+	    start.chars = len.chars;
+	    start.bits = diffbit;
+	    return start;
+	} else return len;
+    }
+
+    return len;
+}
+
+
+static inline cb_node_t node_init() {
+    cb_node_t tree;
+
+    tree = CB_NODE_ALLOC();
+    memset(tree, 0, sizeof(cb_node));
+    CB_INIT_VALUE(tree);
+
+    return tree;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_get_range(const cb_node_t tree, const cb_key a,
+				     const cb_key b) {
+    cb_node_t node = cb_index(tree, a);
+    cb_node_t end = cb_index(tree, b);
+    /* printf("start: %p, stop: %p in line %d\n", node, end, __LINE__); */
+    if (!node) node = cb_find_next(tree, a);
+    /* printf("start: %p, stop: %p in line %d\n", node, end, __LINE__); */
+    if (node) {
+	cb_node_t ntree;
+
+	if ((end && !CB_HAS_VALUE(end)) || (end = cb_find_next(tree, b))) {
+    /* printf("start: %p, stop: %p in line %d\n", node, end, __LINE__); */
+	    if (end == node) return NULL;
+
+	    WALK_BACKWARD(end, {
+		if (CB_HAS_VALUE(_)) {
+		    if (_ == node) return cb_node_from_string(node->key, &node->value);
+		    break;
+		}
+		if (_ == node) return NULL;
+	    });
+    /* printf("start: %p, stop: %p in line %d\n", node, end, __LINE__); */
+	}
+	if (node && !CB_HAS_VALUE(node)) {
+	    if (end == node) return NULL;
+	    WALK_FORWARD(node, {
+		if (_ == end) return NULL;
+		if (CB_HAS_VALUE(_)) break;
+	    });
+	}
+    /* printf("start: %p, stop: %p in line %d\n", node, end, __LINE__); */
+	ntree = cb_node_from_string(node->key, &node->value);
+
+	if (node != end) WALK_FORWARD(node, {
+	    if (CB_HAS_VALUE(_)) {
+		/* printf("adding %p\n", _); */
+		cb_insert(ntree, _->key, &node->value);
+		if (_ == end) break;
+	    }
+	});
+
+	/* printf("new range has %d members.\n", ntree->size); */
+	return ntree;
+    }
+    return NULL;
+}
+
+static inline cb_node_t cb_node_from_string(const cb_key s,
+					    const cb_value * val) {
+    cb_node_t node = node_init();
+    CB_SET_KEY(node, s);
+    node->size = 1;
+    CB_SET_VALUE(node, val);
+
+#ifdef DEBUG_CHECKS
+    if (!CB_HAS_VALUE(node))
+	printf("culprit here. %d\n", __LINE__);
+#endif
+
+    return node;
+}
+
+static inline cb_node_t cb_clone_node(const cb_node_t node) {
+    cb_node_t nnode = CB_NODE_ALLOC();
+
+    memcpy(nnode, node, sizeof(cb_node));
+    CB_ADD_KEY_REF(node->key);
+    CB_INIT_VALUE(node);
+    CB_SET_CHILD(nnode, 0, CB_CHILD(nnode, 0));
+    CB_SET_CHILD(nnode, 1, CB_CHILD(nnode, 1));
+    CB_CHILD(node, 0) = NULL;
+    CB_CHILD(node, 1) = NULL;
+
+    return nnode;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_copy_tree(const cb_node_t from) {
+    cb_node_t new;
+
+    if (!from) return NULL;
+
+    new = CB_NODE_ALLOC();
+
+    memcpy(new, from, sizeof(cb_node));
+    new->parent = NULL;
+    CB_ADD_KEY_REF(new->key);
+    CB_GET_VALUE(from, &new->value);
+
+    if (CB_HAS_CHILD(new, 0)) CB_SET_CHILD(new, 0,
+					   cb_copy_tree(CB_CHILD(new, 0)));
+    if (CB_HAS_CHILD(new, 1)) CB_SET_CHILD(new, 1,
+					   cb_copy_tree(CB_CHILD(new, 1)));
+    return new;
+}
+
+static inline cb_node_t cb_free_node(cb_node_t node) {
+    if (!node) {
+	CB_FATAL(("double free!\n"));
+    }
+    if (CB_HAS_CHILD(node, 0)) {
+	CB_CHILD(node, 0) = cb_free_node(CB_CHILD(node, 0));
+    }
+    if (CB_HAS_CHILD(node, 1)) {
+	CB_CHILD(node, 1) = cb_free_node(CB_CHILD(node, 1));
+    }
+    return cb_zap_node(node);
+}
+
+static inline cb_node_t cb_zap_node(cb_node_t node) {
+    CB_FREE_KEY(node->key);
+    CB_RM_VALUE(node);
+    CB_NODE_FREE(node);
+
+    return NULL;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_first(cb_node_t tree) {
+    while (tree && !CB_HAS_VALUE(tree)) { tree = CB_CHILD(tree, 0); };
+
+    return tree;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_last(cb_node_t tree) {
+    while (1) {
+	if (CB_HAS_CHILD(tree, 1)) tree = CB_CHILD(tree, 1);
+	else if (CB_HAS_CHILD(tree, 0)) tree = CB_CHILD(tree, 0);
+	else break;
+    }
+    return tree;
+}
+
+CB_STATIC CB_INLINE size_t cb_get_depth(cb_node_t node) {
+    size_t a = 0, b = 0, len = 1;
+
+    if (CB_HAS_CHILD(node, 0)) {
+	a = cb_get_depth(CB_CHILD(node, 0));
+    }
+
+    if (CB_HAS_CHILD(node, 1)) {
+	b = cb_get_depth(CB_CHILD(node, 1));
+    }
+
+    return len + MAX(b, a);
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_subtree_prefix(cb_node_t node, cb_key key) {
+    cb_size size;
+    uint32_t bit;
+    size = cb_prefix_count(node->key.str, key.str,
+			   CB_MIN(node->key.len, key.len), size);
+
+    if (CB_S_EQ(size, key.len)) { /*  key is substring */
+	return node;
+    }
+
+    bit = CB_GET_BIT(key.str, size);
+
+    if (CB_HAS_CHILD(node, bit)) {
+	return cb_subtree_prefix(CB_CHILD(node, bit), key);
+    }
+
+    return NULL;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_delete(cb_node_t tree, const cb_key key,
+				  cb_value * val) {
+    cb_node_t node = cb_index(tree, key);
+
+    if (node && CB_HAS_VALUE(node)) {
+	uint32_t bit;
+	cb_node_t t;
+	if (val) CB_GET_VALUE(node, val);
+
+	CB_RM_VALUE(node);
+	node->size--;
+
+	if (node == tree) goto PARENT;
+
+	if (!CB_HAS_PARENT(node)) CB_ERROR(("broken tree\n"));
+
+	t = node;
+	WALK_UP(t, bit, {
+	    _->size--;
+	});
+
+	cb_check_node(tree);
+
+	do {
+	    switch (CB_HAS_CHILD(node, 0) + CB_HAS_CHILD(node, 1)) {
+	    case 2: return tree;
+	    case 1:
+		CB_SET_CHILD(CB_PARENT(node), CB_BIT(node),
+			     CB_CHILD(node, CB_HAS_CHILD(node, 1)));
+		break;
+	    case 0:
+		CB_SET_CHILD(CB_PARENT(node), CB_BIT(node), NULL);
+		break;
+	    }
+	    t = CB_PARENT(node);
+	    cb_zap_node(node);
+	    /*  do some deletion */
+	    node = t;
+	} while (CB_HAS_PARENT(node) && !CB_HAS_VALUE(node));
+
+PARENT:
+	cb_check_node(tree);
+	if (node == tree && !CB_HAS_VALUE(node)) {
+	    switch (CB_HAS_CHILD(node, 0) + CB_HAS_CHILD(node, 1)) {
+	    case 2: return tree;
+	    case 1:
+		t = CB_CHILD(node, CB_HAS_CHILD(node, 1));
+		cb_zap_node(tree);
+		cb_check_node(t);
+		t->parent = NULL;
+		return t;
+	    case 0:
+		cb_zap_node(tree);
+		return NULL;
+	    }
+	}
+
+    }
+
+    cb_check_node(tree);
+    return tree;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_index(const cb_node_t tree, const cb_key key) {
+    cb_node_t node = tree;
+    if (tree) cb_check_node(tree);
+
+    while (node) {
+	if (CB_LT(node->key.len, key.len)) {
+	    uint32_t bit = CB_GET_BIT(key.str, node->key.len);
+
+	    if (CB_HAS_CHILD(node, bit)) {
+		node = CB_CHILD(node, bit);
+		continue;
+	    }
+	} else if (CB_LT(key.len, node->key.len)) {
+	    return NULL;
+	} else if (CB_KEY_EQ(node->key, key)) {
+	    cb_check_node(tree);
+	    return node;
+	}
+
+	break;
+    }
+
+    if (tree) cb_check_node(tree);
+    return NULL;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_next(const cb_node_t tree, const cb_key key) {
+    cb_size size;
+    size_t bit;
+    cb_node_t node;
+    size.bits = size.chars = 0;
+
+    /*  index is cheap. also in many cases its quite likely that we */
+    /*  hit. */
+    node = cb_index(tree, key);
+
+    if (node) {
+	WALK_FORWARD(node, {
+	    if (CB_HAS_VALUE(_)) break;
+	});
+	return node;
+    }
+
+    node = tree;
+
+    while (1) {
+#ifdef ANNOY_DEBUG
+	printf("prefix: (%d,%d)\n", key.len.chars, key.len.bits);
+	cb_size min = CB_MIN(node->key.len, key.len);
+	printf("(%p) start: (%d,%d) stop: (%d,%d) ", node, size.chars,
+	       size.bits, min.chars, min.bits);
+#endif
+	size = cb_prefix_count(node->key.str, key.str,
+			       CB_MIN(node->key.len, key.len), size);
+#ifdef ANNOY_DEBUG
+	printf("prefix: (%d,%d)\n", size.chars, size.bits);
+#endif
+
+	if (CB_S_EQ(size, key.len)) { /*  key is substring */
+	    if (!CB_S_EQ(size, node->key.len)) { /*  key is not equal */
+		if (CB_HAS_VALUE(node))
+		    return node; /*  key is smaller  */
+	    } else WALK_FORWARD(node, {
+		if (CB_HAS_VALUE(_)) return _;
+	    });
+	}
+
+	bit = CB_GET_BIT(key.str, size);
+
+	/* printf("bit is %u\n", bit); */
+
+	if (CB_S_EQ(size, node->key.len)) { /*  node is substring */
+	    if (CB_HAS_CHILD(node, bit)) {
+		node = CB_CHILD(node, bit);
+		continue;
+	    }
+	    if (!bit && CB_HAS_CHILD(node, 1)) {
+		WALK_FORWARD(node, {
+		    if (CB_HAS_VALUE(_)) return _;
+		});
+	    }
+
+	    return NULL;
+	}
+
+	if (!bit) break;
+
+	WALK_UP(node, bit, {
+	    if (!bit && CB_HAS_CHILD(_, 1)) {
+		_ = CB_CHILD(_, 1);
+		break;
+	    }
+	});
+	if (node == tree) return NULL;
+	break;
+    }
+
+    if (node && !CB_HAS_VALUE(node))
+	WALK_FORWARD(node, {
+	    if (CB_HAS_VALUE(_)) break;
+	});
+    return node;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_ne(const cb_node_t tree, const cb_key key) {
+    cb_node_t ne = cb_index(tree, key);
+    if (!ne) ne = cb_find_next(tree, key);
+    return ne;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_get_nth(const cb_node_t tree, size_t n) {
+    cb_node_t node = tree;
+    size_t ln;
+
+    while (node) {
+	if (n >= node->size) return NULL;
+
+	if (n == 0) return cb_find_first(node);
+	else if (n == node->size - 1) return cb_find_last(node);
+
+	if (CB_HAS_VALUE(node)) n--;
+
+	if (CB_HAS_CHILD(node, 0)) {
+	    ln = CB_CHILD(node, 0)->size;
+	    if (n < ln) {
+		node = CB_CHILD(node, 0);
+		continue;
+	    }
+	    n -= ln;
+	}
+
+	node = CB_CHILD(node, 1);
+    }
+
+    return NULL;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_previous(const cb_node_t tree,
+					 const cb_key key) {
+    cb_node_t node = cb_index(tree, key);
+    if (!node) node = cb_find_next(tree, key);
+    if (!node) return cb_find_last(tree);
+    if (node) WALK_BACKWARD(node, {
+	if (CB_HAS_VALUE(_)) break;
+    });
+    return node;
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_find_le(const cb_node_t tree, const cb_key key) {
+    cb_node_t ne = cb_index(tree, key);
+    if (!ne) ne = cb_find_previous(tree, key);
+    return ne;
+}
+
+static inline int cb_low_insert(cb_node_t node, const cb_key key, const cb_value *val) {
+    cb_size size;
+    size.bits = 0;
+    size.chars = 0;
+
+    while (1) {
+	cb_node_t new;
+	size_t bit;
+
+	size = cb_prefix_count(node->key.str, key.str,
+			       CB_MIN(node->key.len, key.len), size);
+
+	if (CB_S_EQ(size, key.len)) {
+	    cb_node_t klon;
+
+	    if (CB_S_EQ(size, node->key.len)) {
+		uint32_t bit;
+
+		klon = node;
+		if (CB_HAS_VALUE(klon))
+		    WALK_UP(klon, bit, {
+			_->size--;
+		    });
+		else node->size++;
+		/*  remove ref */
+		/* free_svalue(&node->value); */
+		CB_SET_KEY(node, key);
+		CB_SET_VALUE(node, val);
+
+		return 0;
+	    }
+	    /*  overwrite not inplace by new key node */
+	    klon = cb_clone_node(node);
+	    node->size++;
+	    bit = CB_GET_BIT(node->key.str, size);
+
+	    /*  add ref for value */
+	    CB_SET_KEY(node, key);
+	    CB_SET_VALUE(node, val);
+
+	    node->key.len = size;
+	    CB_SET_CHILD(node, bit, klon);
+	    CB_SET_CHILD(node, !bit, NULL);
+
+	    return 1;
+	}
+
+	if (likely(CB_S_EQ(size, node->key.len))) {
+	    node->size++;
+	    bit = CB_GET_BIT(key.str, size);
+	    if (CB_HAS_CHILD(node, bit)) {
+		node = CB_CHILD(node, bit);
+		continue;
+	    }
+	    CB_SET_CHILD(node, bit, cb_node_from_string(key, val));
+	    return 1;
+	}
+
+	new = cb_clone_node(node);
+	node->size++;
+#ifdef DEBUG_CHECKS
+	if (CB_LT(CB_MIN(node->key.len, key.len), size)) {
+	    CB_ERROR(("fooo\n"));
+	}
+	if (CB_LT(node->key.len, size)) {
+	    CB_ERROR(("enlarging node [%d, %d] vs [%d, %d]\n", size.chars,
+		      size.bits, node->key.len.chars, node->key.len.bits));
+	}
+#endif /* DEBUG_CHECKS */
+	node->key.len = size;
+	bit = CB_GET_BIT(key.str, size);
+	CB_SET_CHILD(node, bit, cb_node_from_string(key, val));
+	CB_SET_CHILD(node, !bit, new);
+	CB_RM_VALUE(node); /*  do not free here, clone does take ref */
+
+	return 1;
+    }
+}
+
+CB_STATIC CB_INLINE cb_node_t cb_insert(cb_node_t tree, const cb_key key,
+				  const cb_value *val) {
+
+	if (!tree) {
+	    return tree = cb_node_from_string(key, val);
+	}
+
+	cb_check_node(tree);
+
+	cb_low_insert(tree, key, val);
+
+	cb_check_node(tree);
+
+	return tree;
+}
diff --git a/src/post_modules/CritBit/tree_low.h b/src/post_modules/CritBit/tree_low.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f8e8c6b7ee7e933a9b404d9aae1fbf6b12eaed9
--- /dev/null
+++ b/src/post_modules/CritBit/tree_low.h
@@ -0,0 +1,223 @@
+#ifndef _TREE_LOW_H_
+#define _TREE_LOW_H_
+
+#include <sys/types.h>
+#include "gc.h"
+#include "dmalloc.h"
+
+#define CB_PRINTCHAR(buf, s, n)	do { \
+    cb_size j; 			     \
+    j.chars = (size_t)(n); j.bits = 0;		\
+    for (; j.bits < 32; j.bits++) {		\
+	(buf)[j.bits] = (CB_GET_BIT(s, j) ? '1' : '0'); \
+    }\
+} while (0)
+
+#ifdef CB_SOURCE
+
+#ifndef CB_LE
+# define CB_LE(a, b) ((a).chars < (b).chars || ((a).chars == (b).chars \
+						&& (a).bits <= (b).bits))
+# define CB_LT(a, b) ((a).chars < (b).chars || ((a).chars == (b).chars \
+						&& (a).bits < (b).bits))
+# define CB_S_EQ(a, b)	((a).chars == (b).chars && (a).bits == (b).bits)
+#endif
+#define CB_INC(a, c, b) ((a).chars += (c), (a).bits += (b))
+#define CB_MIN(a, b)	(CB_LE((a), (b)) ? a : b)
+#define CB_MAX(a, b)	(CB_LE((b), (a)) ? a : b)
+
+#define CB_HAS_PARENT(node)	(!!(node)->parent)
+#define CB_PARENT(node)	((node)->parent)
+#define CB_BIT(node)		((node) && 		\
+				 CB_HAS_PARENT(node) ? 	\
+				 (CB_CHILD(CB_PARENT(node), 1) == (node)) \
+				  : (CB_FATAL((\
+			"CB_BIT does not make any sense without parent.\n" \
+					     )), -1))
+#define CB_HAS_CHILD(node, bit)	(!!(node)->childs[!!(bit)])
+#define CB_SET_CHILD(__parent, __bit, __child) do {	\
+    cb_node_t _p = (__parent);				\
+    cb_node_t _child = (__child);			\
+    uint32_t _bit = (__bit);				\
+    if (_child) _child->parent = _p;			\
+    CB_CHILD(_p, _bit) = _child;			\
+} while(0)
+#define CB_CHILD(node, bit)	((node)->childs[!!(bit)])
+#define CB_SHORT(a, b)	(CB_LE((a)->len, (b)->len) ? (a) : (b))
+
+#define WALK_UP(node, bit, CODE) do { cb_node_t __ = (node);	do {	\
+    cb_node_t _ = __;	    		    				\
+    /*printf("one step up: %d %d %d\n", CB_HAS_PARENT(_),		\
+       CB_HAS_CHILD(_, 0), CB_HAS_CHILD(_, 1));*/			\
+    if (CB_HAS_PARENT(_)) {						\
+	bit = CB_BIT(_);						\
+	_ = CB_PARENT(_);						\
+	while (1) { if (1) CODE if (!CB_HAS_PARENT(_)) break;		\
+	    bit = CB_BIT(_); _ = CB_PARENT(_); }			\
+	__ = _;								\
+    }\
+} while(0); (node) = __; } while(0)
+
+#define WALK_FORWARD(node, CODE) do { cb_node_t __ = (node); do {	\
+    cb_node_t _ = __;		    		    			\
+    while (1) {								\
+	/*printf("one step forward: %d %d %d\n", CB_HAS_PARENT(_),
+	   CB_HAS_CHILD(_, 0), CB_HAS_CHILD(_, 1));*/			\
+	if (CB_HAS_CHILD(_, 0)) { _ = CB_CHILD(_, 0); }			\
+	else if (CB_HAS_CHILD(_, 1)) { _ = CB_CHILD(_, 1); }		\
+	else {								\
+	    uint32_t hit = 0, oldbit = 3; 				\
+	    WALK_UP(_, oldbit, { 					\
+		/*printf("one step up: %d\n", oldbit);			\
+	printf("one step forward: %d %d %d\n", CB_HAS_PARENT(_),
+	CB_HAS_CHILD(_, 0), CB_HAS_CHILD(_, 1));*/			\
+		if (!oldbit && CB_HAS_CHILD(_, 1)) { 			\
+		    hit = 1;_ = CB_CHILD(_, 1); break;			\
+		}  							\
+	    });								\
+	    if (oldbit == 3 || !hit) { _ = NULL; break;	}		\
+	}								\
+	if (1) CODE							\
+    }									\
+    __ = _;								\
+} while(0); (node) = __; } while(0)
+#define WALK_BACKWARD(node, CODE) do { cb_node_t __ = (node); do {		\
+    cb_node_t _ = __;		    		    				\
+    while (1) {									\
+	/*printf("one step forward: %d %d %d\n",
+	 * CB_HAS_PARENT(_), CB_HAS_CHILD(_, 0), CB_HAS_CHILD(_, 1));*/		\
+	if (CB_HAS_PARENT(_)) {							\
+	    uint32_t bit = CB_BIT(_);						\
+	    _ = CB_PARENT(_);							\
+	    if (bit && CB_HAS_CHILD(_, 0)) {					\
+		_ = CB_CHILD(_, 0);						\
+		while (1) {							\
+		    if (CB_HAS_CHILD(_, 1)) { _ = CB_CHILD(_, 1); continue; }	\
+		    if (CB_HAS_CHILD(_, 0)) { _ = CB_CHILD(_, 0); continue; }	\
+		    break;							\
+		}								\
+	    }									\
+	} else { _ = NULL; break; }						\
+	if (1) CODE								\
+    }										\
+    __ = _;									\
+} while(0); (node) = __; } while(0)
+
+#endif /* CB_SOURCE */
+
+#ifdef cb_node
+# undef cb_node
+#endif
+#define cb_node		CB_NAME(node)
+
+#ifdef cb_key
+# undef cb_key
+#endif
+#define cb_key		CB_NAME(key)
+
+#ifdef cb_node_t
+# undef cb_node_t
+#endif
+#define cb_node_t	CB_TYPE(node)
+
+#ifdef cb_find_ne
+# undef cb_find_ne
+#endif
+#define cb_find_ne	CB_NAME(find_ne)
+
+#ifdef cb_get_nth
+# undef cb_get_nth
+#endif
+#define cb_get_nth	CB_NAME(get_nth)
+
+#ifdef cb_find_previous
+# undef cb_find_previous
+#endif
+#define cb_find_previous	CB_NAME(find_previous)
+
+#ifdef cb_find_le
+# undef cb_find_le
+#endif
+#define cb_find_le	CB_NAME(find_le)
+
+#ifdef cb_subtree_prefix
+# undef cb_subtree_prefix
+#endif
+#define cb_subtree_prefix	CB_NAME(subtree_prefix)
+
+#ifdef cb_get_depth
+# undef cb_get_depth
+#endif
+#define cb_get_depth	CB_NAME(get_depth)
+
+#ifdef cb_find_last
+# undef cb_find_last
+#endif
+#define cb_find_last	CB_NAME(find_last)
+
+#ifdef cb_find_first
+# undef cb_find_first
+#endif
+#define cb_find_first	CB_NAME(find_first)
+
+#ifdef cb_copy_tree
+# undef cb_copy_tree
+#endif
+#define cb_copy_tree	CB_NAME(copy_tree)
+
+#ifdef cb_get_range
+# undef cb_get_range
+#endif
+#define cb_get_range	CB_NAME(get_range)
+
+#ifdef cb_index
+# undef cb_index
+#endif
+#define cb_index	CB_NAME(index)
+
+#ifdef cb_find_next
+# undef cb_find_next
+#endif
+#define cb_find_next	CB_NAME(find_next)
+
+#ifdef cb_insert
+# undef cb_insert
+#endif
+#define cb_insert	CB_NAME(insert)
+
+#endif /* TREE_LOW_H */
+
+typedef struct cb_key {
+    cb_string str;
+    cb_size len;
+} cb_key;
+
+typedef struct cb_node {
+    cb_key key;
+    cb_value value;
+    size_t size; /* size of the subtree */
+    struct cb_node * parent;
+    struct cb_node * childs[2];
+} * cb_node_t;
+
+typedef struct cb_node cb_node;
+
+CB_STATIC CB_INLINE cb_node_t cb_insert(const cb_node_t, const cb_key,
+					const cb_value *);
+CB_STATIC CB_INLINE cb_node_t cb_find_next(cb_node_t, const cb_key);
+CB_STATIC CB_INLINE cb_node_t cb_index(const cb_node_t tree, const cb_key);
+CB_STATIC CB_INLINE cb_node_t cb_get_range(const cb_node_t tree,
+					   const cb_key a, const cb_key b);
+CB_STATIC CB_INLINE cb_node_t cb_copy_tree(const cb_node_t from);
+CB_STATIC CB_INLINE cb_node_t cb_find_first(cb_node_t tree);
+CB_STATIC CB_INLINE cb_node_t cb_find_last(cb_node_t tree);
+CB_STATIC CB_INLINE size_t cb_get_depth(cb_node_t node);
+CB_STATIC CB_INLINE cb_node_t cb_subtree_prefix(cb_node_t node, cb_key key);
+CB_STATIC CB_INLINE cb_node_t cb_find_le(const cb_node_t tree,
+					 const cb_key key);
+CB_STATIC CB_INLINE cb_node_t cb_find_previous(const cb_node_t tree,
+					       const cb_key key);
+CB_STATIC CB_INLINE cb_node_t cb_get_nth(const cb_node_t tree, size_t n);
+CB_STATIC CB_INLINE cb_node_t cb_find_ne(const cb_node_t tree,
+					 const cb_key key);
+
diff --git a/src/post_modules/CritBit/tree_source.H b/src/post_modules/CritBit/tree_source.H
new file mode 100644
index 0000000000000000000000000000000000000000..88b5228191054b8ddb4b888c451ec22068a18cd3
--- /dev/null
+++ b/src/post_modules/CritBit/tree_source.H
@@ -0,0 +1,683 @@
+    INIT {
+	THIS->tree = NULL;
+	THIS->encode_fun = find_identifier
+		("encode_key", Pike_fp->current_object->prog);
+	THIS->decode_fun=find_identifier
+		("decode_key", Pike_fp->current_object->prog);
+	THIS->copy_fun = find_identifier ("copy", Pike_fp->current_object->prog);
+	THIS->insert_fun = find_identifier ("`[]=", Pike_fp->current_object->prog);
+	if (find_identifier("copy", TREE_CLASSIFY(_program)) == THIS->copy_fun) {
+	    THIS->copy_fun = -1;
+	}
+
+	if (find_identifier("`[]=", TREE_CLASSIFY(_program)) == THIS->insert_fun) {
+	    THIS->copy_fun = -1;
+	}
+    }
+static inline void TREE_CLASSIFY(_copy_node)(struct object *o, cb_node_t node) {
+    if (THIS->copy_fun != -1 && THIS->insert_fun != -1) {
+	CB_PUSH_TRANSFORM_KEY(node->key);
+	CB_PUSH_VALUE(node->value);
+	apply_low(o, THIS->insert_fun, 2);
+	pop_stack();
+    } else cmod_OBJ2_TREE(o)->tree =
+		cb_insert(cmod_OBJ2_TREE(o)->tree, node->key, &node->value);
+}
+
+static inline void TREE_CLASSIFY(_copy_tree)(struct object *o, cb_node_t node) {
+	if (THIS->copy_fun != -1 && THIS->insert_fun != -1) {
+	    WALK_FORWARD(node, {
+		if (CB_HAS_VALUE(_)) {
+		    CB_PUSH_TRANSFORM_KEY(node->key);
+		    push_svalue(&node->value);
+		    apply_low(o, THIS->insert_fun, 2);
+		    pop_stack();
+		}
+	    });
+	} else cmod_OBJ2_TREE(o)->tree = cb_copy_tree(node);
+}
+
+static inline struct object *
+TREE_CLASSIFY(_clone_object)(const struct object *o) {
+    struct object * t = NULL;
+    if (THIS->copy_fun != -1) {
+	apply_low(o, THIS->copy_fun, 0);
+	if (!Pike_sp[-1].type != PIKE_T_OBJECT)
+	    Pike_error("clone() is supposed to return an object.\n");
+	t = Pike_sp[-1].u.object;
+	add_ref(t);
+	pop_stack();
+    } else {
+	t = clone_object(Pike_fp->current_object->prog, 0);
+	if (cmod_OBJ2_TREE(o)->tree)
+	    cmod_OBJ2_TREE(t)->tree = cb_copy_tree(cmod_OBJ2_TREE(o)->tree);
+    }
+    return t;
+}
+
+cmod_DEFINE_EVAL(CLONE_OBJECT, TREE_CLASSIFY(_clone_object))
+
+cmod_DEFINE_EVAL(COPY_TREE, TREE_CLASSIFY(_copy_tree))
+
+cmod_DEFINE_EVAL(COPY_NODE, TREE_CLASSIFY(_copy_node))
+
+    /*! @decl mixed _m_delete(mixed key)
+     *! m_delete callback.
+     */
+    PIKEFUN mixed _m_delete(mixed key) {
+	size_t size, oldsize;
+	cb_key k;
+
+	k = CB_KEY_FROM_SVALUE(key);
+
+	oldsize = (THIS->tree) ? THIS->tree->size : 0;
+	if (oldsize) {
+	    THIS->tree = cb_delete(THIS->tree, k, Pike_sp++);
+	    size = (THIS->tree) ? THIS->tree->size : 0;
+	    if (size < oldsize) {
+		THIS->rev++;
+		stack_pop_keep_top();
+		return;
+	    }
+	}
+	pop_stack();
+	push_undefined();
+    }
+
+    PIKEFUN int check_parenting_skills() {
+	push_int(cb_rec_check_parents(THIS->tree));
+    }
+
+    DOCSTART() @decl void create(array|mapping|void o)
+     *! Create a tree_class from o.
+    DOCEND()
+    PIKEFUN void create (array|mapping|void o)
+      optflags OPT_TRY_OPTIMIZE;
+    {
+
+	if (args == 1) {
+	    switch (o->type) {
+	    case PIKE_T_MAPPING: {
+		struct keypair *k;
+		INT32 e;
+		struct mapping_data *md = o->u.mapping->data;
+
+		NEW_MAPPING_LOOP(md) {
+		    cb_key key = CB_KEY_FROM_SVALUE(&k->ind);
+		    THIS->tree = cb_insert(THIS->tree, key, &k->val);
+		}
+		return;
+	    }
+	    case PIKE_T_ARRAY: {
+		INT32 i;
+
+		if (o->u.array->size & 1) goto ARG_ERROR;
+
+		for (i = 0; i < o->u.array->size; i+=2) {
+		    cb_key key = CB_KEY_FROM_SVALUE(ITEM(o->u.array)+i);
+		    THIS->tree = cb_insert(THIS->tree, key, ITEM(o->u.array)+i+1);
+		}
+		return;
+	    }
+	    }
+ARG_ERROR:
+	    SIMPLE_BAD_ARG_ERROR("create", 1, "mapping(" cmod_STRFY_EVAL(key_ptype) ":mixed)|array");
+	}
+    }
+
+DOCSTART() @decl int _sizeof()
+ *! Gives the number of entries in the @[tree_class].
+DOCEND()
+    PIKEFUN int _sizeof() {
+	push_int(THIS->tree ? THIS->tree->size : 0);
+    }
+
+DOCSTART() @decl array _indices()
+ *! Returns a sorted array of indices of the @[tree_class].
+DOCEND()
+    PIKEFUN array _indices() {
+	size_t size = THIS->tree ? THIS->tree->size : 0;
+	if (size) {
+	    size_t start = 0;
+	    struct svalue * s;
+	    cb_key k;
+	    cb_node_t node = THIS->tree;
+	    struct array * a = allocate_array_no_init(size, 0);
+	    push_array(a);
+	    if (CB_HAS_VALUE(node)) {
+		s = ITEM(a)+start;
+		s->type = T_VOID;
+		k = node->key;
+		CB_ASSIGN_SVALUE_KEY(k, s);
+		start ++;
+	    }
+	    WALK_FORWARD(node, {
+		if (CB_HAS_VALUE(_)) {
+		    if (start == size) {
+			Pike_error("super bad!! tree has hidden entries.\n");
+		    }
+		    s = ITEM(a)+start;
+		    s->type = T_VOID;
+		    CB_ASSIGN_SVALUE_KEY(_->key, s);
+		    start ++;
+		}
+	    });
+	    return;
+	}
+	ref_push_array(&empty_array);
+    }
+
+DOCSTART() @decl array _values()
+ *! Returns an array of values of the @[tree_class] object. The returned
+ *! array matches
+ *! @[_indices] so that @expr{mkmapping(indices(tree), values(tree))@} would
+ *! create a mapping with the same contents as this @[tree_class].
+DOCEND()
+    PIKEFUN array _values() {
+	size_t size = THIS->tree ? THIS->tree->size : 0;
+	if (size) {
+	    struct array * a = allocate_array_no_init(size, 0);
+	    push_array(a);
+	    cb_aggregate_values(THIS->tree, a, 0, size);
+	    return;
+	}
+	ref_push_array(&empty_array);
+    }
+
+    /*! @decl mixed `[]=(mixed key, mixed val) */
+    PIKEFUN mixed `[]=(mixed key, mixed val) {
+	cb_key k = CB_KEY_FROM_SVALUE(key);
+	THIS->tree = cb_insert(THIS->tree, k, val);
+#ifdef DEBUG_CHECK
+	cb_check(THIS->tree, THIS->tree, k->str);
+#endif /* DEBUG_CHECK */
+	stack_pop_keep_top();
+    }
+
+    PIKEFUN mixed ninsert(mixed key, mixed val, int chars, int bits) {
+	cb_size len;
+	cb_key k;
+
+	k = CB_KEY_FROM_SVALUE(key);
+	len.chars = chars;
+	len.bits = bits;
+	if (CB_LT(k.len, len)) {
+	    Pike_error("chars, bits are too big for key.\n");
+	}
+	THIS->tree = cb_insert(THIS->tree, k, val);
+	stack_pop_keep_top();
+    }
+
+    /*! @decl mixed cast(string type)
+     *! Cast callback. Supports only cast to mapping and
+     *! behaves as the inverse of create().
+     */
+    PIKEFUN mixed cast(string type) {
+	struct pike_string *mapping_t;
+	REF_MAKE_CONST_STRING(mapping_t, "mapping");
+
+	if (type == mapping_t) {
+	    pop_stack();
+	    cmod_CONCAT_EVAL(f_, tree_class, _cq__indices)(0);
+	    cmod_CONCAT_EVAL(f_, tree_class, _cq__values)(0);
+	    f_mkmapping(2);
+	    free_string(mapping_t);
+	    return;
+	}
+	free_string(mapping_t);
+	Pike_error("Cannot cast to %S\n", type);
+    }
+
+    /*! @decl mixed nth(int(0..) n)
+     *! Get the @expr{n@}th entry in order.
+     *! @returns
+     *! 	An array @expr{({ key, value })@}.
+     */
+    PIKEFUN mixed nth(int n) {
+	cb_node_t node;
+
+	if (THIS->tree) {
+	    if (n >= 0 && (size_t)n < THIS->tree->size) {
+		node = cb_get_nth(THIS->tree, n);
+		if (node) {
+		    pop_stack();
+		    CB_PUSH_TRANSFORM_KEY(node->key);
+		    push_svalue(&node->value);
+		    f_aggregate(2);
+		    return;
+		}
+	    }
+	}
+
+	pop_stack();
+	push_undefined();
+	return;
+    }
+
+    /*! @decl array _random()
+     *! Get a random entry.
+     *! @returns
+     *! 	An array @expr{({ key, value })@}.
+     */
+    PIKEFUN array _random() {
+	cb_node_t node;
+
+	if (THIS->tree) {
+	    node = cb_get_nth(THIS->tree, my_rand() % THIS->tree->size);
+	    if (node) {
+		CB_PUSH_TRANSFORM_KEY(node->key);
+		push_svalue(&node->value);
+		f_aggregate(2);
+		return;
+	    }
+	}
+
+	push_undefined();
+	return;
+    }
+
+    /*! @decl mixed `[](mixed key)
+     */
+    PIKEFUN mixed `[](mixed key) {
+	CB_TRANSFORM_KEY(key);
+	if (key->type & T_KEY) {
+	    cb_node_t n;
+	    cb_key k = CB_LOW_KEY_FROM_SVALUE(key);
+	    pop_stack();
+	    n = cb_index(THIS->tree, k);
+
+	    if (n && CB_HAS_VALUE(n)) {
+		push_svalue(&n->value);
+		return;
+	    }
+	} else pop_stack();
+	push_undefined();
+    }
+
+    /*! @decl int(0..1) _equal(mixed o)
+     */
+    PIKEFUN int _equal(mixed o) {
+	if (o->type == PIKE_T_OBJECT
+	    && o->u.object->prog == Pike_fp->current_object->prog) {
+	    cb_node_t tree1, tree2;
+	    tree1 = THIS->tree;
+	    tree2 = cmod_OBJ2_TREE(o->u.object)->tree;
+
+	    if (tree1 == tree2) {
+		push_int(1);
+		return;
+	    }
+
+	    if (tree1 && tree2 && tree1->size == tree2->size) {
+		WALK_FORWARD(tree1, {
+		    if (CB_HAS_VALUE(_)) {
+			cb_node_t n = cb_index(tree2, _->key);
+			if (!n || !is_equal(&_->value, &n->value)) {
+			    push_int(0);
+			    return;
+			}
+		    }
+		});
+		push_int(1);
+		return;
+	    }
+	}
+	push_int(0);
+	return;
+    }
+
+    /*! @decl mixed `-(mixed o)
+     *! Sub[s]tract two trees from each other (key-wise).
+     */
+    PIKEFUN mixed `-(mixed o) {
+	struct object * res;
+	cb_node_t node, tree = NULL;
+
+	if (o->type != PIKE_T_OBJECT || -1
+	    == low_get_storage(o->u.object->prog, TREE_CLASSIFY(_program))) {
+	    SIMPLE_BAD_ARG_ERROR("`-", 1, "CritBit." cmod_STRFY_EVAL(tree_class));
+	}
+
+	node = cmod_OBJ2_TREE(o->u.object)->tree;
+
+	if (THIS->tree) {
+	    if (node) {
+		cb_node_t t = THIS->tree;
+		res = clone_object(Pike_fp->current_object->prog, 0);
+
+		if (node != THIS->tree)
+		    WALK_FORWARD(t, {
+			if (CB_HAS_VALUE(_) && !cb_index(node, _->key))
+			    COPY_NODE(res, _);
+		    });
+	    } else res = CLONE_OBJECT(Pike_fp->current_object);
+	} else res = clone_object(Pike_fp->current_object->prog, 0);
+
+	push_object(res);
+	return;
+    }
+
+    /* FIXME: we should allow for extra arguments and call += on the copy
+     * of the first one
+     */
+    /*! @decl mixed `+(mixed o)
+     *!	Add callback. Returns the union of two trees.
+     */
+    PIKEFUN mixed `+(mixed o) {
+	cb_node_t tree1, tree2;
+
+	if (o->type != PIKE_T_OBJECT || -1
+	    == low_get_storage(o->u.object->prog, TREE_CLASSIFY(_program))) {
+	    SIMPLE_BAD_ARG_ERROR("`+", 1, "inherits(CritBit." cmod_STRFY_EVAL(tree_class) ")");
+	}
+	tree1 = THIS->tree;
+	tree2 = cmod_OBJ2_TREE(o->u.object)->tree;
+
+	if (tree1 && tree2) {
+	    struct object * res = NULL;
+	    if (tree1->size < tree2->size) {
+		tree1 = tree2;
+		tree2 = THIS->tree;
+		res = CLONE_OBJECT(o->u.object);
+	    } else
+		res = CLONE_OBJECT(Pike_fp->current_object);
+
+	    if (tree1 != tree2) {
+		if (CB_HAS_VALUE(tree2)) COPY_NODE(res, tree2);
+		WALK_FORWARD(tree2, {
+		    if (CB_HAS_VALUE(_)) COPY_NODE(res, _);
+		});
+	    }
+	    push_object(res);
+	} else if (tree1) {
+	    push_object(CLONE_OBJECT(Pike_fp->current_object));
+	} else if (tree2) {
+	    push_object(CLONE_OBJECT(o->u.object));
+	}
+
+	return;
+    }
+
+    /*! @decl mixed `[..](mixed a, int atype, mixed b, int btype)
+     *! @seealso
+     *! 	@[predef::`[..]]
+     */
+    PIKEFUN mixed `[..](mixed a, int atype, mixed b, int btype) {
+	struct object * o = NULL;
+
+	if (THIS->tree) {
+	    cb_node_t start = NULL, stop = NULL;
+
+	    switch (atype & (INDEX_FROM_BEG | INDEX_FROM_END | OPEN_BOUND)) {
+	    case OPEN_BOUND:
+		start = cb_find_first(THIS->tree);
+		break;
+	    case INDEX_FROM_BEG:
+		start = cb_find_ne(THIS->tree, CB_KEY_FROM_SVALUE(a));
+		break;
+	    case INDEX_FROM_END:
+		goto illegal_index;
+	    }
+
+	    if (!start) goto range_do_clone;
+
+	    switch (btype & (INDEX_FROM_BEG | INDEX_FROM_END | OPEN_BOUND)) {
+	    case OPEN_BOUND:
+		stop = cb_find_last(THIS->tree);
+		break;
+	    case INDEX_FROM_BEG:
+		stop = cb_find_le(THIS->tree, CB_KEY_FROM_SVALUE(b));
+		break;
+	    case INDEX_FROM_END:
+		goto illegal_index;
+	    }
+
+	    o = clone_object(Pike_fp->current_object->prog, 0);
+
+	    if (!stop) goto range_do_clone;
+
+	    if (start == stop) {
+		COPY_NODE(o, start);
+		goto range_do_clone;
+	    }
+
+	    if (CB_KEY_LT(start->key, stop->key)) {
+		COPY_NODE(o, start);
+		WALK_FORWARD(start, {
+		    if (CB_HAS_VALUE(_))
+			COPY_NODE(o, _);
+		    if (_ == stop) break;
+		});
+	    }
+	} else {
+	    if (atype & INDEX_FROM_END || btype & INDEX_FROM_END)
+		goto illegal_index;
+	}
+range_do_clone:
+	if (!o)
+	    o = clone_object(Pike_fp->current_object->prog, 0);
+	pop_n_elems(args); /* REVIEW: we need this, right? */
+	push_object(o);
+	return;
+
+illegal_index:
+	Pike_error("INDEX_FROM_END is not supported for CritBit `[..].\n");
+    }
+
+#cmod_if 0
+    PIKEFUN mixed `[](mixed a, mixed b) {
+	struct object * o = NULL;
+
+	if (THIS->tree) {
+	    cb_node_t start = NULL, stop = NULL;
+
+	    if (TYPEOF(*a) == PIKE_T_INT && !a->u.integer) {
+		start = cb_find_first(THIS->tree);
+	    } else {
+		cb_key key = CB_KEY_FROM_SVALUE(a);
+		start = cb_find_ne(THIS->tree, key);
+	    }
+
+	    if (!start) goto range_do_clone;
+
+	    if (TYPEOF(*b) == PIKE_T_INT && b->u.integer == MAX_INT_TYPE) {
+		stop = cb_find_last(THIS->tree);
+	    } else {
+		cb_key key = CB_KEY_FROM_SVALUE(b);
+		stop = cb_find_le(THIS->tree, key);
+	    }
+
+	    o = clone_object(Pike_fp->current_object->prog, 0);
+
+	    if (!stop) goto range_do_clone;
+
+	    if (start == stop) {
+		COPY_NODE(o, start);
+		goto range_do_clone;
+	    }
+
+	    if (CB_KEY_LT(start->key, stop->key)) {
+		COPY_NODE(o, start);
+		WALK_FORWARD(start, {
+		    if (CB_HAS_VALUE(_))
+			COPY_NODE(o, _);
+		    if (_ == stop) break;
+		});
+	    }
+	}
+range_do_clone:
+	if (!o)
+	    o = clone_object(Pike_fp->current_object->prog, 0);
+	pop_n_elems(args); /* REVIEW: we need this, right? */
+	push_object(o);
+	return;
+    }
+#cmod_endif
+
+    PIKEFUN string ugly() {
+	if (THIS->tree) {
+	    struct string_builder s;
+
+	    init_string_builder(&s, 0);
+	    cb_print_tree(&s, THIS->tree, 0);
+	    push_string(finish_string_builder(&s));
+	    return;
+	}
+	push_text("");
+    }
+
+    DOCSTART() @decl key_ptype first()
+     *! Get the lexicographically first index in the tree.
+    DOCEND()
+    PIKEFUN key_ptype first() {
+	if (THIS->tree) {
+	    cb_node_t first = cb_find_first(THIS->tree);
+	    if (first) {
+		CB_PUSH_TRANSFORM_KEY(first->key);
+		return;
+	    }
+	}
+	push_undefined();
+    }
+
+    DOCSTART() @decl key_ptype last()
+     *! Get the lexicographically last index in the tree.
+    DOCEND()
+    PIKEFUN key_ptype last() {
+	if (THIS->tree) {
+	    cb_node_t last = cb_find_last(THIS->tree);
+	    if (last) {
+		CB_PUSH_TRANSFORM_KEY(last->key);
+		return;
+	    }
+	}
+	push_undefined();
+    }
+
+    /*! @decl string bkey(mixed key)
+     *! Render the internally used binary representation of
+     *! the key into a string as a strings of '0's and '1's.
+     */
+    PIKEFUN string bkey(mixed key) {
+	struct string_builder s;
+	cb_key k;
+
+	init_string_builder(&s, 0);
+	k = CB_KEY_FROM_SVALUE(key);
+	pop_stack();
+	cb_print_key(&s, k);
+
+	push_string(finish_string_builder(&s));
+    }
+
+    DOCSTART() @decl key_ptype previous(mixed current)
+     *! Get the key before @expr{current@} in lexicographical order.
+    DOCEND()
+    PIKEFUN key_ptype previous(mixed current) {
+	CB_CHECK_KEY(current, "previous", 1);
+
+	if (THIS->tree) {
+	    cb_node_t previous;
+
+	    previous = cb_find_previous(THIS->tree, CB_LOW_KEY_FROM_SVALUE(current));
+	    pop_stack();
+	    if (previous) {
+		CB_PUSH_TRANSFORM_KEY(previous->key);
+		return;
+	    }
+	}
+	push_undefined();
+    }
+
+    DOCSTART() @decl key_ptype next(mixed current)
+     *! Get the key after @expr{current@} in lexicographical order.
+    DOCEND()
+    PIKEFUN key_ptype next(mixed current) {
+	CB_CHECK_KEY(current, "next", 1);
+
+	if (THIS->tree) {
+	    cb_node_t next;
+
+	    next = cb_find_next(THIS->tree, CB_LOW_KEY_FROM_SVALUE(current));
+	    pop_stack();
+	    if (next) {
+		CB_PUSH_TRANSFORM_KEY(next->key);
+		return;
+	    }
+	}
+	push_undefined();
+    }
+
+    DOCSTART() @decl object _get_iterator()
+     *! @returns
+     *! This function returns an @[Iterator]-instance as would be created
+     *! with @expr{ADT.CritBit.TREE_CLASSIFY(.Iterator)(tree)@}
+    DOCEND()
+    PIKEFUN object _get_iterator() {
+	ref_push_object(Pike_fp->current_object);
+	push_object(clone_object(cmod_CONCAT_EVAL(tree_class,_,iterator_class,_program), 1));
+    }
+
+    /*! @decl int(0..) depth()
+     *! Calculate the depth of the tree.
+     */
+    PIKEFUN int depth() {
+	if (THIS->tree) {
+	    push_int(cb_get_depth(THIS->tree));
+	    return;
+	}
+
+	push_int(0);
+	return;
+    }
+
+    DOCSTART() @decl tree_class copy()
+     *! Create a copy of the tree.
+    DOCEND()
+    PIKEFUN object copy() {
+	struct object * copy;
+	copy = clone_object(Pike_fp->current_object->prog, 0);
+	if (THIS->tree) {
+	    cmod_OBJ2_TREE(copy)->tree = cb_copy_tree(THIS->tree);
+	}
+	push_object(copy);
+    }
+
+    DOCSTART() @decl tree_class get_subtree(void|mixed key)
+     *! Get a copy of the subtree starting at prefix
+     *! @expr{key@}.
+    DOCEND()
+    PIKEFUN object get_subtree(void|mixed key) {
+	struct object * sub;
+	cb_node_t node = NULL;
+
+	if (THIS->tree) {
+	    if (args == 0 || IS_UNDEFINED(key))
+		node = THIS->tree;
+	    else
+		node = cb_subtree_prefix(THIS->tree, CB_LOW_KEY_FROM_SVALUE(key));
+	}
+	sub = clone_object(Pike_fp->current_object->prog, 0);
+
+	pop_n_elems(args);
+
+	if (node) {
+	    COPY_TREE(sub, node);
+	}
+
+	push_object(sub);
+    }
+
+    EXIT {
+#if 0 /* HAS___SYNC_VAL_COMPARE_AND_SWAP */
+	cb_node_t tree = THIS->tree;
+	if (tree && __sync_val_compare_and_swap(&(THIS->tree), tree, NULL)) {
+	    cb_free_node(tree);
+	}
+#else
+	if (THIS->tree) cb_free_node(THIS->tree);
+	THIS->tree = NULL;
+#endif
+    }
+
+/*! @endclass */
diff --git a/src/post_modules/CritBit/widestring.h b/src/post_modules/CritBit/widestring.h
new file mode 100644
index 0000000000000000000000000000000000000000..8676e837e03706c92e4c68f4f6ff90325e04366a
--- /dev/null
+++ b/src/post_modules/CritBit/widestring.h
@@ -0,0 +1,169 @@
+#ifndef _WIDESTRING_H
+#define _WIDESTRING_H
+#include <stdint.h>
+#include "bitvector.h"
+#include "stralloc.h"
+
+typedef struct pike_string * CB_NAME(string);
+typedef p_wchar2 CB_NAME(char);
+
+#include "svalue_value.h"
+#include "tree_low.h"
+
+#define CB_DO_PRINTING
+
+/* the following is used by tree_low */
+#ifdef CB_SOURCE
+#define CB_ADD_KEY_REF(x)	do { if ((x).str) add_ref((x).str); } while(0)
+#define CB_FREE_KEY(x)		do { if ((x).str) free_string((x).str); } while(0)
+#define CB_SET_KEY(node, x)				\
+	do { CB_ADD_KEY_REF(x);				\
+	    CB_FREE_KEY((node)->key); (node)->key = (x); } while(0)
+
+#define CB_KEY_EQ(k1, k2)	(CB_S_EQ((k1).len, (k2).len) && (k1).str == (k2).str)
+#define CB_KEY_LT(k1, k2)				\
+	(CB_LT((k1).len, (k2).len) && my_quick_strcmp((k1).str, (k2).str) < 0)
+
+#define CB_GET_CHAR(s, n)	((cb_char)INDEX_CHARP((s)->str, (n), (s)->size_shift))
+#define CB_WIDTH(s)	(1 << (3 + (s)->size_shift)) /* width in bits */
+#define CB_LENGTH(str)	((str)->len)
+#define CB_SIZE(key)	((key).len)
+#define CB_GET_BIT(str, pos)				\
+	(BITN(cb_char, CB_GET_CHAR((str), (pos).chars), (pos).bits))
+static inline uint32_t CB_COUNT_PREFIX(const cb_string s1, const cb_string s2, const size_t n) {
+    cb_char c;
+    c = CB_GET_CHAR(s1, n);
+    c ^= CB_GET_CHAR(s2, n);
+
+    return clz32(c);
+}
+#if 0
+#define CB_COUNT_PREFIX(s1, s2, n)			\
+	(clz32(CB_GET_CHAR((s1), (n)) ^ CB_GET_CHAR((s2), (n))))
+#endif
+#endif /* CB_SOURCE */
+
+/* this is only used in pike code! */
+#define CB_PRINT_CHAR(buf, str, n)			\
+    do { string_builder_sprintf((buf), "%c", CB_GET_CHAR(str, n)); } while(0)
+
+#define CB_PRINT_KEY(buf, key)				\
+	do { string_builder_shared_strcat((buf), (key).str); } while(0)
+#define CB_LOW_ASSIGN_SVALUE_KEY(key, s)	do {	\
+    struct pike_string * _key = (key).str;		\
+    struct svalue * _svalue = (s);			\
+    add_ref(_key);					\
+    _svalue->subtype = 0;				\
+    _svalue->u.string = _key;				\
+    _svalue->type = PIKE_T_STRING;			\
+} while(0)
+#define CB_PUSH_KEY(key)	ref_push_string((key).str)
+#define CB_PUSH_STRING(str)	ref_push_string(str)
+#define CB_STRING_FROM_SVALUE(v)	((v)->u.string)
+#define CB_LOW_KEY_FROM_SVALUE(v)	CB_KEY_FROM_STRING(CB_STRING_FROM_SVALUE(v))
+
+static inline cb_size cb_prefix_count_wide0(const cb_string s1,
+					    const cb_string s2,
+					    const cb_size len,
+					    cb_size start) {
+    size_t j = start.chars;
+    const unsigned char * p1, * p2;
+
+    p1 = STR0(s1);
+    p2 = STR0(s2);
+
+#if 0
+    asm volatile(
+    "pushf\t\n"
+    "orl $(1<<18), (%esp)\t\n"
+    "popf\t\n"
+  );
+#endif
+
+#define PREFIX(n) do {						\
+    size_t k = j/sizeof(uint ##n ##_t);				\
+    for (;k < len.chars/sizeof(uint ##n ##_t);k++) {		\
+	uint ##n ##_t x = ((uint ##n ##_t *)p1)[k] 		\
+			^ ((uint ##n ##_t *)p2)[k];	    	\
+	if (x) {						\
+	    uint32_t a;						\
+	    a = clz ##n(hton ##n(x));				\
+	    start.chars = k*sizeof(uint ##n ##_t) + a/8;	\
+	    start.bits = 24 + a % 8;				\
+	    return start;					\
+	}							\
+    }								\
+    j = k*sizeof(uint ##n ##_t);				\
+    } while(0)
+#ifdef lzc64
+   PREFIX(64);
+#endif
+   PREFIX(32);
+    PREFIX(8);
+
+#if 0
+    asm volatile(
+    "pushf\t\n"
+    "andl $(~(1<<18)), (%esp)\t\n"
+    "popf\t\n"
+  );
+#endif
+
+    start.chars = j;
+
+    if (len.bits) {
+	uint32_t a = clz8(((p_wchar0*)p1)[j]^((p_wchar0*)p2)[j]);
+	start.bits = MINIMUM(len.bits, 24+a);
+	return start;
+    }
+
+    start.bits = 0;
+    return start;
+}
+
+static inline cb_size cb_prefix_count_widestring(const cb_string s1,
+						 const cb_string s2,
+						 const cb_size len,
+						 const cb_size start) {
+#if 0
+    size_t i;
+    cb_size t, r;
+    unsigned char* chrptr = s1->str;;
+    static volatile cb_string n1, n2;
+    static volatile void* zero = NULL;
+    static volatile cb_size *rp, *tp;
+
+    n1 = s1;
+    n2 = s2;
+
+#endif
+    if (CB_WIDTH(s1) == 8 && 8 == CB_WIDTH(s2))
+	return cb_prefix_count_wide0(s1, s2, len, start);
+#if 0
+	if (!CB_S_EQ(r, t)) {
+	    rp = &r;
+	    tp = &t;
+	    fprintf(stderr, "%p(%p) and %p(%p) have prefix %lu,%lu. should "
+		    + "have %lu,%lu (len: %lu, %lu  start: %lu, %lu)\n",
+		    s1->str, s1, s2->str, s2, t.chars, t.bits, r.chars,
+		    r.bits, len.chars, len.bits, start.chars, start.bits);
+	    fprintf(stderr, "here you die: %p, %lu\n", chrptr,
+		    r.bits/(uint64_t)zero);
+	    fprintf(stderr, "%p %p %p", zero, n1, n2);
+	    n1 = n2 = (void*)(zero = (uint64_t)chrptr ^ (uint64_t)n1
+			      ^ (uint64_t)n2);
+	    fprintf(stderr, "%p %p %p %p %p %p", zero, n1, n2, rp, (void*)rp,
+		    tp, (void*)tp);
+	}
+#endif
+
+
+    return cb_prefix_count_fallback(s1, s2, len, start);
+}
+
+#define	cb_prefix_count	cb_prefix_count_widestring
+
+#undef CB_WIDTH
+#define CB_WIDTH(s)	(32)
+
+#endif