Lindenii Project Forge
Login

hare-ds

Data structures for Hare
Commit info
ID
c504154595336fe3029bcfdffe0129e127308f68
Author
Runxi Yu <me@runxiyu.org>
Author date
Sun, 21 Sep 2025 18:40:40 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Sun, 21 Sep 2025 18:59:07 +0800
Actions
Add iter
// SPDX-License-Identifier: MPL-2.0

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	nodes: []*node,
	idxs: []size,
	visit_key: []bool,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let it = alloc(iterator {
		vt = &_itvt,
		nodes = [],
		idxs = [],
		visit_key = [],
	})?;

	match (append(it.nodes, m.root)) {
	case void => void;
	case nomem => return nomem;
	};
	match (append(it.idxs, 0z)) {
	case void => void;
	case nomem => return nomem;
	};
	match (append(it.visit_key, false)) {
	case void => void;
	case nomem => return nomem;
	};

	return (it: *map::iterator);
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	for (len(it.nodes) != 0) {
		let top = len(it.nodes) - 1;
		let x = it.nodes[top];
		let i = it.idxs[top];
		let vk = it.visit_key[top];

		if (x.leaf) {
			if (i < len(x.keys)) {
				it.idxs[top] = i + 1;
				return (x.keys[i], x.vals[i]);
			};
			delete(it.nodes[top]);
			delete(it.idxs[top]);
			delete(it.visit_key[top]);
			continue;
		};

		if (vk) {
			if (i >= len(x.keys)) {
				it.visit_key[top] = false;
				continue;
			};
			it.visit_key[top] = false;
			it.idxs[top] = i + 1;
			return (x.keys[i], x.vals[i]);
		};

		if (i < len(x.keys)) {
			match (append(it.nodes, x.children[i])) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			match (append(it.idxs, 0z)) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			match (append(it.visit_key, false)) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			it.visit_key[top] = true;
			continue;
		};

		if (i == len(x.keys)) {
			match (append(it.nodes, x.children[i])) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			match (append(it.idxs, 0z)) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			match (append(it.visit_key, false)) {
			case void => void;
			case nomem => abort("btree::iter: nomem");
			};
			it.idxs[top] = i + 1;
			continue;
		};

		delete(it.nodes[top]);
		delete(it.idxs[top]);
		delete(it.visit_key[top]);
	};

	return done;
};
// SPDX-License-Identifier: MPL-2.0

use ds::map;

// B-tree-based map from []u8 to *opaque.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	// Min degree
	t: size,
	root: *node,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	m: *map,
	bi: size,
	cur: nullable *map::iterator,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let it = alloc(iterator {
		vt = &_itvt,
		m = m,
		bi = 0,
		cur = null,
	})?;
	for (it.bi < m.n) {
		let b = m.buckets[it.bi];
		it.bi += 1;
		match (map::iter(b)) {
		case let i: *map::iterator =>
			it.cur = i;
			break;
		case nomem =>
			abort("hashmap::iter: nomem");
		};
	};
	return (it: *map::iterator);
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	for (true) {
		match (it.cur) {
		case null =>
			if (it.bi >= it.m.n) return done;
			let b = it.m.buckets[it.bi];
			it.bi += 1;
			match (map::iter(b)) {
			case let i: *map::iterator =>
				it.cur = i;
			case nomem =>
				abort("hashmap::iter: nomem");
			};
		case let curi: *map::iterator =>
			match (map::next(curi)) {
			case let kv: ([]u8, *opaque) =>
				return kv;
			case done =>
				it.cur = null;
			};
		};
	};
};
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

// A simple hash map from []u8 to *opaque pointers, using the user-provided hash
// and collision resolution function.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	n: size,
	buckets: []*map::map,
	hash64: *fn(hash_params: nullable *opaque, key: []u8) size,
	hash_params: nullable *opaque,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

export type iterator = map::iterator;

export fn iter(m: *map) (*map::iterator | nomem) = {
	return map::iter(m.inner);
};
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

