Lindenii Project Forge
Login

hare-ds

Data structures for Hare
Commit info
ID
96fd779639f91e3a124c3d1ed7b141cf785db4bc
Author
Runxi Yu <me@runxiyu.org>
Author date
Wed, 17 Sep 2025 04:02:37 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Wed, 17 Sep 2025 04:03:45 +0800
Actions
Update test routines
use crypto::random;
use ds::map;
use ds::map::slice_basic;
use ds::map::slice_sorted;
use ds::map::btree;
use ds::map::rbtree;
use ds::map::swiss_siphash;
use errors;

fn mk_slice_basic() (*map::map | nomem) = {
	match (slice_basic::new()) {
	case let p: *slice_basic::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_slice_sorted() (*map::map | nomem) = {
	match (slice_sorted::new()) {
	case let p: *slice_sorted::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_btree2() (*map::map | nomem) = {
	match (btree::new(2)) {
	case let p: *btree::map => return (p: *map::map);
	case errors::invalid => abort("btree(2) invalid");
	case nomem => return nomem;
	};
};

fn mk_rbtree() (*map::map | nomem) = {
	match (rbtree::new()) {
	case let p: *rbtree::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_swiss() (*map::map | nomem) = {
	let key: [16]u8 = [0...];
	random::buffer(&key);
	match (swiss_siphash::new(1, key)) {
	case let p: *swiss_siphash::map => return (p: *map::map);
	case errors::invalid => abort("swiss: invalid");
	case nomem => return nomem;
	};
};

@test fn test() void = {
	const buckets: [2]size = [128z, 256z];
	const makers: [5]*fn() (*map::map | nomem) = [&mk_slice_basic, &mk_slice_sorted, &mk_btree2, &mk_rbtree, &mk_swiss];
	const buckets: [_]size = [128z, 256z];
	const makers: [_]*fn() (*map::map | nomem) = [&mk_slice_basic];

	for (let bi = 0z; bi < len(buckets); bi += 1) {
		for (let mi = 0z; mi < len(makers); mi += 1) {
			let m: *map = match (new(makers[mi], buckets[bi])) {
			case let p: *map => yield p;
			case errors::invalid => abort("fnv: invalid");
			case nomem => abort("fnv: nomem");
			};
			defer finish(m);
			map::stress_test(m, 20000);
		};
	};
};
use crypto::random;
use ds::map;
use ds::map::slice_basic;
use ds::map::slice_sorted;
use ds::map::btree;
use ds::map::rbtree;
use ds::map::swiss_siphash;
use errors;

fn testhash(_params: nullable *opaque, key: []u8) size = {
	let val: u64 = 0;
	let limit = if (len(key) < 8z) len(key) else 8z;
	for (let i = 0z; i < limit; i += 1) {
		val |= (key[i]: u64) << (8u64 * (i: u64));
	};
	return (val: size);
};

fn mk_slice_basic() (*map::map | nomem) = {
	match (slice_basic::new()) {
	case let p: *slice_basic::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

@test fn invalid() void = {
	match (new(&mk_slice_basic, 0, &testhash, null)) {
	case errors::invalid => void;
	case *map => abort("hashmap: accepted n=0");
	case nomem => abort("hashmap: nomem for n=0");
	};
};

@test fn test() void = {
	const buckets: [_]size = [64z, 128z];
	const makers: [_]*fn() (*map::map | nomem) = [&mk_slice_basic];

	for (let bi = 0z; bi < len(buckets); bi += 1) {
		for (let mi = 0z; mi < len(makers); mi += 1) {
			let m = match (new(makers[mi], buckets[bi], &testhash, null)) {
			case let p: *map => yield p;
			case errors::invalid => abort("hashmap: invalid parameters");
			case nomem => abort("hashmap: nomem");
			};
			defer finish(m);
			map::stress_test(m, 20000);
		};
	};
};
use crypto::random;
use ds::map;
use ds::map::slice_basic;
use ds::map::slice_sorted;
use ds::map::btree;
use ds::map::rbtree;
use ds::map::swiss_siphash;
use errors;

fn mk_slice_basic() (*map::map | nomem) = {
	match (slice_basic::new()) {
	case let p: *slice_basic::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_slice_sorted() (*map::map | nomem) = {
	match (slice_sorted::new()) {
	case let p: *slice_sorted::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_btree2() (*map::map | nomem) = {
	match (btree::new(2)) {
	case let p: *btree::map => return (p: *map::map);
	case errors::invalid => abort("btree(2) invalid");
	case nomem => return nomem;
	};
};

fn mk_rbtree() (*map::map | nomem) = {
	match (rbtree::new()) {
	case let p: *rbtree::map => return (p: *map::map);
	case nomem => return nomem;
	};
};

fn mk_swiss() (*map::map | nomem) = {
	let key: [16]u8 = [0...];
	random::buffer(&key);
	match (swiss_siphash::new(1, key)) {
	case let p: *swiss_siphash::map => return (p: *map::map);
	case errors::invalid => abort("swiss: invalid");
	case nomem => return nomem;
	};
};

@test fn test() void = {
	const buckets: [2]size = [128z, 256z];
	const makers: [5]*fn() (*map::map | nomem) = [&mk_slice_basic, &mk_slice_sorted, &mk_btree2, &mk_rbtree, &mk_swiss];
	const buckets: [_]size = [128z, 256z];
	const makers: [_]*fn() (*map::map | nomem) = [&mk_slice_basic];

	let key1: [16]u8 = [0...];
	let key2: [16]u8 = [0...];
	random::buffer(&key1);
	random::buffer(&key2);
	const keys: [2]*[16]u8 = [&key1, &key2];

	for (let bi = 0z; bi < len(buckets); bi += 1) {
		for (let ki = 0z; ki < len(keys); ki += 1) {
			for (let mi = 0z; mi < len(makers); mi += 1) {
				let m: *map = match (new(makers[mi], buckets[bi], *keys[ki])) {
				case let p: *map => yield p;
				case errors::invalid => abort("siphash: invalid");
				case nomem => abort("siphash: nomem");
				};
				defer finish(m);
				map::stress_test(m, 20000);
			};
		};
	};
};
use ds::map;

@test fn test() void = {
@test fn test_2000() void = {
	let m: *map = match (new()) {
	case let p: *map => yield p;
	case nomem => abort("slice_basic: nomem");
	};
	defer finish(m);
	map::stress_test(m, 20000);
	map::stress_test(m, 2000);
};
use ds::set;
use errors;

fn testhash(_params: nullable *opaque, key: []u8) size = {
	let val: u64 = 0;
	let limit = if (len(key) < 8z) len(key) else 8z;
	for (let i = 0z; i < limit; i += 1) {
		val |= (key[i]: u64) << (8u64 * (i: u64));
	};
	return (val: size);
};

fn put_le64(dst: *[8]u8, v: u64) []u8 = {
	for (let i = 0z; i < 8z; i += 1) {
		dst[i] = ((v >> (8u64 * (i: u64))) & 0xFFu64): u8;
	};
	return dst[..];
};

@test fn invalid() void = {
	match (new(0, 1, &testhash, null)) {
	case errors::invalid => void;
	case *set => abort("new accepted m=0");
	case nomem => abort("new(m=0) returned nomem");
	};
	match (new(64, 0, &testhash, null)) {
	case errors::invalid => void;
	case *set => abort("new accepted k=0");
	case nomem => abort("new(k=0) returned nomem");
	};
};

@test fn basic() void = {
	let s = match (new(256, 2, &testhash, null)) {
	case let sp: *set => yield sp;
	case errors::invalid => abort("basic: invalid");
	case nomem => abort("basic: nomem");
	};
	defer finish(s);
	let iface: *set::set = (s: *set::set);

	const inserted: [4]u64 = [1u64, 3u64, 17u64, 41u64];
	let keybuf: [8]u8 = [0...];
	for (let i = 0z; i < len(inserted); i += 1) {
		let key = put_le64(&keybuf, inserted[i]);
		assert(!contains(s, key), "contains before add");
		match (set::add(iface, key)) {
		case void => void;
		case nomem => abort("basic: add nomem");
		};
		assert(set::contains(iface, key), "contains after add");
	};

	const missing: [3]u64 = [11u64, 21u64, 111u64];
	for (let i = 0z; i < len(missing); i += 1) {
		let key = put_le64(&keybuf, missing[i]);
		assert(!set::contains(iface, key), "contains false positive");
	};
};