Lindenii Project Forge
Login

hare-ds

Data structures for Hare

Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.

/ds/map/rbtree/internal.ha (raw)

use bytes;

fn keycmp(a: []u8, b: []u8) int = {
	let n = if (len(a) < len(b)) len(a) else len(b);
	for (let i = 0z; i < n; i += 1) {
		if (a[i] < b[i]) return -1;
		if (a[i] > b[i]) return 1;
	};
	if (len(a) < len(b)) return -1;
	if (len(a) > len(b)) return 1;
	return 0;
};

fn is_red(p: nullable *node) bool = {
	match (p) {
	case null => return false;
	case let n: *node => return n.color == color::RED;
	};
};

fn is_black(p: nullable *node) bool = !is_red(p);

fn set_color(p: nullable *node, c: color) void = {
	match (p) {
	case null => return;
	case let n: *node => n.color = c;
	};
};

fn set_parent(ch: nullable *node, pa: nullable *node) void = {
	match (ch) {
	case null => return;
	case let n: *node => n.parent = pa;
	};
};

fn subtree_min(n: *node) *node = {
	let cur = n;
	for (true) {
		match (cur.left) {
		case null => return cur;
		case let l: *node => cur = l;
		};
	};
};

fn transplant(m: *map, u: *node, v: nullable *node) void = {
	match (u.parent) {
	case null =>
		m.root = v;
	case let p: *node =>
		if (p.left == (u: nullable *node)) {
			p.left = v;
		} else {
			p.right = v;
		};
	};
	set_parent(v, u.parent);
};

fn rotate_left(m: *map, x: *node) void = {
	let y = match (x.right) {
	case let r: *node => yield r;
	case null => abort("rb invariant violated: rotate_left with null right");
	};

	x.right = y.left;
	set_parent(x.right, x);

	y.parent = x.parent;
	match (x.parent) {
	case null =>
		m.root = y;
	case let p: *node =>
		if (p.left == (x: nullable *node)) {
			p.left = y;
		} else {
			p.right = y;
		};
	};

	y.left = x;
	x.parent = y;
};

fn rotate_right(m: *map, x: *node) void = {
	let y = match (x.left) {
	case let l: *node => yield l;
	case null => abort("rb invariant violated: rotate_right with null left");
	};

	x.left = y.right;
	set_parent(x.left, x);

	y.parent = x.parent;
	match (x.parent) {
	case null =>
		m.root = y;
	case let p: *node =>
		if (p.left == (x: nullable *node)) {
			p.left = y;
		} else {
			p.right = y;
		};
	};

	y.right = x;
	x.parent = y;
};

fn insert_fixup(m: *map, z: *node) void = {
	let cur = z;
	for (true) {
		let p = match (cur.parent) {
		case null => break;
		case let pp: *node => yield pp;
		};
		if (p.color == color::BLACK) break;

		let gp = match (p.parent) {
		case null => break;
		case let g: *node => yield g;
		};

		let uncle: nullable *node = if (gp.left == (p: nullable *node))
			gp.right else gp.left;

		if (is_red(uncle)) {
			set_color(p, color::BLACK);
			set_color(uncle, color::BLACK);
			set_color(gp, color::RED);
			cur = gp;
			continue;
		};

		if (gp.left == (p: nullable *node)) {
			if (p.right == (cur: nullable *node)) {
				rotate_left(m, p);
				cur = p;
			};
			let p2 = match (cur.parent) {
			case null => break;
			case let pp2: *node => yield pp2;
			};
			let g2 = match (p2.parent) {
			case null => break;
			case let gg2: *node => yield gg2;
			};
			set_color(p2, color::BLACK);
			set_color(g2, color::RED);
			rotate_right(m, g2);
		} else {
			if (p.left == (cur: nullable *node)) {
				rotate_right(m, p);
				cur = p;
			};
			let p2 = match (cur.parent) {
			case null => break;
			case let pp2: *node => yield pp2;
			};
			let g2 = match (p2.parent) {
			case null => break;
			case let gg2: *node => yield gg2;
			};
			set_color(p2, color::BLACK);
			set_color(g2, color::RED);
			rotate_left(m, g2);
		};
	};
	match (m.root) {
	case null => void;
	case let r: *node => r.color = color::BLACK;
	};
};

fn find_node(m: *map, key: []u8) nullable *node = {
	let cur = m.root;
	for (true) {
		match (cur) {
		case null => return null;
		case let n: *node =>
			let c = keycmp(key, n.key);
			if (c == 0) return n;
			cur = if (c < 0) n.left else n.right;
		};
	};
};

fn delete_fixup(m: *map, x0: nullable *node, p0: nullable *node) void = {
	let x = x0;
	let p = p0;

	for (x != m.root && is_black(x)) {
		let pp = match (p) {
		case null => break;
		case let q: *node => yield q;
		};

		if (pp.left == x) {
			let mutw = pp.right;
			let w = match (mutw) {
			case null => break;
			case let w_: *node => yield w_;
			};
			if (is_red(w)) {
				set_color(w, color::BLACK);
				set_color(pp, color::RED);
				rotate_left(m, pp);
				mutw = pp.right;
			};
			let wr = match (mutw) {
			case null => yield null;
			case let w2: *node => yield w2.right;
			};
			let wl = match (mutw) {
			case null => yield null;
			case let w2: *node => yield w2.left;
			};
			if (is_black(wl) && is_black(wr)) {
				set_color(mutw, color::RED);
				x = pp;
				p = pp.parent;
			} else {
				if (is_black(wr)) {
					set_color(wl, color::BLACK);
					set_color(mutw, color::RED);
					match (mutw) {
					case null => void;
					case let ww: *node => rotate_right(m, ww);
					};
					mutw = pp.right;
				};
				match (mutw) {
				case null => void;
				case let w3: *node =>
					w3.color = pp.color;
					set_color(pp, color::BLACK);
					set_color(w3.right, color::BLACK);
					rotate_left(m, pp);
				};
				x = m.root;
				p = null;
			};
		} else {
			let mutw = pp.left;
			let w = match (mutw) {
			case null => break;
			case let w_: *node => yield w_;
			};
			if (is_red(w)) {
				set_color(w, color::BLACK);
				set_color(pp, color::RED);
				rotate_right(m, pp);
				mutw = pp.left;
			};
			let wl = match (mutw) {
			case null => yield null;
			case let w2: *node => yield w2.left;
			};
			let wr = match (mutw) {
			case null => yield null;
			case let w2: *node => yield w2.right;
			};
			if (is_black(wl) && is_black(wr)) {
				set_color(mutw, color::RED);
				x = pp;
				p = pp.parent;
			} else {
				if (is_black(wl)) {
					set_color(wr, color::BLACK);
					set_color(mutw, color::RED);
					match (mutw) {
					case null => void;
					case let ww: *node => rotate_left(m, ww);
					};
					mutw = pp.left;
				};
				match (mutw) {
				case null => void;
				case let w3: *node =>
					w3.color = pp.color;
					set_color(pp, color::BLACK);
					set_color(w3.left, color::BLACK);
					rotate_right(m, pp);
				};
				x = m.root;
				p = null;
			};
		};
	};
	set_color(x, color::BLACK);
};