Skip to content

Commit 3be720a

Browse files
daurnimatorandrewrk
authored andcommitted
std: mem span functions can take an optional pointer
1 parent c1cc1eb commit 3be720a

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

lib/std/mem.zig

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -512,36 +512,54 @@ pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
512512
/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated,
513513
/// and assumed to not allow null.
514514
pub fn Span(comptime T: type) type {
515-
var ptr_info = @typeInfo(T).Pointer;
516-
switch (ptr_info.size) {
517-
.One => switch (@typeInfo(ptr_info.child)) {
518-
.Array => |info| {
519-
ptr_info.child = info.child;
520-
ptr_info.sentinel = info.sentinel;
521-
},
522-
else => @compileError("invalid type given to std.mem.Span"),
515+
switch(@typeInfo(T)) {
516+
.Optional => |optional_info| {
517+
return ?Span(optional_info.child);
523518
},
524-
.C => {
525-
ptr_info.sentinel = 0;
526-
ptr_info.is_allowzero = false;
519+
.Pointer => |ptr_info| {
520+
var new_ptr_info = ptr_info;
521+
switch (ptr_info.size) {
522+
.One => switch (@typeInfo(ptr_info.child)) {
523+
.Array => |info| {
524+
new_ptr_info.child = info.child;
525+
new_ptr_info.sentinel = info.sentinel;
526+
},
527+
else => @compileError("invalid type given to std.mem.Span"),
528+
},
529+
.C => {
530+
new_ptr_info.sentinel = 0;
531+
new_ptr_info.is_allowzero = false;
532+
},
533+
.Many, .Slice => {},
534+
}
535+
new_ptr_info.size = .Slice;
536+
return @Type(std.builtin.TypeInfo{ .Pointer = new_ptr_info });
527537
},
528-
.Many, .Slice => {},
538+
else => @compileError("invalid type given to std.mem.Span"),
529539
}
530-
ptr_info.size = .Slice;
531-
return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
532540
}
533541

534542
test "Span" {
535543
testing.expect(Span(*[5]u16) == []u16);
544+
testing.expect(Span(?*[5]u16) == ?[]u16);
536545
testing.expect(Span(*const [5]u16) == []const u16);
546+
testing.expect(Span(?*const [5]u16) == ?[]const u16);
537547
testing.expect(Span([]u16) == []u16);
548+
testing.expect(Span(?[]u16) == ?[]u16);
538549
testing.expect(Span([]const u8) == []const u8);
550+
testing.expect(Span(?[]const u8) == ?[]const u8);
539551
testing.expect(Span([:1]u16) == [:1]u16);
552+
testing.expect(Span(?[:1]u16) == ?[:1]u16);
540553
testing.expect(Span([:1]const u8) == [:1]const u8);
554+
testing.expect(Span(?[:1]const u8) == ?[:1]const u8);
541555
testing.expect(Span([*:1]u16) == [:1]u16);
556+
testing.expect(Span(?[*:1]u16) == ?[:1]u16);
542557
testing.expect(Span([*:1]const u8) == [:1]const u8);
558+
testing.expect(Span(?[*:1]const u8) == ?[:1]const u8);
543559
testing.expect(Span([*c]u16) == [:0]u16);
560+
testing.expect(Span(?[*c]u16) == ?[:0]u16);
544561
testing.expect(Span([*c]const u8) == [:0]const u8);
562+
testing.expect(Span(?[*c]const u8) == ?[:0]const u8);
545563
}
546564

547565
/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
@@ -553,6 +571,9 @@ test "Span" {
553571
/// length value is used instead of the sentinel.
554572
pub fn span(ptr: var) Span(@TypeOf(ptr)) {
555573
const Result = Span(@TypeOf(ptr));
574+
if (@typeInfo(@TypeOf(ptr)) == .Optional and ptr == null) {
575+
return null;
576+
}
556577
const l = len(ptr);
557578
if (@typeInfo(Result).Pointer.sentinel) |s| {
558579
return ptr[0..l :s];
@@ -573,6 +594,9 @@ test "span" {
573594
/// rather than using the length.
574595
pub fn spanZ(ptr: var) Span(@TypeOf(ptr)) {
575596
const Result = Span(@TypeOf(ptr));
597+
if (@typeInfo(@TypeOf(ptr)) == .Optional and ptr == null) {
598+
return null;
599+
}
576600
const l = lenZ(ptr);
577601
if (@typeInfo(Result).Pointer.sentinel) |s| {
578602
return ptr[0..l :s];

0 commit comments

Comments
 (0)