Given a sentinel-terminated array [N:0]T
which is only partially filled at the beginning of the array with and unknown amount of entities n < N
, and the rest is filled with sentinels (0
), what's the most concise way to grab a slice only containing the first entities before any sentinel?
Here's a code example in linux, where utsname.release: [64:0]u8
is populated by the OS with the kernel's semantic version string.
const std = @import("std");
// ...
const utsname: std.os.linux.utsname = std.os.uname();
std.debug.print("utsname.release = '{s}'\n", .{utsname.release});
std.debug.print("utsname.release.len = {}\n", .{utsname.release.len});
const utsNameReleaseSlice: []const u8 = &utsname.release;
std.debug.print("utsNameReleaseSlice = '{s}'\n", .{utsNameReleaseSlice});
std.debug.print("utsNameReleaseSlice.len = {}\n", .{utsNameReleaseSlice.len});
output:
utsname.release = '6.6.8-gnu'
utsname.release.len = 64
utsNameReleaseSlice = '6.6.8-gnu'
utsNameReleaseSlice.len = 64
In the print above, the string looks ok but it prints out the sentinels which are zero-width characters. When I provide the slice to std.SemanticVersion.parse
it throws an error when it gets to those sentinel characters.
To fix this I got the index of the first sentinel and took a slice up to there:
const versionStringEnd: usize = std.mem.indexOf(u8, &utsname.release, &[_]u8{0}) orelse utsname.release.len;
const utsNameReleaseSlice: []const u8 = utsname.release[0..versionStringEnd];
std.debug.print("utsNameReleaseSlice = '{s}'\n", .{utsNameReleaseSlice});
std.debug.print("utsNameReleaseSlice.len = {}\n", .{utsNameReleaseSlice.len});
output:
utsNameReleaseSlice = '6.6.8-gnu'
utsNameReleaseSlice.len = 9
Is there a more concise way of getting this slice which ignores sentinels?
You're looking for std.mem.span
, which does exactly that.
Specifically, with the above example, you would need to cast the sentinel-terminated array as a sentinel-terminated pointer @as([*:0]const u8, &utsname.release)
and provide that to std.mem.span
:
const utsNameReleaseSlice: []const u8 = std.mem.span(@as([*:0]const u8, &utsname.release));