| ... | ... | @@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T { |
| 333 | 333 | } |
| 334 | 334 | return array; |
| 335 | 335 | }, |
| 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."); |
| 338 | 350 | }, |
| 339 | 351 | } |
| 340 | 352 | } |
| ... | ... | @@ -470,20 +482,122 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 470 | 482 | return true; |
| 471 | 483 | } |
| 472 | 484 | |
| 485 | /// Deprecated. Use `length` or `indexOfSentinel`. |
| 473 | 486 | pub fn len(comptime T: type, ptr: [*:0]const T) usize { |
| 474 | 487 | var count: usize = 0; |
| 475 | 488 | while (ptr[count] != 0) : (count += 1) {} |
| 476 | 489 | return count; |
| 477 | 490 | } |
| 478 | 491 | |
| 492 | /// Deprecated. Use `span`. |
| 479 | 493 | pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { |
| 480 | 494 | return ptr[0..len(T, ptr) :0]; |
| 481 | 495 | } |
| 482 | 496 | |
| 497 | /// Deprecated. Use `span`. |
| 483 | 498 | pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { |
| 484 | 499 | return ptr[0..len(T, ptr) :0]; |
| 485 | 500 | } |
| 486 | 501 | |
| 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. |
| 506 | pub 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 | |
| 525 | test "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. |
| 542 | pub 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 | |
| 552 | test "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. |
| 561 | pub 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 | |
| 580 | test "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 | |
| 593 | pub 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 | 601 | /// Returns true if all elements in a slice are equal to the scalar value provided |
| 488 | 602 | pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { |
| 489 | 603 | for (slice) |item| { |