diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-03-01 13:07:55 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-03-01 13:07:55 -0500 |
| commit | 5b26128bacddf594dfe45958a236bfa2459f878b (patch) | |
| tree | 46843b88c41264e6ad4a3ffe5a743d94f7051b47 /lib/std | |
| parent | 4505857e30233d87f9ece403458c0988e8c68493 (diff) | |
| download | zig-5b26128bacddf594dfe45958a236bfa2459f878b.tar.gz zig-5b26128bacddf594dfe45958a236bfa2459f878b.zip | |
add new functions to std.mem and deprecate others
add std.mem.Span
add std.mem.span
add std.mem.length
add std.mem.indexOfSentinel
deprecate std.mem.len
deprecate std.mem.toSlice
deprecate std.mem.toSliceConst
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/builtin.zig | 2 | ||||
| -rw-r--r-- | lib/std/mem.zig | 118 |
2 files changed, 118 insertions, 2 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index de37fda903..a4f0ef269f 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) { child: type, is_allowzero: bool, + /// This field is an optional type. /// The type of the sentinel is the element type of the pointer, which is /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. @@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) { len: comptime_int, child: type, + /// This field is an optional type. /// The type of the sentinel is the element type of the array, which is /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. diff --git a/lib/std/mem.zig b/lib/std/mem.zig index a4b48bbc1c..775e999e0b 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T { } return array; }, - .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => { - @compileError("Can't set a "++ @typeName(T) ++" to zero."); + .Vector, + .ErrorUnion, + .ErrorSet, + .Union, + .Fn, + .BoundFn, + .Type, + .NoReturn, + .Undefined, + .Opaque, + .Frame, + .AnyFrame, + => { + @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); }, } } @@ -470,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { return true; } +/// Deprecated. Use `length` or `indexOfSentinel`. pub fn len(comptime T: type, ptr: [*:0]const T) usize { var count: usize = 0; while (ptr[count] != 0) : (count += 1) {} return count; } +/// Deprecated. Use `span`. pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { return ptr[0..len(T, ptr) :0]; } +/// Deprecated. Use `span`. pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { return ptr[0..len(T, ptr) :0]; } +/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and +/// returns a slice. If there is a sentinel on the input type, there will be a +/// sentinel on the output type. The constness of the output type matches +/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated. +pub fn Span(comptime T: type) type { + var ptr_info = @typeInfo(T).Pointer; + switch (ptr_info.size) { + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |info| { + ptr_info.child = info.child; + ptr_info.sentinel = info.sentinel; + }, + else => @compileError("invalid type given to std.mem.Span"), + }, + .C => { + ptr_info.sentinel = 0; + }, + .Many, .Slice => {}, + } + ptr_info.size = .Slice; + return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info }); +} + +test "Span" { + testing.expect(Span(*[5]u16) == []u16); + testing.expect(Span(*const [5]u16) == []const u16); + testing.expect(Span([]u16) == []u16); + testing.expect(Span([]const u8) == []const u8); + testing.expect(Span([:1]u16) == [:1]u16); + testing.expect(Span([:1]const u8) == [:1]const u8); + testing.expect(Span([*:1]u16) == [:1]u16); + testing.expect(Span([*:1]const u8) == [:1]const u8); + testing.expect(Span([*c]u16) == [:0]u16); + testing.expect(Span([*c]const u8) == [:0]const u8); +} + +/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and +/// returns a slice. If there is a sentinel on the input type, there will be a +/// sentinel on the output type. The constness of the output type matches +/// the constness of the input type. +pub fn span(ptr: var) Span(@TypeOf(ptr)) { + const Result = Span(@TypeOf(ptr)); + const l = length(ptr); + if (@typeInfo(Result).Pointer.sentinel) |s| { + return ptr[0..l :s]; + } else { + return ptr[0..l]; + } +} + +test "span" { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + const ptr = array[0..2 :3].ptr; + testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); + testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); +} + +/// Takes a pointer to an array, an array, a sentinel-terminated pointer, +/// or a slice, and returns the length. +pub fn length(ptr: var) usize { + return switch (@typeInfo(@TypeOf(ptr))) { + .Array => |info| info.len, + .Pointer => |info| switch (info.size) { + .One => switch (@typeInfo(info.child)) { + .Array => |x| x.len, + else => @compileError("invalid type given to std.mem.length"), + }, + .Many => if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, ptr) + else + @compileError("length of pointer with no sentinel"), + .C => indexOfSentinel(info.child, 0, ptr), + .Slice => ptr.len, + }, + else => @compileError("invalid type given to std.mem.length"), + }; +} + +test "length" { + testing.expect(length("aoeu") == 4); + + { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + testing.expect(length(&array) == 5); + testing.expect(length(array[0..3]) == 3); + array[2] = 0; + const ptr = array[0..2 :0].ptr; + testing.expect(length(ptr) == 2); + } +} + +pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { + var i: usize = 0; + while (ptr[i] != sentinel) { + i += 1; + } + return i; +} + /// Returns true if all elements in a slice are equal to the scalar value provided pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { for (slice) |item| { |
