authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-01 13:07:55-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-01 13:07:55-05:00
log5b26128bacddf594dfe45958a236bfa2459f878b
tree46843b88c41264e6ad4a3ffe5a743d94f7051b47
parent4505857e30233d87f9ece403458c0988e8c68493
signature Commit is signed but in an unrecognized format.

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

2 files changed, 118 insertions(+), 2 deletions(-)

lib/std/builtin.zig+2
...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
185 child: type,185 child: type,
186 is_allowzero: bool,186 is_allowzero: bool,
187187
188 /// This field is an optional type.
188 /// The type of the sentinel is the element type of the pointer, which is189 /// The type of the sentinel is the element type of the pointer, which is
189 /// the value of the `child` field in this struct. However there is no way190 /// the value of the `child` field in this struct. However there is no way
190 /// to refer to that type here, so we use `var`.191 /// to refer to that type here, so we use `var`.
...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
206 len: comptime_int,207 len: comptime_int,
207 child: type,208 child: type,
208209
210 /// This field is an optional type.
209 /// The type of the sentinel is the element type of the array, which is211 /// The type of the sentinel is the element type of the array, which is
210 /// the value of the `child` field in this struct. However there is no way212 /// the value of the `child` field in this struct. However there is no way
211 /// to refer to that type here, so we use `var`.213 /// to refer to that type here, so we use `var`.
lib/std/mem.zig+116-2
...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
333 }333 }
334 return array;334 return array;
335 },335 },
336 .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {336 .Vector,
337 @compileError("Can't set a "++ @typeName(T) ++" to zero.");337 .ErrorUnion,
338 .ErrorSet,
339 .Union,
340 .Fn,
341 .BoundFn,
342 .Type,
343 .NoReturn,
344 .Undefined,
345 .Opaque,
346 .Frame,
347 .AnyFrame,
348 => {
349 @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
338 },350 },
339 }351 }
340}352}
...@@ -470,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -470,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
470 return true;482 return true;
471}483}
472484
485/// Deprecated. Use `length` or `indexOfSentinel`.
473pub fn len(comptime T: type, ptr: [*:0]const T) usize {486pub fn len(comptime T: type, ptr: [*:0]const T) usize {
474 var count: usize = 0;487 var count: usize = 0;
475 while (ptr[count] != 0) : (count += 1) {}488 while (ptr[count] != 0) : (count += 1) {}
476 return count;489 return count;
477}490}
478491
492/// Deprecated. Use `span`.
479pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {493pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
480 return ptr[0..len(T, ptr) :0];494 return ptr[0..len(T, ptr) :0];
481}495}
482496
497/// Deprecated. Use `span`.
483pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {498pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
484 return ptr[0..len(T, ptr) :0];499 return ptr[0..len(T, ptr) :0];
485}500}
486501
502/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
503/// returns a slice. If there is a sentinel on the input type, there will be a
504/// sentinel on the output type. The constness of the output type matches
505/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated.
506pub fn Span(comptime T: type) type {
507 var ptr_info = @typeInfo(T).Pointer;
508 switch (ptr_info.size) {
509 .One => switch (@typeInfo(ptr_info.child)) {
510 .Array => |info| {
511 ptr_info.child = info.child;
512 ptr_info.sentinel = info.sentinel;
513 },
514 else => @compileError("invalid type given to std.mem.Span"),
515 },
516 .C => {
517 ptr_info.sentinel = 0;
518 },
519 .Many, .Slice => {},
520 }
521 ptr_info.size = .Slice;
522 return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
523}
524
525test "Span" {
526 testing.expect(Span(*[5]u16) == []u16);
527 testing.expect(Span(*const [5]u16) == []const u16);
528 testing.expect(Span([]u16) == []u16);
529 testing.expect(Span([]const u8) == []const u8);
530 testing.expect(Span([:1]u16) == [:1]u16);
531 testing.expect(Span([:1]const u8) == [:1]const u8);
532 testing.expect(Span([*:1]u16) == [:1]u16);
533 testing.expect(Span([*:1]const u8) == [:1]const u8);
534 testing.expect(Span([*c]u16) == [:0]u16);
535 testing.expect(Span([*c]const u8) == [:0]const u8);
536}
537
538/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
539/// returns a slice. If there is a sentinel on the input type, there will be a
540/// sentinel on the output type. The constness of the output type matches
541/// the constness of the input type.
542pub fn span(ptr: var) Span(@TypeOf(ptr)) {
543 const Result = Span(@TypeOf(ptr));
544 const l = length(ptr);
545 if (@typeInfo(Result).Pointer.sentinel) |s| {
546 return ptr[0..l :s];
547 } else {
548 return ptr[0..l];
549 }
550}
551
552test "span" {
553 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
554 const ptr = array[0..2 :3].ptr;
555 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
556 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
557}
558
559/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
560/// or a slice, and returns the length.
561pub fn length(ptr: var) usize {
562 return switch (@typeInfo(@TypeOf(ptr))) {
563 .Array => |info| info.len,
564 .Pointer => |info| switch (info.size) {
565 .One => switch (@typeInfo(info.child)) {
566 .Array => |x| x.len,
567 else => @compileError("invalid type given to std.mem.length"),
568 },
569 .Many => if (info.sentinel) |sentinel|
570 indexOfSentinel(info.child, sentinel, ptr)
571 else
572 @compileError("length of pointer with no sentinel"),
573 .C => indexOfSentinel(info.child, 0, ptr),
574 .Slice => ptr.len,
575 },
576 else => @compileError("invalid type given to std.mem.length"),
577 };
578}
579
580test "length" {
581 testing.expect(length("aoeu") == 4);
582
583 {
584 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
585 testing.expect(length(&array) == 5);
586 testing.expect(length(array[0..3]) == 3);
587 array[2] = 0;
588 const ptr = array[0..2 :0].ptr;
589 testing.expect(length(ptr) == 2);
590 }
591}
592
593pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
594 var i: usize = 0;
595 while (ptr[i] != sentinel) {
596 i += 1;
597 }
598 return i;
599}
600
487/// Returns true if all elements in a slice are equal to the scalar value provided601/// Returns true if all elements in a slice are equal to the scalar value provided
488pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {602pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
489 for (slice) |item| {603 for (slice) |item| {