Skip to content

Commit

Permalink
Add string slice serializer (Zig)
Browse files Browse the repository at this point in the history
Part of the encode/decode strings LeetCode. This commit implements
string serialization using a Bencode-esque scheme.
  • Loading branch information
joshuamegnauth54 committed Nov 27, 2023
1 parent 7baf11c commit 9772340
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Zig/src/neet.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub const longest_prefix = @import("neet/longest_prefix.zig").longest_prefix;
pub const group_anagrams = @import("neet/group_anagrams.zig").group_anagrams;
pub const k_largest = @import("neet/k_largest.zig").k_largest;
pub const valid_sudoku = @import("neet/valid_sudoku.zig").valid_sudoku;
// pub const encode_str = @import("neet/")
pub const serialize_slice_str = @import("neet/encode_decode_strs.zig").serialize_slice_str;
pub const deserialize_slice_str = @import("neet/encode_decode_strs.zig").deserialize_slice_str;
// pub const logger_rate_limit =
// pub const ranked_voting
pub const prod_sans_self = @import("neet/prod_sans_self.zig").prod_sans_self;
Expand Down
77 changes: 77 additions & 0 deletions Zig/src/neet/encode_decode_strs.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const std = @import("std");
const fmt = std.fmt;
const Allocator = std.mem.Allocator;
const expectEqualStrings = std.testing.expectEqualStrings;

// Format string to serialize strings
// length:string
const ser_str_fmt = "{d}:{s}";

// Number of bytes required to serialize string.
fn serialized_str_len(s: []const u8) u64 {
return fmt.count(ser_str_fmt, .{ s.len, s });
}

// Serialize a single string
fn serialize_str(allocator: Allocator, s: []const u8) ![]const u8 {
return try fmt.allocPrint(allocator, ser_str_fmt, .{ s.len, s });
}

fn serialize_str_buf(buf: []u8, s: []const u8) !void {
_ = try fmt.bufPrint(buf, ser_str_fmt, .{ s.len, s });
}

pub fn serialize_slice_str(allocator: Allocator, strings: []const []const u8) ![]const u8 {
// Cumulative length of each prefix + string (total length of each serialized string)
var strs_offsets = try allocator.alloc(u64, strings.len);
defer allocator.destroy(strs_offsets.ptr);

// Length of entire buffer to serialize
var total_len: usize = 0;

// Calculate required lengths of each string
var i: usize = 0;
while (i < strings.len) : (i += 1) {
const slen = serialized_str_len(strings[i]);

// Offset should be the cumulative sum of string lengths up to but precluding i
// So the offset at i = 0 is 0
// Offset at i = 1 is the length of string #0
// Offset at i = 2 is len string #0 + len string #1...
strs_offsets[i] = total_len;
total_len += slen;
}

// Allocate buffer for entire serialized string
var ser_buf = try allocator.alloc(u8, total_len);
errdefer allocator.destroy(ser_buf.ptr);

i = 0;
while (i < strings.len) : (i += 1) {
const offset = strs_offsets[i];
const s = strings[i];
try serialize_str_buf(ser_buf[offset..], s);
}

return ser_buf;
}

test "serialize strings simple" {
const strings = [3][]const u8{ "Frieren", " is ", "awesome." };
const expected = "";

const actual = try serialize_slice_str(std.testing.allocator, &strings);
defer std.testing.allocator.destroy(actual.ptr);

try expectEqualStrings(expected, actual);
}

test "serialize strings empty" {
const strings = [1][]const u8{""};
const expected = "0:";

const actual = try serialize_slice_str(std.testing.allocator, &strings);
defer std.testing.allocator.destroy(actual.ptr);

try expectEqualStrings(expected, actual);
}

0 comments on commit 9772340

Please sign in to comment.