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
signaturelock-open 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) {
185185 child: type,
186186 is_allowzero: bool,
187187
188 /// This field is an optional type.
188189 /// The type of the sentinel is the element type of the pointer, which is
189190 /// the value of the `child` field in this struct. However there is no way
190191 /// to refer to that type here, so we use `var`.
......@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
206207 len: comptime_int,
207208 child: type,
208209
210 /// This field is an optional type.
209211 /// The type of the sentinel is the element type of the array, which is
210212 /// the value of the `child` field in this struct. However there is no way
211213 /// 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 {
333333 }
334334 return array;
335335 },
336 .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {
337 @compileError("Can't set a "++ @typeName(T) ++" to zero.");
336 .Vector,
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.");
338350 },
339351 }
340352}
......@@ -470,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
470482 return true;
471483}
472484
485/// Deprecated. Use `length` or `indexOfSentinel`.
473486pub fn len(comptime T: type, ptr: [*:0]const T) usize {
474487 var count: usize = 0;
475488 while (ptr[count] != 0) : (count += 1) {}
476489 return count;
477490}
478491
492/// Deprecated. Use `span`.
479493pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
480494 return ptr[0..len(T, ptr) :0];
481495}
482496
497/// Deprecated. Use `span`.
483498pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
484499 return ptr[0..len(T, ptr) :0];
485500}
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
487601/// Returns true if all elements in a slice are equal to the scalar value provided
488602pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
489603 for (slice) |item| {