// A simple hash map from byte strings to opaque pointers, using FNV for
// hashing and fallback maps for collision resolution.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	inner: *map::map,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

export type iterator = map::iterator;

export fn iter(m: *map) (*map::iterator | nomem) = {
	return map::iter(m.inner);
};
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

// A simple hash map from byte strings to opaque pointers, using SipHash for
// hashing and fallback maps for collision resolution.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	inner: *map::map,
	key: *[16]u8,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// A map is a pointer to a [[vtable]] which allows for map types to implement
// common operations.
export type map = *vtable;

// Iterator vtable for map iteration.
export type vtable_iterator = struct {
	nexter: *nexter,
};

// The outward-facing iterator type (pointer to an iterator vtable).
export type iterator = *vtable_iterator;

// The vtable type defines a set of virtual functions for a [[map]].
export type vtable = struct {
	getter: *getter,
	setter: *setter,
	deleter: *deleter,
	finisher: *finisher,
	iter: *iterer,
};

// The interface for a map which could be used to get values. Returns either a
// pointer to the value, or void if the key does not exist.
export type getter = fn(m: *map, key: []u8) (*opaque | void);

// Gets an item from a [[map]]. Returns a pointer to the value or void.
export fn get(m: *map, key: []u8) (*opaque | void) = {
	return m.getter(m, key);
};

// The interface for a map which could be used to set values. Returns void on
// success, or nomem if memory allocation failed. If the value already exists,
// it is replaced.
export type setter = fn(m: *map, key: []u8, value: *opaque) (void | nomem);

// Sets an item in a [[map]], replacing any existing item with the same key.
export fn set(m: *map, key: []u8, value: *opaque) (void | nomem) = {
	return m.setter(m, key, value);
};

// The interface for a map which could be used to delete values. Returns a
// pointer to the deleted value, or void if the key does not exist.
export type deleter = fn(m: *map, key: []u8) (*opaque | void);

// Deletes an item from a [[map]]. Returns the removed value or void.
export fn del(m: *map, key: []u8) (*opaque | void) = {
	return m.deleter(m, key);
};

// The interface for a map which requires a finisher function to free it.
export type finisher = fn(m: *map) void;

// Frees the map and all of its resources. Do not use the map after calling.
export fn finish(m: *map) void = {
	m.finisher(m);
};

// Iterator maker function in the main vtable.
export type iterer = fn(m: *map) (*iterator | nomem);

// Creates an iterator for this map implementation.
export fn iter(m: *map) (*iterator | nomem) = {
	return m.iter(m);
};

// Iterator "next" method signature.
// Returns the next (key, value) pair, or done when iteration is complete.
export type nexter = fn(it: *iterator) (([]u8, *opaque) | done);

// Advances the iterator, yielding (key, value) or done when finished.
export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	return it.nexter(it);
};
// SPDX-License-Identifier: MPL-2.0

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	cur: nullable *node,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let start: nullable *node = match (m.root) {
	case null => yield null;
	case let r: *node => yield subtree_min(r);
	};
	let it = alloc(iterator {
		vt = &_itvt,
		cur = start,
	})?;
	return (it: *map::iterator);
};

fn successor(n0: *node) nullable *node = {
	let n = n0;

	match (n.right) {
	case let r: *node =>
		return subtree_min(r);
	case null =>
		void;
	};

	let mut_p: nullable *node = n.parent;
	let child: nullable *node = n;

	for (mut_p != null) {
		let p = match (mut_p) {
		case let pp: *node => yield pp;
		case null => break;
		};
		if (p.right != child) {
			return p;
		};
		child = p;
		mut_p = p.parent;
	};

	return null;
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	match (it.cur) {
	case null =>
		return done;
	case let n: *node =>
		let k = n.key;
		let v = n.val;
		it.cur = successor(n);
		return (k, v);
	};
};
use ds::map;

