Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/small_buf_map.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ pub fn SmallBufMap(comptime buffer_size: u8) type {
const Self = @This();

/// Assumes the existence of a key at i
inline fn getKey(self: Self, i: u8) []const u8 {
inline fn getKey(self: *const Self, i: u8) []const u8 {
const start = if (i == 0) 0 else self.buffer[buffer_size - (2 * i)];
const end = self.buffer[buffer_size - (2 * i) - 1];
return self.buffer[start..end];
}
/// Assumes the existence of a value at i
inline fn getValue(self: Self, i: u8) []const u8 {
inline fn getValue(self: *const Self, i: u8) []const u8 {
const start = self.buffer[buffer_size - (2 * i) - 1];
const end = self.buffer[buffer_size - (2 * i) - 2];
return self.buffer[start..end];
}
/// Assumes the existence of key+value at i
pub fn getKeyValue(self: Self, i: u8) [2][]const u8 {
pub fn getKeyValue(self: *const Self, i: u8) [2][]const u8 {
return [2][]const u8{ self.getKey(i), self.getValue(i) };
}

Expand All @@ -50,12 +50,12 @@ pub fn SmallBufMap(comptime buffer_size: u8) type {
@memcpy(self.buffer[key_end..value_end], value);
}

fn hasEntry(self: Self, i: u8) bool {
fn hasEntry(self: *const Self, i: u8) bool {
const offset = self.buffer[buffer_size - (2 * i) - 1];
return offset != 0;
}

pub fn count(self: Self) u8 {
pub fn count(self: *const Self) u8 {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The loop condition i < 256 in count (and similarly in getKeyIndex and getPutOp) can lead to an out-of-bounds access and runtime panic if the map is full.

Since each entry requires at least 2 bytes of metadata at the end of the buffer, the maximum number of entries is bounded by buffer_size / 2. When the map is full, hasEntry(i) will eventually attempt to access an index below zero (e.g., buffer_size - (2 * i) - 1).

Consider bounding the loop by buffer_size / 2 to ensure safety when the map reaches capacity.

var i: u8 = 0;
while (i < 256) : (i += 1) {
if (!self.hasEntry(i)) {
Expand All @@ -65,12 +65,12 @@ pub fn SmallBufMap(comptime buffer_size: u8) type {
return 255;
}

pub fn dataCount(self: Self) u8 {
pub fn dataCount(self: *const Self) u8 {
const c = self.count();
return if (c == 0) 0 else self.buffer[buffer_size - (2 * c)];
}

inline fn getKeyIndex(self: Self, key: []const u8) ?u8 {
inline fn getKeyIndex(self: *const Self, key: []const u8) ?u8 {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of getKeyIndex is redundant with getPutOp. Since the map is maintained in sorted order, getPutOp already performs an optimized search that exits early when it encounters a key greater than the target.

You could simplify this method by calling getPutOp and checking if the operation is .replace:

inline fn getKeyIndex(self: *const Self, key: []const u8) ?u8 {
    const res = self.getPutOp(key);
    return if (res.op == .replace) res.i else null;
}

This would improve maintainability and slightly improve performance for missing keys.

var i: u8 = 0;
while (i < 256) : (i += 1) {
if (!self.hasEntry(i)) {
Expand All @@ -84,14 +84,14 @@ pub fn SmallBufMap(comptime buffer_size: u8) type {
return null;
}

pub fn get(self: Self, key: []const u8) ?[]const u8 {
pub fn get(self: *const Self, key: []const u8) ?[]const u8 {
const i = self.getKeyIndex(key) orelse return null;
return self.getValue(i);
}

const PutOpType = enum { replace, insert, append };
const PutOp = struct { op: PutOpType, i: u8 };
fn getPutOp(self: Self, key: []const u8) PutOp {
fn getPutOp(self: *const Self, key: []const u8) PutOp {
var i: u8 = 0;
while (i < 256) : (i += 1) {
if (!self.hasEntry(i)) {
Expand Down