Lindenii Project Forge
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); }; };