// Red–black tree-based map from []u8 to *opaque.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	root: nullable *node,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: MPL-2.0

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	m: *map,
	i: size,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let it = alloc(iterator {
		vt = &_itvt,
		m = m,
		i = 0,
	})?;
	return (it: *map::iterator);
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	if (it.i >= len(it.m.items)) {
		return done;
	};
	let kv = it.m.items[it.i];
	it.i += 1;
	return (kv.0, kv.1);
};
// SPDX-License-Identifier: MPL-2.0

use ds::map;

// Slice-backed map from []u8 to *opaque using linear scanning.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	items: []([]u8, *opaque),
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: MPL-2.0

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	m: *map,
	i: size,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let it = alloc(iterator {
		vt = &_itvt,
		m = m,
		i = 0,
	})?;
	return (it: *map::iterator);
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	if (it.i >= len(it.m.items)) {
		return done;
	};
	let kv = it.m.items[it.i];
	it.i += 1;
	return (kv.0, kv.1);
};
// SPDX-License-Identifier: MPL-2.0

use ds::map;

// Sorted slice backed map from []u8 to *opaque.
// Keys are ordered byte-wize lexicgraphically.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	items: []([]u8, *opaque),
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2024 The Cockroach Authors
// SPDX-FileCopyrightText: 2025 Runxi Yu

use ds::map;

export type iterator = struct {
	vt: map::iterator,
	m: *map,
	gi: size,
	si: size,
};

const _itvt: map::vtable_iterator = map::vtable_iterator {
	nexter = &vt_next,
};

fn vt_next(it: *map::iterator) (([]u8, *opaque) | done) = next(it: *iterator);

export fn iter(m: *map) (*map::iterator | nomem) = {
	let it = alloc(iterator {
		vt = &_itvt,
		m = m,
		gi = 0,
		si = 0,
	})?;
	return (it: *map::iterator);
};

export fn next(it: *iterator) (([]u8, *opaque) | done) = {
	if (len(it.m.groups) == 0) return done;

	for (it.gi <= it.m.group_mask) {
		for (let g = &it.m.groups[it.gi]; it.si < GROUP_SIZE; it.si += 1) {
			let c = g.ctrl[it.si];
			if (!is_full_ctrl(c)) {
				continue;
			};
			let k = g.keys[it.si];
			let v = g.vals[it.si];
			it.si += 1;
			match (v) {
			case null =>
				abort("map: null internal state escaped");
			case let p: *opaque =>
				return (k, p);
			};
		};
		it.gi += 1;
		it.si = 0;
	};

	return done;
};
// SPDX-FileCopyrightText: 2024 The Cockroach Authors
// SPDX-FileCopyrightText: 2025 Runxi Yu

use ds::map;

// Generic map based on swiss tables from []u8 to *opaque.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	group_mask: size,
	used: size,
	tombs: size,
	hash64: *fn(hash_params: nullable *opaque, key: []u8) size,
	hash_params: nullable *opaque,
	groups: []group,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

export type iterator = map::iterator;

export fn iter(m: *map) (*map::iterator | nomem) = {
	return map::iter(m.inner);
};
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

// Swiss-table based map from []u8 to *opaque, using FNV-1a.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	inner: *map::map,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

export type iterator = map::iterator;

export fn iter(m: *map) (*map::iterator | nomem) = {
	return map::iter(m.inner);
};
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use ds::map;

// Swiss-table based map from []u8 to *opaque, using SipHash.
//
// You are advised to create these with [[new]].
export type map = struct {
	vt: map::map,
	inner: *map::map,
	key: *[16]u8,
};

const _vt: map::vtable = map::vtable {
	getter   = &vt_get,
	setter   = &vt_set,
	deleter  = &vt_del,
	finisher = &vt_finish,
	iter     = &vt_iter,
};

fn vt_get(m: *map::map, key: []u8) (*opaque | void) = get(m: *map, key);
fn vt_set(m: *map::map, key: []u8, v: *opaque) (void | nomem) = set(m: *map, key, v);
fn vt_del(m: *map::map, key: []u8) (*opaque | void) = del(m: *map, key);
fn vt_finish(m: *map::map) void = finish(m: *map);
fn vt_iter(m: *map::map) (*map::iterator | nomem) = iter(m: *map);