Hi… I am well aware that this diff view is very suboptimal. It will be fixed when the refactored server comes along!
Add swiss FNV wrapper
swiss_fnv: FNV swiss tables
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use ds::map;
// Deletes an item from a [[map]].
export fn del(m: *map, key: []u8) (*opaque | void) = {
return map::del(m.inner, key);
};
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use ds::map;
// Frees resources associated with a [[map]].
export fn finish(m: *map) void = {
map::finish(m.inner);
free(m);
};
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use ds::map;
// Gets an item from a [[map]] by key, returning void if not found.
export fn get(m: *map, key: []u8) (*opaque | void) = {
return map::get(m.inner, key);
};
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use hash;
use hash::fnv;
fn hash64(_params: nullable *opaque, key: []u8) size = {
let h = fnv::fnv64a();
defer hash::close(&h);
hash::write(&h, key);
return fnv::sum64(&h): size;
};
// 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,
};
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);
// SPDX-License-Identifier: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use errors;
use ds::map;
use ds::map::swiss;
// Creates a new [[map]] with an initial number of groups using FNV.
//
// n_groups must be greater than zero.
export fn new(
n_groups: size,
) (*map | errors::invalid | nomem) = {
let inner = match (swiss::new(
n_groups, &hash64, null,
)) {
case let sm: *swiss::map =>
yield (sm: *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: Apache-2.0 AND MPL-2.0
// SPDX-FileCopyrightText: 2025 Runxi Yu <me@runxiyu.org>
use ds::map;
// 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 map::set(m.inner, key, value);
};
use ds::map;
use errors;
@test fn test() void = {
const groups: [2]size = [1z, 32z];
for (let gi = 0z; gi < len(groups); gi += 1) {
let m: *map = match (new(groups[gi])) {
case let p: *map => yield p;
case errors::invalid => abort("swiss_fnv: invalid groups");
case nomem => abort("swiss_fnv: nomem");
};
defer finish(m);
map::stress_test(m, 200000);
};
};