Lindenii Project Forge
Login

hare-ds

Data structures for Hare
Commit info
ID
b215faa44f909c35fdd0e5f6daa6c32961b4ae8e
Author
Runxi Yu <me@runxiyu.org>
Author date
Fri, 19 Sep 2025 14:21:25 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Fri, 19 Sep 2025 14:21:25 +0800
Actions
Explain why fallback functions are necessary in hashmaps
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use bytes;
use errors;
use ds::map;

// Creates a new [[map]] with a function that creates fallback maps, the number
// of buckets, and the hash function and parameters.
//
// Hash collisions are virtually inevitable for typical map sizes. Therefore,
// you are required to supply a function that helps creates fallback maps, which
// are used to distinguish between items when they collide in hash.
//
// Alternatively, you may wish to use [[ds::map::swiss]] for Swiss Tables,
// which do not require a custom fallback mechanism and are typically more
// performant than hashmaps.
export fn new(
	make_fallback: *fn() (*map::map | nomem),
	n: size,
	hash64: *fn(hash_params: nullable *opaque, key: []u8) size,
	hash_params: nullable *opaque,
) (*map | errors::invalid | nomem) = {
	if (n == 0) {
		return errors::invalid;
	};

	let buckets: []*map::map = [];
	for (let i = 0z; i < n; i += 1) {
		let fb = match (make_fallback()) {
		case let p: *map::map => yield p;
		case nomem =>
			for (let j = 0z; j < len(buckets); j += 1) {
				map::finish(buckets[j]);
			};
			return nomem;
		};
		match (append(buckets, fb)) {
		case void => yield;
		case nomem =>
			for (let j = 0z; j < len(buckets); j += 1) {
				map::finish(buckets[j]);
			};
			return nomem;
		};
	};

	let m = match (alloc(map {
		vt = &_vt,
		n = n,
		buckets = buckets,
		hash64 = hash64,
		hash_params = hash_params,
	})) {
	case let pm: *map => yield pm;
	case nomem =>
		for (let j = 0z; j < len(buckets); j += 1) {
			map::finish(buckets[j]);
		};
		free(buckets);
		return nomem;
	};
	return m;
};
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use errors;
use ds::map;
use ds::map::hashmap;

// Creates a new [[map]] with the given number of buckets.
// make_fallback is a function that creates per-bucket fallback maps.
//
// Hash collisions are virtually inevitable for typical map sizes. Therefore,
// you are required to supply a function that helps creates fallback maps, which
// are used to distinguish between items when they collide in hash.
//
// Alternatively, you may wish to use [[ds::map::swiss]] for Swiss Tables,
// which do not require a custom fallback mechanism and are typically more
// performant than hashmaps.
export fn new(
	make_fallback: *fn() (*map::map | nomem),
	n: size,
) (*map | errors::invalid | nomem) = {
	let inner = match (hashmap::new(make_fallback, n, &hash64, null)) {
	case let hm: *hashmap::map =>
		yield (hm: *map::map);
	case errors::invalid =>
		return errors::invalid;
	case nomem =>
		return nomem;
	};

	let m = match (alloc(map {
		vt = &_vt,
		inner = inner,
	})) {
	case let p: *map => yield p;
	case nomem =>
		map::finish(inner);
		return nomem;
	};
	return m;
};
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2024 Drew DeVault <drew@ddevault.org>
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>

use errors;
use ds::map;
use ds::map::hashmap;

// Creates a new [[map]] with a function that creates fallback maps, the number
// of buckets, and the SipHash key.
//
// Hash collisions are virtually inevitable for typical map sizes. Therefore,
// you are required to supply a function that helps creates fallback maps, which
// are used to distinguish between items when they collide in hash.
//
// Alternatively, you may wish to use [[ds::map::swiss]] for Swiss Tables,
// which do not require a custom fallback mechanism and are typically more
// performant than hashmaps.
export fn new(
	make_fallback: *fn() (*map::map | nomem),
	n: size,
	siphash_key: [16]u8,
) (*map | errors::invalid | nomem) = {
	let keybox = match (alloc(siphash_key)) {
	case let kp: *[16]u8 => yield kp;
	case nomem => return nomem;
	};

	let inner = match (hashmap::new(
		make_fallback, n, &hash64, (keybox: *opaque),
	)) {
	case let hm: *hashmap::map =>
		yield (hm: *map::map);
	case errors::invalid =>
		free(keybox);
		return errors::invalid;
	case nomem =>
		free(keybox);
		return nomem;
	};

	let m = match (alloc(map {
		vt = &_vt,
		inner = inner,
		key = keybox,
	})) {
	case let p: *map => yield p;
	case nomem =>
		map::finish(inner);
		free(keybox);
		return nomem;
	};
	return m;
};