Skip to documentation
SLOP

tiny.simd.ShardMulPlan

Reference tiny.simd ShardMulPlan

Defined in shardmul.

API (8)

Actions

Public operations.

Fields and members

Public fields and members.

No direct callersNo direct callsshardmulShardMulPlan
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/simd/src/shardmul.zig:154

zig
pub const ShardMulPlan = struct {    best_seed: u64,    key_counts: [bucket_count]usize,    extra_counts: [bucket_count]usize,    offsets: [bucket_count + 1]usize,    slot_count: usize,    scratch_len: usize,    const Self = @This();    pub fn inspect(keys: []const u64, extra_outputs: []const u32) ShardMulBuildError!Self {        const total = std.math.add(usize, keys.len, extra_outputs.len) catch            return error.CapacityExceeded;        if (total > std.math.maxInt(u32)) return error.CapacityExceeded;        const engine = random.AesCtrEngine.initDeterministic();        var extra_counts: [bucket_count]usize = @splat(0);        for (extra_outputs) |value| extra_counts[value >> 28] += 1;        var best_seed: u64 = feistel_candidate_count;        var best_ratio: f32 = std.math.inf(f32);        for (0..feistel_candidate_count) |candidate| {            const candidate_seed: u64 = @intCast(candidate);            const shard = ShardMul.init(.{ .keys = makeFeistelKeys(&engine, candidate_seed) });            var counts = extra_counts;            for (keys) |key| counts[ShardMul.bucketIndex(shard.feistel(key).left)] += 1;            var minimum = counts[0];            var maximum = counts[0];            for (counts[1..]) |count| {                minimum = @min(minimum, count);                maximum = @max(maximum, count);            }            if (minimum == 0) continue;            const ratio = @as(f32, @floatFromInt(maximum)) /                @as(f32, @floatFromInt(minimum));            if (ratio < best_ratio) {                best_ratio = ratio;                best_seed = candidate_seed;            }        }        const shard = ShardMul.init(.{ .keys = makeFeistelKeys(&engine, best_seed) });        var key_counts: [bucket_count]usize = @splat(0);        for (keys) |key| key_counts[ShardMul.bucketIndex(shard.feistel(key).left)] += 1;        var offsets: [bucket_count + 1]usize = @splat(0);        var maximum_bucket_size: usize = 0;        for (0..bucket_count) |bucket| {            const bucket_size = std.math.add(                usize,                key_counts[bucket],                extra_counts[bucket],            ) catch return error.CapacityExceeded;            if (bucket_size > @as(usize, 1) << 28) return error.CapacityExceeded;            maximum_bucket_size = @max(maximum_bucket_size, bucket_size);            offsets[bucket + 1] = std.math.add(usize, offsets[bucket], bucket_size) catch                return error.CapacityExceeded;        }        std.debug.assert(offsets[bucket_count] == total);        const slot_count = try slotsFor(maximum_bucket_size);        const slot_u64 = std.math.divCeil(usize, slot_count, 2) catch unreachable;        const scratch_len = std.math.add(usize, total, slot_u64) catch            return error.CapacityExceeded;        return .{            .best_seed = best_seed,            .key_counts = key_counts,            .extra_counts = extra_counts,            .offsets = offsets,            .slot_count = slot_count,            .scratch_len = scratch_len,        };    }    pub fn build(        self: Self,        scratch: []u64,        keys: []const u64,        extra_outputs: []const u32,    ) ShardMulBuildError!ShardMulData {        if (scratch.len < self.scratch_len) return error.ScratchTooSmall;        const total = std.math.add(usize, keys.len, extra_outputs.len) catch            return error.CapacityExceeded;        if (total != self.offsets[bucket_count]) return error.PlanMismatch;        const engine = random.AesCtrEngine.initDeterministic();        const feistel_keys = makeFeistelKeys(&engine, self.best_seed);        const shard = ShardMul.init(.{ .keys = feistel_keys });        const records = scratch[0..total];        const slot_bytes = std.mem.sliceAsBytes(scratch[total..self.scratch_len]);        const all_slots = std.mem.bytesAsSlice(u32, slot_bytes)[0..self.slot_count];        var key_cursor = self.offsets[0..bucket_count].*;        var extra_cursor: [bucket_count]usize = undefined;        for (0..bucket_count) |bucket| {            extra_cursor[bucket] = self.offsets[bucket] + self.key_counts[bucket];        }        for (keys) |key| {            const pair = shard.feistel(key);            const bucket = ShardMul.bucketIndex(pair.left);            if (key_cursor[bucket] >= self.offsets[bucket] + self.key_counts[bucket]) {                return error.PlanMismatch;            }            records[key_cursor[bucket]] = encodePair(pair);            key_cursor[bucket] += 1;        }        for (extra_outputs) |value| {            const bucket = value >> 28;            if (extra_cursor[bucket] >= self.offsets[bucket + 1]) return error.PlanMismatch;            records[extra_cursor[bucket]] = value;            extra_cursor[bucket] += 1;        }        for (0..bucket_count) |bucket| {            if (key_cursor[bucket] != self.offsets[bucket] + self.key_counts[bucket] or                extra_cursor[bucket] != self.offsets[bucket + 1])            {                return error.PlanMismatch;            }        }        var data = ShardMulData{ .keys = feistel_keys };        for (0..bucket_count) |bucket| {            const bucket_size = self.key_counts[bucket] + self.extra_counts[bucket];            const slots = all_slots[0..try slotsFor(bucket_size)];            const first = self.offsets[bucket];            const key_records = records[first .. first + self.key_counts[bucket]];            const extras = records[first + self.key_counts[bucket] .. self.offsets[bucket + 1]];            for (0..max_attempts_per_bucket) |attempt| {                @memset(slots, 0);                var stream = random.RngStream.init(                    &engine,                    multiplierSeed(self.best_seed, bucket, attempt),                );                const muls = makeMultiplierPair(&stream);                var collision = false;                for (key_records) |encoded| {                    const pair = decodePair(encoded);                    const output = mulAndXorScalar(pair.left, pair.right, muls);                    if (!insertUnique(slots, output)) {                        collision = true;                        break;                    }                }                if (!collision) {                    for (extras) |encoded| {                        if (!insertUnique(slots, @truncate(encoded))) {                            collision = true;                            break;                        }                    }                }                if (!collision) {                    data.table[bucket] = muls;                    data.attempts[bucket] = @intCast(attempt + 1);                    break;                }            }            if (data.table[bucket] == 0) return .{};        }        return data;    }};

Source: lib/simd/src/root.zig:624

zig
pub const ShardMulPlan = shardmul.ShardMulPlan;
Called byCallsNo direct callersAesCtrEngineinitDeterministicRngStreaminitShardMulbucketIndexShardMulfeistelShardMulinit+8 moreShardMulPlanbuild
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsshardmulbuildShardMulshardmulshardMulScratchLentest sourcelib.simd.src.shardmultest: Highway ShardMul builder produc...test sourcelib.simd.src.shardmultest: Highway ShardMul builder remain...test sourcelib.simd.src.shardmultest: Highway ShardMul plans enforce ...test sourcelib.simd.src.shardmultest: Highway ShardMul single-worker ...AesCtrEngineinitDeterministicShardMulbucketIndexShardMulfeistelShardMulinitprivate sourcelib.simd.src.shardmulmakeFeistelKeysprivate sourcelib.simd.src.shardmulslotsForShardMulPlaninspect
Static calls · unresolved targets: 0 · external targets: 0.

Complete call list for ShardMulPlan.build

13 direct calls.

Audit

Definitions3
Public names6
Members6
Version26.7.0
Revisiondaab053ee433