| author | |
| committer | |
| log | d8cecffe314230f1ff42391be98622ac8098833c |
| tree | 791ccaa082bd52364d68a1aeb630747a8fa69f90 |
| parent | 3914eaf3571949718bcd986ab8129b3c9f39b1d0 |
| parent | 8c11ada66caa011523e5c1019f9bb23c2db89231 |
| signature |
remove RingBuffer; remove BoundedArray; use `@memmove`17 files changed, 258 insertions(+), 807 deletions(-)
doc/langref/test_switch_dispatch_loop.zig+5-3| ... | ... | @@ -8,20 +8,22 @@ const Instruction = enum { |
| 8 | 8 | }; |
| 9 | 9 | |
| 10 | 10 | fn evaluate(initial_stack: []const i32, code: []const Instruction) !i32 { |
| 11 | var stack = try std.BoundedArray(i32, 8).fromSlice(initial_stack); | |
| 11 | var buffer: [8]i32 = undefined; | |
| 12 | var stack = std.ArrayListUnmanaged(i32).initBuffer(&buffer); | |
| 13 | try stack.appendSliceBounded(initial_stack); | |
| 12 | 14 | var ip: usize = 0; |
| 13 | 15 | |
| 14 | 16 | return vm: switch (code[ip]) { |
| 15 | 17 | // Because all code after `continue` is unreachable, this branch does |
| 16 | 18 | // not provide a result. |
| 17 | 19 | .add => { |
| 18 | try stack.append(stack.pop().? + stack.pop().?); | |
| 20 | try stack.appendBounded(stack.pop().? + stack.pop().?); | |
| 19 | 21 | |
| 20 | 22 | ip += 1; |
| 21 | 23 | continue :vm code[ip]; |
| 22 | 24 | }, |
| 23 | 25 | .mul => { |
| 24 | try stack.append(stack.pop().? * stack.pop().?); | |
| 26 | try stack.appendBounded(stack.pop().? * stack.pop().?); | |
| 25 | 27 | |
| 26 | 28 | ip += 1; |
| 27 | 29 | continue :vm code[ip]; |
lib/docs/wasm/markdown/Parser.zig+40-26| ... | ... | @@ -29,13 +29,14 @@ const Node = Document.Node; |
| 29 | 29 | const ExtraIndex = Document.ExtraIndex; |
| 30 | 30 | const ExtraData = Document.ExtraData; |
| 31 | 31 | const StringIndex = Document.StringIndex; |
| 32 | const ArrayList = std.ArrayListUnmanaged; | |
| 32 | 33 | |
| 33 | 34 | nodes: Node.List = .{}, |
| 34 | extra: std.ArrayListUnmanaged(u32) = .empty, | |
| 35 | scratch_extra: std.ArrayListUnmanaged(u32) = .empty, | |
| 36 | string_bytes: std.ArrayListUnmanaged(u8) = .empty, | |
| 37 | scratch_string: std.ArrayListUnmanaged(u8) = .empty, | |
| 38 | pending_blocks: std.ArrayListUnmanaged(Block) = .empty, | |
| 35 | extra: ArrayList(u32) = .empty, | |
| 36 | scratch_extra: ArrayList(u32) = .empty, | |
| 37 | string_bytes: ArrayList(u8) = .empty, | |
| 38 | scratch_string: ArrayList(u8) = .empty, | |
| 39 | pending_blocks: ArrayList(Block) = .empty, | |
| 39 | 40 | allocator: Allocator, |
| 40 | 41 | |
| 41 | 42 | const Parser = @This(); |
| ... | ... | @@ -86,7 +87,8 @@ const Block = struct { |
| 86 | 87 | continuation_indent: usize, |
| 87 | 88 | }, |
| 88 | 89 | table: struct { |
| 89 | column_alignments: std.BoundedArray(Node.TableCellAlignment, max_table_columns) = .{}, | |
| 90 | column_alignments_buffer: [max_table_columns]Node.TableCellAlignment, | |
| 91 | column_alignments_len: usize, | |
| 90 | 92 | }, |
| 91 | 93 | heading: struct { |
| 92 | 94 | /// Between 1 and 6, inclusive. |
| ... | ... | @@ -354,7 +356,8 @@ const BlockStart = struct { |
| 354 | 356 | continuation_indent: usize, |
| 355 | 357 | }, |
| 356 | 358 | table_row: struct { |
| 357 | cells: std.BoundedArray([]const u8, max_table_columns), | |
| 359 | cells_buffer: [max_table_columns][]const u8, | |
| 360 | cells_len: usize, | |
| 358 | 361 | }, |
| 359 | 362 | heading: struct { |
| 360 | 363 | /// Between 1 and 6, inclusive. |
| ... | ... | @@ -422,7 +425,8 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { |
| 422 | 425 | try p.pending_blocks.append(p.allocator, .{ |
| 423 | 426 | .tag = .table, |
| 424 | 427 | .data = .{ .table = .{ |
| 425 | .column_alignments = .{}, | |
| 428 | .column_alignments_buffer = undefined, | |
| 429 | .column_alignments_len = 0, | |
| 426 | 430 | } }, |
| 427 | 431 | .string_start = p.scratch_string.items.len, |
| 428 | 432 | .extra_start = p.scratch_extra.items.len, |
| ... | ... | @@ -431,15 +435,19 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { |
| 431 | 435 | |
| 432 | 436 | const current_row = p.scratch_extra.items.len - p.pending_blocks.getLast().extra_start; |
| 433 | 437 | if (current_row <= 1) { |
| 434 | if (parseTableHeaderDelimiter(block_start.data.table_row.cells)) |alignments| { | |
| 435 | p.pending_blocks.items[p.pending_blocks.items.len - 1].data.table.column_alignments = alignments; | |
| 438 | var buffer: [max_table_columns]Node.TableCellAlignment = undefined; | |
| 439 | const table_row = &block_start.data.table_row; | |
| 440 | if (parseTableHeaderDelimiter(table_row.cells_buffer[0..table_row.cells_len], &buffer)) |alignments| { | |
| 441 | const table = &p.pending_blocks.items[p.pending_blocks.items.len - 1].data.table; | |
| 442 | @memcpy(table.column_alignments_buffer[0..alignments.len], alignments); | |
| 443 | table.column_alignments_len = alignments.len; | |
| 436 | 444 | if (current_row == 1) { |
| 437 | 445 | // We need to go back and mark the header row and its column |
| 438 | 446 | // alignments. |
| 439 | 447 | const datas = p.nodes.items(.data); |
| 440 | 448 | const header_data = datas[p.scratch_extra.getLast()]; |
| 441 | 449 | for (p.extraChildren(header_data.container.children), 0..) |header_cell, i| { |
| 442 | const alignment = if (i < alignments.len) alignments.buffer[i] else .unset; | |
| 450 | const alignment = if (i < alignments.len) alignments[i] else .unset; | |
| 443 | 451 | const cell_data = &datas[@intFromEnum(header_cell)].table_cell; |
| 444 | 452 | cell_data.info.alignment = alignment; |
| 445 | 453 | cell_data.info.header = true; |
| ... | ... | @@ -480,8 +488,10 @@ fn appendBlockStart(p: *Parser, block_start: BlockStart) !void { |
| 480 | 488 | // available in the BlockStart. We can immediately parse and append |
| 481 | 489 | // these children now. |
| 482 | 490 | const containing_table = p.pending_blocks.items[p.pending_blocks.items.len - 2]; |
| 483 | const column_alignments = containing_table.data.table.column_alignments.slice(); | |
| 484 | for (block_start.data.table_row.cells.slice(), 0..) |cell_content, i| { | |
| 491 | const table = &containing_table.data.table; | |
| 492 | const column_alignments = table.column_alignments_buffer[0..table.column_alignments_len]; | |
| 493 | const table_row = &block_start.data.table_row; | |
| 494 | for (table_row.cells_buffer[0..table_row.cells_len], 0..) |cell_content, i| { | |
| 485 | 495 | const cell_children = try p.parseInlines(cell_content); |
| 486 | 496 | const alignment = if (i < column_alignments.len) column_alignments[i] else .unset; |
| 487 | 497 | const cell = try p.addNode(.{ |
| ... | ... | @@ -523,7 +533,8 @@ fn startBlock(p: *Parser, line: []const u8) !?BlockStart { |
| 523 | 533 | return .{ |
| 524 | 534 | .tag = .table_row, |
| 525 | 535 | .data = .{ .table_row = .{ |
| 526 | .cells = table_row.cells, | |
| 536 | .cells_buffer = table_row.cells_buffer, | |
| 537 | .cells_len = table_row.cells_len, | |
| 527 | 538 | } }, |
| 528 | 539 | .rest = "", |
| 529 | 540 | }; |
| ... | ... | @@ -606,7 +617,8 @@ fn startListItem(unindented_line: []const u8) ?ListItemStart { |
| 606 | 617 | } |
| 607 | 618 | |
| 608 | 619 | const TableRowStart = struct { |
| 609 | cells: std.BoundedArray([]const u8, max_table_columns), | |
| 620 | cells_buffer: [max_table_columns][]const u8, | |
| 621 | cells_len: usize, | |
| 610 | 622 | }; |
| 611 | 623 | |
| 612 | 624 | fn startTableRow(unindented_line: []const u8) ?TableRowStart { |
| ... | ... | @@ -615,7 +627,8 @@ fn startTableRow(unindented_line: []const u8) ?TableRowStart { |
| 615 | 627 | mem.endsWith(u8, unindented_line, "\\|") or |
| 616 | 628 | !mem.endsWith(u8, unindented_line, "|")) return null; |
| 617 | 629 | |
| 618 | var cells: std.BoundedArray([]const u8, max_table_columns) = .{}; | |
| 630 | var cells_buffer: [max_table_columns][]const u8 = undefined; | |
| 631 | var cells: ArrayList([]const u8) = .initBuffer(&cells_buffer); | |
| 619 | 632 | const table_row_content = unindented_line[1 .. unindented_line.len - 1]; |
| 620 | 633 | var cell_start: usize = 0; |
| 621 | 634 | var i: usize = 0; |
| ... | ... | @@ -623,7 +636,7 @@ fn startTableRow(unindented_line: []const u8) ?TableRowStart { |
| 623 | 636 | switch (table_row_content[i]) { |
| 624 | 637 | '\\' => i += 1, |
| 625 | 638 | '|' => { |
| 626 | cells.append(table_row_content[cell_start..i]) catch return null; | |
| 639 | cells.appendBounded(table_row_content[cell_start..i]) catch return null; | |
| 627 | 640 | cell_start = i + 1; |
| 628 | 641 | }, |
| 629 | 642 | '`' => { |
| ... | ... | @@ -641,20 +654,21 @@ fn startTableRow(unindented_line: []const u8) ?TableRowStart { |
| 641 | 654 | else => {}, |
| 642 | 655 | } |
| 643 | 656 | } |
| 644 | cells.append(table_row_content[cell_start..]) catch return null; | |
| 657 | cells.appendBounded(table_row_content[cell_start..]) catch return null; | |
| 645 | 658 | |
| 646 | return .{ .cells = cells }; | |
| 659 | return .{ .cells_buffer = cells_buffer, .cells_len = cells.items.len }; | |
| 647 | 660 | } |
| 648 | 661 | |
| 649 | 662 | fn parseTableHeaderDelimiter( |
| 650 | row_cells: std.BoundedArray([]const u8, max_table_columns), | |
| 651 | ) ?std.BoundedArray(Node.TableCellAlignment, max_table_columns) { | |
| 652 | var alignments: std.BoundedArray(Node.TableCellAlignment, max_table_columns) = .{}; | |
| 653 | for (row_cells.slice()) |content| { | |
| 663 | row_cells: []const []const u8, | |
| 664 | buffer: []Node.TableCellAlignment, | |
| 665 | ) ?[]Node.TableCellAlignment { | |
| 666 | var alignments: ArrayList(Node.TableCellAlignment) = .initBuffer(buffer); | |
| 667 | for (row_cells) |content| { | |
| 654 | 668 | const alignment = parseTableHeaderDelimiterCell(content) orelse return null; |
| 655 | 669 | alignments.appendAssumeCapacity(alignment); |
| 656 | 670 | } |
| 657 | return alignments; | |
| 671 | return alignments.items; | |
| 658 | 672 | } |
| 659 | 673 | |
| 660 | 674 | fn parseTableHeaderDelimiterCell(content: []const u8) ?Node.TableCellAlignment { |
| ... | ... | @@ -928,8 +942,8 @@ const InlineParser = struct { |
| 928 | 942 | parent: *Parser, |
| 929 | 943 | content: []const u8, |
| 930 | 944 | pos: usize = 0, |
| 931 | pending_inlines: std.ArrayListUnmanaged(PendingInline) = .empty, | |
| 932 | completed_inlines: std.ArrayListUnmanaged(CompletedInline) = .empty, | |
| 945 | pending_inlines: ArrayList(PendingInline) = .empty, | |
| 946 | completed_inlines: ArrayList(CompletedInline) = .empty, | |
| 933 | 947 | |
| 934 | 948 | const PendingInline = struct { |
| 935 | 949 | tag: Tag, |
lib/std/Io.zig-15| ... | ... | @@ -231,21 +231,6 @@ pub fn GenericReader( |
| 231 | 231 | return @errorCast(self.any().readBytesNoEof(num_bytes)); |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | pub inline fn readIntoBoundedBytes( | |
| 235 | self: Self, | |
| 236 | comptime num_bytes: usize, | |
| 237 | bounded: *std.BoundedArray(u8, num_bytes), | |
| 238 | ) Error!void { | |
| 239 | return @errorCast(self.any().readIntoBoundedBytes(num_bytes, bounded)); | |
| 240 | } | |
| 241 | ||
| 242 | pub inline fn readBoundedBytes( | |
| 243 | self: Self, | |
| 244 | comptime num_bytes: usize, | |
| 245 | ) Error!std.BoundedArray(u8, num_bytes) { | |
| 246 | return @errorCast(self.any().readBoundedBytes(num_bytes)); | |
| 247 | } | |
| 248 | ||
| 249 | 234 | pub inline fn readInt(self: Self, comptime T: type, endian: std.builtin.Endian) NoEofError!T { |
| 250 | 235 | return @errorCast(self.any().readInt(T, endian)); |
| 251 | 236 | } |
lib/std/Io/DeprecatedReader.zig-27| ... | ... | @@ -249,33 +249,6 @@ pub fn readBytesNoEof(self: Self, comptime num_bytes: usize) anyerror![num_bytes |
| 249 | 249 | return bytes; |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | /// Reads bytes until `bounded.len` is equal to `num_bytes`, | |
| 253 | /// or the stream ends. | |
| 254 | /// | |
| 255 | /// * it is assumed that `num_bytes` will not exceed `bounded.capacity()` | |
| 256 | pub fn readIntoBoundedBytes( | |
| 257 | self: Self, | |
| 258 | comptime num_bytes: usize, | |
| 259 | bounded: *std.BoundedArray(u8, num_bytes), | |
| 260 | ) anyerror!void { | |
| 261 | while (bounded.len < num_bytes) { | |
| 262 | // get at most the number of bytes free in the bounded array | |
| 263 | const bytes_read = try self.read(bounded.unusedCapacitySlice()); | |
| 264 | if (bytes_read == 0) return; | |
| 265 | ||
| 266 | // bytes_read will never be larger than @TypeOf(bounded.len) | |
| 267 | // due to `self.read` being bounded by `bounded.unusedCapacitySlice()` | |
| 268 | bounded.len += @as(@TypeOf(bounded.len), @intCast(bytes_read)); | |
| 269 | } | |
| 270 | } | |
| 271 | ||
| 272 | /// Reads at most `num_bytes` and returns as a bounded array. | |
| 273 | pub fn readBoundedBytes(self: Self, comptime num_bytes: usize) anyerror!std.BoundedArray(u8, num_bytes) { | |
| 274 | var result = std.BoundedArray(u8, num_bytes){}; | |
| 275 | try self.readIntoBoundedBytes(num_bytes, &result); | |
| 276 | return result; | |
| 277 | } | |
| 278 | ||
| 279 | 252 | pub inline fn readInt(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T { |
| 280 | 253 | const bytes = try self.readBytesNoEof(@divExact(@typeInfo(T).int.bits, 8)); |
| 281 | 254 | return mem.readInt(T, &bytes, endian); |
lib/std/Io/Reader/test.zig-21| ... | ... | @@ -349,24 +349,3 @@ test "streamUntilDelimiter writes all bytes without delimiter to the output" { |
| 349 | 349 | |
| 350 | 350 | try std.testing.expectError(error.StreamTooLong, reader.streamUntilDelimiter(writer, '!', 5)); |
| 351 | 351 | } |
| 352 | ||
| 353 | test "readBoundedBytes correctly reads into a new bounded array" { | |
| 354 | const test_string = "abcdefg"; | |
| 355 | var fis = std.io.fixedBufferStream(test_string); | |
| 356 | const reader = fis.reader(); | |
| 357 | ||
| 358 | var array = try reader.readBoundedBytes(10000); | |
| 359 | try testing.expectEqualStrings(array.slice(), test_string); | |
| 360 | } | |
| 361 | ||
| 362 | test "readIntoBoundedBytes correctly reads into a provided bounded array" { | |
| 363 | const test_string = "abcdefg"; | |
| 364 | var fis = std.io.fixedBufferStream(test_string); | |
| 365 | const reader = fis.reader(); | |
| 366 | ||
| 367 | var bounded_array = std.BoundedArray(u8, 10000){}; | |
| 368 | ||
| 369 | // compile time error if the size is not the same at the provided `bounded.capacity()` | |
| 370 | try reader.readIntoBoundedBytes(10000, &bounded_array); | |
| 371 | try testing.expectEqualStrings(bounded_array.slice(), test_string); | |
| 372 | } |
lib/std/Progress.zig+1-1| ... | ... | @@ -1006,7 +1006,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 1006 | 1006 | continue; |
| 1007 | 1007 | } |
| 1008 | 1008 | const src = pipe_buf[m.remaining_read_trash_bytes..n]; |
| 1009 | std.mem.copyForwards(u8, &pipe_buf, src); | |
| 1009 | @memmove(pipe_buf[0..src.len], src); | |
| 1010 | 1010 | m.remaining_read_trash_bytes = 0; |
| 1011 | 1011 | bytes_read = src.len; |
| 1012 | 1012 | continue; |
lib/std/RingBuffer.zig deleted-230| ... | ... | @@ -1,230 +0,0 @@ |
| 1 | //! This ring buffer stores read and write indices while being able to utilise | |
| 2 | //! the full backing slice by incrementing the indices modulo twice the slice's | |
| 3 | //! length and reducing indices modulo the slice's length on slice access. This | |
| 4 | //! means that whether the ring buffer is full or empty can be distinguished by | |
| 5 | //! looking at the difference between the read and write indices without adding | |
| 6 | //! an extra boolean flag or having to reserve a slot in the buffer. | |
| 7 | //! | |
| 8 | //! This ring buffer has not been implemented with thread safety in mind, and | |
| 9 | //! therefore should not be assumed to be suitable for use cases involving | |
| 10 | //! separate reader and writer threads. | |
| 11 | ||
| 12 | const Allocator = @import("std").mem.Allocator; | |
| 13 | const assert = @import("std").debug.assert; | |
| 14 | const copyForwards = @import("std").mem.copyForwards; | |
| 15 | ||
| 16 | const RingBuffer = @This(); | |
| 17 | ||
| 18 | data: []u8, | |
| 19 | read_index: usize, | |
| 20 | write_index: usize, | |
| 21 | ||
| 22 | pub const Error = error{ Full, ReadLengthInvalid }; | |
| 23 | ||
| 24 | /// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer. | |
| 25 | pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer { | |
| 26 | const bytes = try allocator.alloc(u8, capacity); | |
| 27 | return RingBuffer{ | |
| 28 | .data = bytes, | |
| 29 | .write_index = 0, | |
| 30 | .read_index = 0, | |
| 31 | }; | |
| 32 | } | |
| 33 | ||
| 34 | /// Free the data backing a `RingBuffer`; must be passed the same `Allocator` as | |
| 35 | /// `init()`. | |
| 36 | pub fn deinit(self: *RingBuffer, allocator: Allocator) void { | |
| 37 | allocator.free(self.data); | |
| 38 | self.* = undefined; | |
| 39 | } | |
| 40 | ||
| 41 | /// Returns `index` modulo the length of the backing slice. | |
| 42 | pub fn mask(self: RingBuffer, index: usize) usize { | |
| 43 | return index % self.data.len; | |
| 44 | } | |
| 45 | ||
| 46 | /// Returns `index` modulo twice the length of the backing slice. | |
| 47 | pub fn mask2(self: RingBuffer, index: usize) usize { | |
| 48 | return index % (2 * self.data.len); | |
| 49 | } | |
| 50 | ||
| 51 | /// Write `byte` into the ring buffer. Returns `error.Full` if the ring | |
| 52 | /// buffer is full. | |
| 53 | pub fn write(self: *RingBuffer, byte: u8) Error!void { | |
| 54 | if (self.isFull()) return error.Full; | |
| 55 | self.writeAssumeCapacity(byte); | |
| 56 | } | |
| 57 | ||
| 58 | /// Write `byte` into the ring buffer. If the ring buffer is full, the | |
| 59 | /// oldest byte is overwritten. | |
| 60 | pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void { | |
| 61 | self.data[self.mask(self.write_index)] = byte; | |
| 62 | self.write_index = self.mask2(self.write_index + 1); | |
| 63 | } | |
| 64 | ||
| 65 | /// Write `bytes` into the ring buffer. Returns `error.Full` if the ring | |
| 66 | /// buffer does not have enough space, without writing any data. | |
| 67 | /// Uses memcpy and so `bytes` must not overlap ring buffer data. | |
| 68 | pub fn writeSlice(self: *RingBuffer, bytes: []const u8) Error!void { | |
| 69 | if (self.len() + bytes.len > self.data.len) return error.Full; | |
| 70 | self.writeSliceAssumeCapacity(bytes); | |
| 71 | } | |
| 72 | ||
| 73 | /// Write `bytes` into the ring buffer. If there is not enough space, older | |
| 74 | /// bytes will be overwritten. | |
| 75 | /// Uses memcpy and so `bytes` must not overlap ring buffer data. | |
| 76 | pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void { | |
| 77 | assert(bytes.len <= self.data.len); | |
| 78 | const data_start = self.mask(self.write_index); | |
| 79 | const part1_data_end = @min(data_start + bytes.len, self.data.len); | |
| 80 | const part1_len = part1_data_end - data_start; | |
| 81 | @memcpy(self.data[data_start..part1_data_end], bytes[0..part1_len]); | |
| 82 | ||
| 83 | const remaining = bytes.len - part1_len; | |
| 84 | const to_write = @min(remaining, remaining % self.data.len + self.data.len); | |
| 85 | const part2_bytes_start = bytes.len - to_write; | |
| 86 | const part2_bytes_end = @min(part2_bytes_start + self.data.len, bytes.len); | |
| 87 | const part2_len = part2_bytes_end - part2_bytes_start; | |
| 88 | @memcpy(self.data[0..part2_len], bytes[part2_bytes_start..part2_bytes_end]); | |
| 89 | if (part2_bytes_end != bytes.len) { | |
| 90 | const part3_len = bytes.len - part2_bytes_end; | |
| 91 | @memcpy(self.data[0..part3_len], bytes[part2_bytes_end..bytes.len]); | |
| 92 | } | |
| 93 | self.write_index = self.mask2(self.write_index + bytes.len); | |
| 94 | } | |
| 95 | ||
| 96 | /// Write `bytes` into the ring buffer. Returns `error.Full` if the ring | |
| 97 | /// buffer does not have enough space, without writing any data. | |
| 98 | /// Uses copyForwards and can write slices from this RingBuffer into itself. | |
| 99 | pub fn writeSliceForwards(self: *RingBuffer, bytes: []const u8) Error!void { | |
| 100 | if (self.len() + bytes.len > self.data.len) return error.Full; | |
| 101 | self.writeSliceForwardsAssumeCapacity(bytes); | |
| 102 | } | |
| 103 | ||
| 104 | /// Write `bytes` into the ring buffer. If there is not enough space, older | |
| 105 | /// bytes will be overwritten. | |
| 106 | /// Uses copyForwards and can write slices from this RingBuffer into itself. | |
| 107 | pub fn writeSliceForwardsAssumeCapacity(self: *RingBuffer, bytes: []const u8) void { | |
| 108 | assert(bytes.len <= self.data.len); | |
| 109 | const data_start = self.mask(self.write_index); | |
| 110 | const part1_data_end = @min(data_start + bytes.len, self.data.len); | |
| 111 | const part1_len = part1_data_end - data_start; | |
| 112 | copyForwards(u8, self.data[data_start..], bytes[0..part1_len]); | |
| 113 | ||
| 114 | const remaining = bytes.len - part1_len; | |
| 115 | const to_write = @min(remaining, remaining % self.data.len + self.data.len); | |
| 116 | const part2_bytes_start = bytes.len - to_write; | |
| 117 | const part2_bytes_end = @min(part2_bytes_start + self.data.len, bytes.len); | |
| 118 | copyForwards(u8, self.data[0..], bytes[part2_bytes_start..part2_bytes_end]); | |
| 119 | if (part2_bytes_end != bytes.len) | |
| 120 | copyForwards(u8, self.data[0..], bytes[part2_bytes_end..bytes.len]); | |
| 121 | self.write_index = self.mask2(self.write_index + bytes.len); | |
| 122 | } | |
| 123 | ||
| 124 | /// Consume a byte from the ring buffer and return it. Returns `null` if the | |
| 125 | /// ring buffer is empty. | |
| 126 | pub fn read(self: *RingBuffer) ?u8 { | |
| 127 | if (self.isEmpty()) return null; | |
| 128 | return self.readAssumeLength(); | |
| 129 | } | |
| 130 | ||
| 131 | /// Consume a byte from the ring buffer and return it; asserts that the buffer | |
| 132 | /// is not empty. | |
| 133 | pub fn readAssumeLength(self: *RingBuffer) u8 { | |
| 134 | assert(!self.isEmpty()); | |
| 135 | const byte = self.data[self.mask(self.read_index)]; | |
| 136 | self.read_index = self.mask2(self.read_index + 1); | |
| 137 | return byte; | |
| 138 | } | |
| 139 | ||
| 140 | /// Reads first `length` bytes written to the ring buffer into `dest`; Returns | |
| 141 | /// Error.ReadLengthInvalid if length greater than ring or dest length | |
| 142 | /// Uses memcpy and so `dest` must not overlap ring buffer data. | |
| 143 | pub fn readFirst(self: *RingBuffer, dest: []u8, length: usize) Error!void { | |
| 144 | if (length > self.len() or length > dest.len) return error.ReadLengthInvalid; | |
| 145 | self.readFirstAssumeLength(dest, length); | |
| 146 | } | |
| 147 | ||
| 148 | /// Reads first `length` bytes written to the ring buffer into `dest`; | |
| 149 | /// Asserts that length not greater than ring buffer or dest length | |
| 150 | /// Uses memcpy and so `dest` must not overlap ring buffer data. | |
| 151 | pub fn readFirstAssumeLength(self: *RingBuffer, dest: []u8, length: usize) void { | |
| 152 | assert(length <= self.len() and length <= dest.len); | |
| 153 | const slice = self.sliceAt(self.read_index, length); | |
| 154 | slice.copyTo(dest); | |
| 155 | self.read_index = self.mask2(self.read_index + length); | |
| 156 | } | |
| 157 | ||
| 158 | /// Reads last `length` bytes written to the ring buffer into `dest`; Returns | |
| 159 | /// Error.ReadLengthInvalid if length greater than ring or dest length | |
| 160 | /// Uses memcpy and so `dest` must not overlap ring buffer data. | |
| 161 | /// Reduces write index by `length`. | |
| 162 | pub fn readLast(self: *RingBuffer, dest: []u8, length: usize) Error!void { | |
| 163 | if (length > self.len() or length > dest.len) return error.ReadLengthInvalid; | |
| 164 | self.readLastAssumeLength(dest, length); | |
| 165 | } | |
| 166 | ||
| 167 | /// Reads last `length` bytes written to the ring buffer into `dest`; | |
| 168 | /// Asserts that length not greater than ring buffer or dest length | |
| 169 | /// Uses memcpy and so `dest` must not overlap ring buffer data. | |
| 170 | /// Reduces write index by `length`. | |
| 171 | pub fn readLastAssumeLength(self: *RingBuffer, dest: []u8, length: usize) void { | |
| 172 | assert(length <= self.len() and length <= dest.len); | |
| 173 | const slice = self.sliceLast(length); | |
| 174 | slice.copyTo(dest); | |
| 175 | self.write_index = if (self.write_index >= self.data.len) | |
| 176 | self.write_index - length | |
| 177 | else | |
| 178 | self.mask(self.write_index + self.data.len - length); | |
| 179 | } | |
| 180 | ||
| 181 | /// Returns `true` if the ring buffer is empty and `false` otherwise. | |
| 182 | pub fn isEmpty(self: RingBuffer) bool { | |
| 183 | return self.write_index == self.read_index; | |
| 184 | } | |
| 185 | ||
| 186 | /// Returns `true` if the ring buffer is full and `false` otherwise. | |
| 187 | pub fn isFull(self: RingBuffer) bool { | |
| 188 | return self.mask2(self.write_index + self.data.len) == self.read_index; | |
| 189 | } | |
| 190 | ||
| 191 | /// Returns the length of data available for reading | |
| 192 | pub fn len(self: RingBuffer) usize { | |
| 193 | const wrap_offset = 2 * self.data.len * @intFromBool(self.write_index < self.read_index); | |
| 194 | const adjusted_write_index = self.write_index + wrap_offset; | |
| 195 | return adjusted_write_index - self.read_index; | |
| 196 | } | |
| 197 | ||
| 198 | /// A `Slice` represents a region of a ring buffer. The region is split into two | |
| 199 | /// sections as the ring buffer data will not be contiguous if the desired | |
| 200 | /// region wraps to the start of the backing slice. | |
| 201 | pub const Slice = struct { | |
| 202 | first: []u8, | |
| 203 | second: []u8, | |
| 204 | ||
| 205 | /// Copy data from `self` into `dest` | |
| 206 | pub fn copyTo(self: Slice, dest: []u8) void { | |
| 207 | @memcpy(dest[0..self.first.len], self.first); | |
| 208 | @memcpy(dest[self.first.len..][0..self.second.len], self.second); | |
| 209 | } | |
| 210 | }; | |
| 211 | ||
| 212 | /// Returns a `Slice` for the region of the ring buffer starting at | |
| 213 | /// `self.mask(start_unmasked)` with the specified length. | |
| 214 | pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice { | |
| 215 | assert(length <= self.data.len); | |
| 216 | const slice1_start = self.mask(start_unmasked); | |
| 217 | const slice1_end = @min(self.data.len, slice1_start + length); | |
| 218 | const slice1 = self.data[slice1_start..slice1_end]; | |
| 219 | const slice2 = self.data[0 .. length - slice1.len]; | |
| 220 | return Slice{ | |
| 221 | .first = slice1, | |
| 222 | .second = slice2, | |
| 223 | }; | |
| 224 | } | |
| 225 | ||
| 226 | /// Returns a `Slice` for the last `length` bytes written to the ring buffer. | |
| 227 | /// Does not check that any bytes have been written into the region. | |
| 228 | pub fn sliceLast(self: RingBuffer, length: usize) Slice { | |
| 229 | return self.sliceAt(self.write_index + self.data.len - length, length); | |
| 230 | } |
lib/std/array_list.zig+174-16| ... | ... | @@ -158,7 +158,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty |
| 158 | 158 | assert(self.items.len < self.capacity); |
| 159 | 159 | self.items.len += 1; |
| 160 | 160 | |
| 161 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); | |
| 161 | @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); | |
| 162 | 162 | self.items[i] = item; |
| 163 | 163 | } |
| 164 | 164 | |
| ... | ... | @@ -216,7 +216,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty |
| 216 | 216 | assert(self.capacity >= new_len); |
| 217 | 217 | const to_move = self.items[index..]; |
| 218 | 218 | self.items.len = new_len; |
| 219 | mem.copyBackwards(T, self.items[index + count ..], to_move); | |
| 219 | @memmove(self.items[index + count ..][0..to_move.len], to_move); | |
| 220 | 220 | const result = self.items[index..][0..count]; |
| 221 | 221 | @memset(result, undefined); |
| 222 | 222 | return result; |
| ... | ... | @@ -657,6 +657,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 657 | 657 | |
| 658 | 658 | /// Initialize with externally-managed memory. The buffer determines the |
| 659 | 659 | /// capacity, and the length is set to zero. |
| 660 | /// | |
| 660 | 661 | /// When initialized this way, all functions that accept an Allocator |
| 661 | 662 | /// argument cause illegal behavior. |
| 662 | 663 | pub fn initBuffer(buffer: Slice) Self { |
| ... | ... | @@ -738,18 +739,37 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 738 | 739 | } |
| 739 | 740 | |
| 740 | 741 | /// Insert `item` at index `i`. Moves `list[i .. list.len]` to higher indices to make room. |
| 741 | /// If in` is equal to the length of the list this operation is equivalent to append. | |
| 742 | /// | |
| 743 | /// If `i` is equal to the length of the list this operation is equivalent to append. | |
| 744 | /// | |
| 742 | 745 | /// This operation is O(N). |
| 746 | /// | |
| 743 | 747 | /// Asserts that the list has capacity for one additional item. |
| 748 | /// | |
| 744 | 749 | /// Asserts that the index is in bounds or equal to the length. |
| 745 | 750 | pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { |
| 746 | 751 | assert(self.items.len < self.capacity); |
| 747 | 752 | self.items.len += 1; |
| 748 | 753 | |
| 749 | mem.copyBackwards(T, self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); | |
| 754 | @memmove(self.items[i + 1 .. self.items.len], self.items[i .. self.items.len - 1]); | |
| 750 | 755 | self.items[i] = item; |
| 751 | 756 | } |
| 752 | 757 | |
| 758 | /// Insert `item` at index `i`, moving `list[i .. list.len]` to higher indices to make room. | |
| 759 | /// | |
| 760 | /// If `i` is equal to the length of the list this operation is equivalent to append. | |
| 761 | /// | |
| 762 | /// This operation is O(N). | |
| 763 | /// | |
| 764 | /// If the list lacks unused capacity for the additional item, returns | |
| 765 | /// `error.OutOfMemory`. | |
| 766 | /// | |
| 767 | /// Asserts that the index is in bounds or equal to the length. | |
| 768 | pub fn insertBounded(self: *Self, i: usize, item: T) error{OutOfMemory}!void { | |
| 769 | if (self.capacity - self.items.len == 0) return error.OutOfMemory; | |
| 770 | return insertAssumeCapacity(self, i, item); | |
| 771 | } | |
| 772 | ||
| 753 | 773 | /// Add `count` new elements at position `index`, which have |
| 754 | 774 | /// `undefined` values. Returns a slice pointing to the newly allocated |
| 755 | 775 | /// elements, which becomes invalid after various `ArrayList` |
| ... | ... | @@ -782,12 +802,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 782 | 802 | assert(self.capacity >= new_len); |
| 783 | 803 | const to_move = self.items[index..]; |
| 784 | 804 | self.items.len = new_len; |
| 785 | mem.copyBackwards(T, self.items[index + count ..], to_move); | |
| 805 | @memmove(self.items[index + count ..][0..to_move.len], to_move); | |
| 786 | 806 | const result = self.items[index..][0..count]; |
| 787 | 807 | @memset(result, undefined); |
| 788 | 808 | return result; |
| 789 | 809 | } |
| 790 | 810 | |
| 811 | /// Add `count` new elements at position `index`, which have | |
| 812 | /// `undefined` values, returning a slice pointing to the newly | |
| 813 | /// allocated elements, which becomes invalid after various `ArrayList` | |
| 814 | /// operations. | |
| 815 | /// | |
| 816 | /// Invalidates pre-existing pointers to elements at and after `index`, but | |
| 817 | /// does not invalidate any before that. | |
| 818 | /// | |
| 819 | /// If the list lacks unused capacity for the additional items, returns | |
| 820 | /// `error.OutOfMemory`. | |
| 821 | /// | |
| 822 | /// Asserts that the index is in bounds or equal to the length. | |
| 823 | pub fn addManyAtBounded(self: *Self, index: usize, count: usize) error{OutOfMemory}![]T { | |
| 824 | if (self.capacity - self.items.len < count) return error.OutOfMemory; | |
| 825 | return addManyAtAssumeCapacity(self, index, count); | |
| 826 | } | |
| 827 | ||
| 791 | 828 | /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room. |
| 792 | 829 | /// This operation is O(N). |
| 793 | 830 | /// Invalidates pre-existing pointers to elements at and after `index`. |
| ... | ... | @@ -831,7 +868,9 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 831 | 868 | } |
| 832 | 869 | |
| 833 | 870 | /// Grows or shrinks the list as necessary. |
| 871 | /// | |
| 834 | 872 | /// Never invalidates element pointers. |
| 873 | /// | |
| 835 | 874 | /// Asserts the capacity is enough for additional items. |
| 836 | 875 | pub fn replaceRangeAssumeCapacity(self: *Self, start: usize, len: usize, new_items: []const T) void { |
| 837 | 876 | const after_range = start + len; |
| ... | ... | @@ -848,16 +887,24 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 848 | 887 | } else { |
| 849 | 888 | const extra = range.len - new_items.len; |
| 850 | 889 | @memcpy(range[0..new_items.len], new_items); |
| 851 | std.mem.copyForwards( | |
| 852 | T, | |
| 853 | self.items[after_range - extra ..], | |
| 854 | self.items[after_range..], | |
| 855 | ); | |
| 890 | const src = self.items[after_range..]; | |
| 891 | @memmove(self.items[after_range - extra ..][0..src.len], src); | |
| 856 | 892 | @memset(self.items[self.items.len - extra ..], undefined); |
| 857 | 893 | self.items.len -= extra; |
| 858 | 894 | } |
| 859 | 895 | } |
| 860 | 896 | |
| 897 | /// Grows or shrinks the list as necessary. | |
| 898 | /// | |
| 899 | /// Never invalidates element pointers. | |
| 900 | /// | |
| 901 | /// If the unused capacity is insufficient for additional items, | |
| 902 | /// returns `error.OutOfMemory`. | |
| 903 | pub fn replaceRangeBounded(self: *Self, start: usize, len: usize, new_items: []const T) error{OutOfMemory}!void { | |
| 904 | if (self.capacity - self.items.len < new_items.len -| len) return error.OutOfMemory; | |
| 905 | return replaceRangeAssumeCapacity(self, start, len, new_items); | |
| 906 | } | |
| 907 | ||
| 861 | 908 | /// Extend the list by 1 element. Allocates more memory as necessary. |
| 862 | 909 | /// Invalidates element pointers if additional memory is needed. |
| 863 | 910 | pub fn append(self: *Self, gpa: Allocator, item: T) Allocator.Error!void { |
| ... | ... | @@ -866,12 +913,25 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 866 | 913 | } |
| 867 | 914 | |
| 868 | 915 | /// Extend the list by 1 element. |
| 916 | /// | |
| 869 | 917 | /// Never invalidates element pointers. |
| 918 | /// | |
| 870 | 919 | /// Asserts that the list can hold one additional item. |
| 871 | 920 | pub fn appendAssumeCapacity(self: *Self, item: T) void { |
| 872 | 921 | self.addOneAssumeCapacity().* = item; |
| 873 | 922 | } |
| 874 | 923 | |
| 924 | /// Extend the list by 1 element. | |
| 925 | /// | |
| 926 | /// Never invalidates element pointers. | |
| 927 | /// | |
| 928 | /// If the list lacks unused capacity for the additional item, returns | |
| 929 | /// `error.OutOfMemory`. | |
| 930 | pub fn appendBounded(self: *Self, item: T) error{OutOfMemory}!void { | |
| 931 | if (self.capacity - self.items.len == 0) return error.OutOfMemory; | |
| 932 | return appendAssumeCapacity(self, item); | |
| 933 | } | |
| 934 | ||
| 875 | 935 | /// Remove the element at index `i` from the list and return its value. |
| 876 | 936 | /// Invalidates pointers to the last element. |
| 877 | 937 | /// This operation is O(N). |
| ... | ... | @@ -906,6 +966,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 906 | 966 | } |
| 907 | 967 | |
| 908 | 968 | /// Append the slice of items to the list. |
| 969 | /// | |
| 909 | 970 | /// Asserts that the list can hold the additional items. |
| 910 | 971 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { |
| 911 | 972 | const old_len = self.items.len; |
| ... | ... | @@ -915,6 +976,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 915 | 976 | @memcpy(self.items[old_len..][0..items.len], items); |
| 916 | 977 | } |
| 917 | 978 | |
| 979 | /// Append the slice of items to the list. | |
| 980 | /// | |
| 981 | /// If the list lacks unused capacity for the additional items, returns `error.OutOfMemory`. | |
| 982 | pub fn appendSliceBounded(self: *Self, items: []const T) error{OutOfMemory}!void { | |
| 983 | if (self.capacity - self.items.len < items.len) return error.OutOfMemory; | |
| 984 | return appendSliceAssumeCapacity(self, items); | |
| 985 | } | |
| 986 | ||
| 918 | 987 | /// Append the slice of items to the list. Allocates more |
| 919 | 988 | /// memory as necessary. Only call this function if a call to `appendSlice` instead would |
| 920 | 989 | /// be a compile error. |
| ... | ... | @@ -925,8 +994,10 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 925 | 994 | } |
| 926 | 995 | |
| 927 | 996 | /// Append an unaligned slice of items to the list. |
| 928 | /// Only call this function if a call to `appendSliceAssumeCapacity` | |
| 929 | /// instead would be a compile error. | |
| 997 | /// | |
| 998 | /// Intended to be used only when `appendSliceAssumeCapacity` would be | |
| 999 | /// a compile error. | |
| 1000 | /// | |
| 930 | 1001 | /// Asserts that the list can hold the additional items. |
| 931 | 1002 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { |
| 932 | 1003 | const old_len = self.items.len; |
| ... | ... | @@ -936,6 +1007,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 936 | 1007 | @memcpy(self.items[old_len..][0..items.len], items); |
| 937 | 1008 | } |
| 938 | 1009 | |
| 1010 | /// Append an unaligned slice of items to the list. | |
| 1011 | /// | |
| 1012 | /// Intended to be used only when `appendSliceAssumeCapacity` would be | |
| 1013 | /// a compile error. | |
| 1014 | /// | |
| 1015 | /// If the list lacks unused capacity for the additional items, returns | |
| 1016 | /// `error.OutOfMemory`. | |
| 1017 | pub fn appendUnalignedSliceBounded(self: *Self, items: []align(1) const T) error{OutOfMemory}!void { | |
| 1018 | if (self.capacity - self.items.len < items.len) return error.OutOfMemory; | |
| 1019 | return appendUnalignedSliceAssumeCapacity(self, items); | |
| 1020 | } | |
| 1021 | ||
| 939 | 1022 | pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { |
| 940 | 1023 | comptime assert(T == u8); |
| 941 | 1024 | try self.ensureUnusedCapacity(gpa, fmt.len); |
| ... | ... | @@ -953,6 +1036,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 953 | 1036 | self.items.len += w.end; |
| 954 | 1037 | } |
| 955 | 1038 | |
| 1039 | pub fn printBounded(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void { | |
| 1040 | comptime assert(T == u8); | |
| 1041 | var w: std.io.Writer = .fixed(self.unusedCapacitySlice()); | |
| 1042 | w.print(fmt, args) catch return error.OutOfMemory; | |
| 1043 | self.items.len += w.end; | |
| 1044 | } | |
| 1045 | ||
| 956 | 1046 | /// Deprecated in favor of `print` or `std.io.Writer.Allocating`. |
| 957 | 1047 | pub const WriterContext = struct { |
| 958 | 1048 | self: *Self, |
| ... | ... | @@ -1007,9 +1097,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1007 | 1097 | } |
| 1008 | 1098 | |
| 1009 | 1099 | /// Append a value to the list `n` times. |
| 1100 | /// | |
| 1010 | 1101 | /// Never invalidates element pointers. |
| 1102 | /// | |
| 1011 | 1103 | /// The function is inline so that a comptime-known `value` parameter will |
| 1012 | 1104 | /// have better memset codegen in case it has a repeated byte pattern. |
| 1105 | /// | |
| 1013 | 1106 | /// Asserts that the list can hold the additional items. |
| 1014 | 1107 | pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { |
| 1015 | 1108 | const new_len = self.items.len + n; |
| ... | ... | @@ -1018,6 +1111,22 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1018 | 1111 | self.items.len = new_len; |
| 1019 | 1112 | } |
| 1020 | 1113 | |
| 1114 | /// Append a value to the list `n` times. | |
| 1115 | /// | |
| 1116 | /// Never invalidates element pointers. | |
| 1117 | /// | |
| 1118 | /// The function is inline so that a comptime-known `value` parameter will | |
| 1119 | /// have better memset codegen in case it has a repeated byte pattern. | |
| 1120 | /// | |
| 1121 | /// If the list lacks unused capacity for the additional items, returns | |
| 1122 | /// `error.OutOfMemory`. | |
| 1123 | pub inline fn appendNTimesBounded(self: *Self, value: T, n: usize) error{OutOfMemory}!void { | |
| 1124 | const new_len = self.items.len + n; | |
| 1125 | if (self.capacity < new_len) return error.OutOfMemory; | |
| 1126 | @memset(self.items.ptr[self.items.len..new_len], value); | |
| 1127 | self.items.len = new_len; | |
| 1128 | } | |
| 1129 | ||
| 1021 | 1130 | /// Adjust the list length to `new_len`. |
| 1022 | 1131 | /// Additional elements contain the value `undefined`. |
| 1023 | 1132 | /// Invalidates element pointers if additional memory is needed. |
| ... | ... | @@ -1143,8 +1252,11 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1143 | 1252 | } |
| 1144 | 1253 | |
| 1145 | 1254 | /// Increase length by 1, returning pointer to the new item. |
| 1255 | /// | |
| 1146 | 1256 | /// Never invalidates element pointers. |
| 1257 | /// | |
| 1147 | 1258 | /// The returned element pointer becomes invalid when the list is resized. |
| 1259 | /// | |
| 1148 | 1260 | /// Asserts that the list can hold one additional item. |
| 1149 | 1261 | pub fn addOneAssumeCapacity(self: *Self) *T { |
| 1150 | 1262 | assert(self.items.len < self.capacity); |
| ... | ... | @@ -1153,6 +1265,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1153 | 1265 | return &self.items[self.items.len - 1]; |
| 1154 | 1266 | } |
| 1155 | 1267 | |
| 1268 | /// Increase length by 1, returning pointer to the new item. | |
| 1269 | /// | |
| 1270 | /// Never invalidates element pointers. | |
| 1271 | /// | |
| 1272 | /// The returned element pointer becomes invalid when the list is resized. | |
| 1273 | /// | |
| 1274 | /// If the list lacks unused capacity for the additional item, returns `error.OutOfMemory`. | |
| 1275 | pub fn addOneBounded(self: *Self) error{OutOfMemory}!*T { | |
| 1276 | if (self.capacity - self.items.len < 1) return error.OutOfMemory; | |
| 1277 | return addOneAssumeCapacity(self); | |
| 1278 | } | |
| 1279 | ||
| 1156 | 1280 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1157 | 1281 | /// The return value is an array pointing to the newly allocated elements. |
| 1158 | 1282 | /// The returned pointer becomes invalid when the list is resized. |
| ... | ... | @@ -1163,9 +1287,13 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1163 | 1287 | } |
| 1164 | 1288 | |
| 1165 | 1289 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1290 | /// | |
| 1166 | 1291 | /// The return value is an array pointing to the newly allocated elements. |
| 1292 | /// | |
| 1167 | 1293 | /// Never invalidates element pointers. |
| 1294 | /// | |
| 1168 | 1295 | /// The returned pointer becomes invalid when the list is resized. |
| 1296 | /// | |
| 1169 | 1297 | /// Asserts that the list can hold the additional items. |
| 1170 | 1298 | pub fn addManyAsArrayAssumeCapacity(self: *Self, comptime n: usize) *[n]T { |
| 1171 | 1299 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -1174,6 +1302,21 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1174 | 1302 | return self.items[prev_len..][0..n]; |
| 1175 | 1303 | } |
| 1176 | 1304 | |
| 1305 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 1306 | /// | |
| 1307 | /// The return value is an array pointing to the newly allocated elements. | |
| 1308 | /// | |
| 1309 | /// Never invalidates element pointers. | |
| 1310 | /// | |
| 1311 | /// The returned pointer becomes invalid when the list is resized. | |
| 1312 | /// | |
| 1313 | /// If the list lacks unused capacity for the additional items, returns | |
| 1314 | /// `error.OutOfMemory`. | |
| 1315 | pub fn addManyAsArrayBounded(self: *Self, comptime n: usize) error{OutOfMemory}!*[n]T { | |
| 1316 | if (self.capacity - self.items.len < n) return error.OutOfMemory; | |
| 1317 | return addManyAsArrayAssumeCapacity(self, n); | |
| 1318 | } | |
| 1319 | ||
| 1177 | 1320 | /// Resize the array, adding `n` new elements, which have `undefined` values. |
| 1178 | 1321 | /// The return value is a slice pointing to the newly allocated elements. |
| 1179 | 1322 | /// The returned pointer becomes invalid when the list is resized. |
| ... | ... | @@ -1184,10 +1327,12 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1184 | 1327 | return self.items[prev_len..][0..n]; |
| 1185 | 1328 | } |
| 1186 | 1329 | |
| 1187 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 1188 | /// The return value is a slice pointing to the newly allocated elements. | |
| 1189 | /// Never invalidates element pointers. | |
| 1190 | /// The returned pointer becomes invalid when the list is resized. | |
| 1330 | /// Resizes the array, adding `n` new elements, which have `undefined` | |
| 1331 | /// values, returning a slice pointing to the newly allocated elements. | |
| 1332 | /// | |
| 1333 | /// Never invalidates element pointers. The returned pointer becomes | |
| 1334 | /// invalid when the list is resized. | |
| 1335 | /// | |
| 1191 | 1336 | /// Asserts that the list can hold the additional items. |
| 1192 | 1337 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { |
| 1193 | 1338 | assert(self.items.len + n <= self.capacity); |
| ... | ... | @@ -1196,6 +1341,19 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig |
| 1196 | 1341 | return self.items[prev_len..][0..n]; |
| 1197 | 1342 | } |
| 1198 | 1343 | |
| 1344 | /// Resizes the array, adding `n` new elements, which have `undefined` | |
| 1345 | /// values, returning a slice pointing to the newly allocated elements. | |
| 1346 | /// | |
| 1347 | /// Never invalidates element pointers. The returned pointer becomes | |
| 1348 | /// invalid when the list is resized. | |
| 1349 | /// | |
| 1350 | /// If the list lacks unused capacity for the additional items, returns | |
| 1351 | /// `error.OutOfMemory`. | |
| 1352 | pub fn addManyAsSliceBounded(self: *Self, n: usize) error{OutOfMemory}![]T { | |
| 1353 | if (self.capacity - self.items.len < n) return error.OutOfMemory; | |
| 1354 | return addManyAsSliceAssumeCapacity(self, n); | |
| 1355 | } | |
| 1356 | ||
| 1199 | 1357 | /// Remove and return the last element from the list. |
| 1200 | 1358 | /// If the list is empty, returns `null`. |
| 1201 | 1359 | /// Invalidates pointers to last element. |
lib/std/base64.zig+6-26| ... | ... | @@ -118,22 +118,6 @@ pub const Base64Encoder = struct { |
| 118 | 118 | } |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | // destWriter must be compatible with std.io.GenericWriter's writeAll interface | |
| 122 | // sourceReader must be compatible with `std.io.GenericReader` read interface | |
| 123 | pub fn encodeFromReaderToWriter(encoder: *const Base64Encoder, destWriter: anytype, sourceReader: anytype) !void { | |
| 124 | while (true) { | |
| 125 | var tempSource: [3]u8 = undefined; | |
| 126 | const bytesRead = try sourceReader.read(&tempSource); | |
| 127 | if (bytesRead == 0) { | |
| 128 | break; | |
| 129 | } | |
| 130 | ||
| 131 | var temp: [5]u8 = undefined; | |
| 132 | const s = encoder.encode(&temp, tempSource[0..bytesRead]); | |
| 133 | try destWriter.writeAll(s); | |
| 134 | } | |
| 135 | } | |
| 136 | ||
| 137 | 121 | /// dest.len must at least be what you get from ::calcSize. |
| 138 | 122 | pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 { |
| 139 | 123 | const out_len = encoder.calcSize(source.len); |
| ... | ... | @@ -517,17 +501,13 @@ fn testAllApis(codecs: Codecs, expected_decoded: []const u8, expected_encoded: [ |
| 517 | 501 | var buffer: [0x100]u8 = undefined; |
| 518 | 502 | const encoded = codecs.Encoder.encode(&buffer, expected_decoded); |
| 519 | 503 | try testing.expectEqualSlices(u8, expected_encoded, encoded); |
| 520 | ||
| 504 | } | |
| 505 | { | |
| 521 | 506 | // stream encode |
| 522 | var list = try std.BoundedArray(u8, 0x100).init(0); | |
| 523 | try codecs.Encoder.encodeWriter(list.writer(), expected_decoded); | |
| 524 | try testing.expectEqualSlices(u8, expected_encoded, list.slice()); | |
| 525 | ||
| 526 | // reader to writer encode | |
| 527 | var stream = std.io.fixedBufferStream(expected_decoded); | |
| 528 | list = try std.BoundedArray(u8, 0x100).init(0); | |
| 529 | try codecs.Encoder.encodeFromReaderToWriter(list.writer(), stream.reader()); | |
| 530 | try testing.expectEqualSlices(u8, expected_encoded, list.slice()); | |
| 507 | var buffer: [0x100]u8 = undefined; | |
| 508 | var writer: std.Io.Writer = .fixed(&buffer); | |
| 509 | try codecs.Encoder.encodeWriter(&writer, expected_decoded); | |
| 510 | try testing.expectEqualSlices(u8, expected_encoded, writer.buffered()); | |
| 531 | 511 | } |
| 532 | 512 | |
| 533 | 513 | // Base64Decoder |
lib/std/bounded_array.zig deleted-412| ... | ... | @@ -1,412 +0,0 @@ |
| 1 | const std = @import("std.zig"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const mem = std.mem; | |
| 4 | const testing = std.testing; | |
| 5 | const Alignment = std.mem.Alignment; | |
| 6 | ||
| 7 | /// A structure with an array and a length, that can be used as a slice. | |
| 8 | /// | |
| 9 | /// Useful to pass around small arrays whose exact size is only known at | |
| 10 | /// runtime, but whose maximum size is known at comptime, without requiring | |
| 11 | /// an `Allocator`. | |
| 12 | /// | |
| 13 | /// ```zig | |
| 14 | /// var actual_size = 32; | |
| 15 | /// var a = try BoundedArray(u8, 64).init(actual_size); | |
| 16 | /// var slice = a.slice(); // a slice of the 64-byte array | |
| 17 | /// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers | |
| 18 | /// ``` | |
| 19 | pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { | |
| 20 | return BoundedArrayAligned(T, .of(T), buffer_capacity); | |
| 21 | } | |
| 22 | ||
| 23 | /// A structure with an array, length and alignment, that can be used as a | |
| 24 | /// slice. | |
| 25 | /// | |
| 26 | /// Useful to pass around small explicitly-aligned arrays whose exact size is | |
| 27 | /// only known at runtime, but whose maximum size is known at comptime, without | |
| 28 | /// requiring an `Allocator`. | |
| 29 | /// ```zig | |
| 30 | // var a = try BoundedArrayAligned(u8, 16, 2).init(0); | |
| 31 | // try a.append(255); | |
| 32 | // try a.append(255); | |
| 33 | // const b = @ptrCast(*const [1]u16, a.constSlice().ptr); | |
| 34 | // try testing.expectEqual(@as(u16, 65535), b[0]); | |
| 35 | /// ``` | |
| 36 | pub fn BoundedArrayAligned( | |
| 37 | comptime T: type, | |
| 38 | comptime alignment: Alignment, | |
| 39 | comptime buffer_capacity: usize, | |
| 40 | ) type { | |
| 41 | return struct { | |
| 42 | const Self = @This(); | |
| 43 | buffer: [buffer_capacity]T align(alignment.toByteUnits()) = undefined, | |
| 44 | len: usize = 0, | |
| 45 | ||
| 46 | /// Set the actual length of the slice. | |
| 47 | /// Returns error.Overflow if it exceeds the length of the backing array. | |
| 48 | pub fn init(len: usize) error{Overflow}!Self { | |
| 49 | if (len > buffer_capacity) return error.Overflow; | |
| 50 | return Self{ .len = len }; | |
| 51 | } | |
| 52 | ||
| 53 | /// View the internal array as a slice whose size was previously set. | |
| 54 | pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { | |
| 55 | *align(alignment.toByteUnits()) [buffer_capacity]T => []align(alignment.toByteUnits()) T, | |
| 56 | *align(alignment.toByteUnits()) const [buffer_capacity]T => []align(alignment.toByteUnits()) const T, | |
| 57 | else => unreachable, | |
| 58 | } { | |
| 59 | return self.buffer[0..self.len]; | |
| 60 | } | |
| 61 | ||
| 62 | /// View the internal array as a constant slice whose size was previously set. | |
| 63 | pub fn constSlice(self: *const Self) []align(alignment.toByteUnits()) const T { | |
| 64 | return self.slice(); | |
| 65 | } | |
| 66 | ||
| 67 | /// Adjust the slice's length to `len`. | |
| 68 | /// Does not initialize added items if any. | |
| 69 | pub fn resize(self: *Self, len: usize) error{Overflow}!void { | |
| 70 | if (len > buffer_capacity) return error.Overflow; | |
| 71 | self.len = len; | |
| 72 | } | |
| 73 | ||
| 74 | /// Remove all elements from the slice. | |
| 75 | pub fn clear(self: *Self) void { | |
| 76 | self.len = 0; | |
| 77 | } | |
| 78 | ||
| 79 | /// Copy the content of an existing slice. | |
| 80 | pub fn fromSlice(m: []const T) error{Overflow}!Self { | |
| 81 | var list = try init(m.len); | |
| 82 | @memcpy(list.slice(), m); | |
| 83 | return list; | |
| 84 | } | |
| 85 | ||
| 86 | /// Return the element at index `i` of the slice. | |
| 87 | pub fn get(self: Self, i: usize) T { | |
| 88 | return self.constSlice()[i]; | |
| 89 | } | |
| 90 | ||
| 91 | /// Set the value of the element at index `i` of the slice. | |
| 92 | pub fn set(self: *Self, i: usize, item: T) void { | |
| 93 | self.slice()[i] = item; | |
| 94 | } | |
| 95 | ||
| 96 | /// Return the maximum length of a slice. | |
| 97 | pub fn capacity(self: Self) usize { | |
| 98 | return self.buffer.len; | |
| 99 | } | |
| 100 | ||
| 101 | /// Check that the slice can hold at least `additional_count` items. | |
| 102 | pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void { | |
| 103 | if (self.len + additional_count > buffer_capacity) { | |
| 104 | return error.Overflow; | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | /// Increase length by 1, returning a pointer to the new item. | |
| 109 | pub fn addOne(self: *Self) error{Overflow}!*T { | |
| 110 | try self.ensureUnusedCapacity(1); | |
| 111 | return self.addOneAssumeCapacity(); | |
| 112 | } | |
| 113 | ||
| 114 | /// Increase length by 1, returning pointer to the new item. | |
| 115 | /// Asserts that there is space for the new item. | |
| 116 | pub fn addOneAssumeCapacity(self: *Self) *T { | |
| 117 | assert(self.len < buffer_capacity); | |
| 118 | self.len += 1; | |
| 119 | return &self.slice()[self.len - 1]; | |
| 120 | } | |
| 121 | ||
| 122 | /// Resize the slice, adding `n` new elements, which have `undefined` values. | |
| 123 | /// The return value is a pointer to the array of uninitialized elements. | |
| 124 | pub fn addManyAsArray(self: *Self, comptime n: usize) error{Overflow}!*align(alignment.toByteUnits()) [n]T { | |
| 125 | const prev_len = self.len; | |
| 126 | try self.resize(self.len + n); | |
| 127 | return self.slice()[prev_len..][0..n]; | |
| 128 | } | |
| 129 | ||
| 130 | /// Resize the slice, adding `n` new elements, which have `undefined` values. | |
| 131 | /// The return value is a slice pointing to the uninitialized elements. | |
| 132 | pub fn addManyAsSlice(self: *Self, n: usize) error{Overflow}![]align(alignment.toByteUnits()) T { | |
| 133 | const prev_len = self.len; | |
| 134 | try self.resize(self.len + n); | |
| 135 | return self.slice()[prev_len..][0..n]; | |
| 136 | } | |
| 137 | ||
| 138 | /// Remove and return the last element from the slice, or return `null` if the slice is empty. | |
| 139 | pub fn pop(self: *Self) ?T { | |
| 140 | if (self.len == 0) return null; | |
| 141 | const item = self.get(self.len - 1); | |
| 142 | self.len -= 1; | |
| 143 | return item; | |
| 144 | } | |
| 145 | ||
| 146 | /// Return a slice of only the extra capacity after items. | |
| 147 | /// This can be useful for writing directly into it. | |
| 148 | /// Note that such an operation must be followed up with a | |
| 149 | /// call to `resize()` | |
| 150 | pub fn unusedCapacitySlice(self: *Self) []align(alignment.toByteUnits()) T { | |
| 151 | return self.buffer[self.len..]; | |
| 152 | } | |
| 153 | ||
| 154 | /// Insert `item` at index `i` by moving `slice[n .. slice.len]` to make room. | |
| 155 | /// This operation is O(N). | |
| 156 | pub fn insert( | |
| 157 | self: *Self, | |
| 158 | i: usize, | |
| 159 | item: T, | |
| 160 | ) error{Overflow}!void { | |
| 161 | if (i > self.len) { | |
| 162 | return error.Overflow; | |
| 163 | } | |
| 164 | _ = try self.addOne(); | |
| 165 | var s = self.slice(); | |
| 166 | mem.copyBackwards(T, s[i + 1 .. s.len], s[i .. s.len - 1]); | |
| 167 | self.buffer[i] = item; | |
| 168 | } | |
| 169 | ||
| 170 | /// Insert slice `items` at index `i` by moving `slice[i .. slice.len]` to make room. | |
| 171 | /// This operation is O(N). | |
| 172 | pub fn insertSlice(self: *Self, i: usize, items: []const T) error{Overflow}!void { | |
| 173 | try self.ensureUnusedCapacity(items.len); | |
| 174 | self.len += items.len; | |
| 175 | mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]); | |
| 176 | @memcpy(self.slice()[i..][0..items.len], items); | |
| 177 | } | |
| 178 | ||
| 179 | /// Replace range of elements `slice[start..][0..len]` with `new_items`. | |
| 180 | /// Grows slice if `len < new_items.len`. | |
| 181 | /// Shrinks slice if `len > new_items.len`. | |
| 182 | pub fn replaceRange( | |
| 183 | self: *Self, | |
| 184 | start: usize, | |
| 185 | len: usize, | |
| 186 | new_items: []const T, | |
| 187 | ) error{Overflow}!void { | |
| 188 | const after_range = start + len; | |
| 189 | var range = self.slice()[start..after_range]; | |
| 190 | ||
| 191 | if (range.len == new_items.len) { | |
| 192 | @memcpy(range[0..new_items.len], new_items); | |
| 193 | } else if (range.len < new_items.len) { | |
| 194 | const first = new_items[0..range.len]; | |
| 195 | const rest = new_items[range.len..]; | |
| 196 | @memcpy(range[0..first.len], first); | |
| 197 | try self.insertSlice(after_range, rest); | |
| 198 | } else { | |
| 199 | @memcpy(range[0..new_items.len], new_items); | |
| 200 | const after_subrange = start + new_items.len; | |
| 201 | for (self.constSlice()[after_range..], 0..) |item, i| { | |
| 202 | self.slice()[after_subrange..][i] = item; | |
| 203 | } | |
| 204 | self.len -= len - new_items.len; | |
| 205 | } | |
| 206 | } | |
| 207 | ||
| 208 | /// Extend the slice by 1 element. | |
| 209 | pub fn append(self: *Self, item: T) error{Overflow}!void { | |
| 210 | const new_item_ptr = try self.addOne(); | |
| 211 | new_item_ptr.* = item; | |
| 212 | } | |
| 213 | ||
| 214 | /// Extend the slice by 1 element, asserting the capacity is already | |
| 215 | /// enough to store the new item. | |
| 216 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | |
| 217 | const new_item_ptr = self.addOneAssumeCapacity(); | |
| 218 | new_item_ptr.* = item; | |
| 219 | } | |
| 220 | ||
| 221 | /// Remove the element at index `i`, shift elements after index | |
| 222 | /// `i` forward, and return the removed element. | |
| 223 | /// Asserts the slice has at least one item. | |
| 224 | /// This operation is O(N). | |
| 225 | pub fn orderedRemove(self: *Self, i: usize) T { | |
| 226 | const newlen = self.len - 1; | |
| 227 | if (newlen == i) return self.pop().?; | |
| 228 | const old_item = self.get(i); | |
| 229 | for (self.slice()[i..newlen], 0..) |*b, j| b.* = self.get(i + 1 + j); | |
| 230 | self.set(newlen, undefined); | |
| 231 | self.len = newlen; | |
| 232 | return old_item; | |
| 233 | } | |
| 234 | ||
| 235 | /// Remove the element at the specified index and return it. | |
| 236 | /// The empty slot is filled from the end of the slice. | |
| 237 | /// This operation is O(1). | |
| 238 | pub fn swapRemove(self: *Self, i: usize) T { | |
| 239 | if (self.len - 1 == i) return self.pop().?; | |
| 240 | const old_item = self.get(i); | |
| 241 | self.set(i, self.pop().?); | |
| 242 | return old_item; | |
| 243 | } | |
| 244 | ||
| 245 | /// Append the slice of items to the slice. | |
| 246 | pub fn appendSlice(self: *Self, items: []const T) error{Overflow}!void { | |
| 247 | try self.ensureUnusedCapacity(items.len); | |
| 248 | self.appendSliceAssumeCapacity(items); | |
| 249 | } | |
| 250 | ||
| 251 | /// Append the slice of items to the slice, asserting the capacity is already | |
| 252 | /// enough to store the new items. | |
| 253 | pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { | |
| 254 | const old_len = self.len; | |
| 255 | self.len += items.len; | |
| 256 | @memcpy(self.slice()[old_len..][0..items.len], items); | |
| 257 | } | |
| 258 | ||
| 259 | /// Append a value to the slice `n` times. | |
| 260 | /// Allocates more memory as necessary. | |
| 261 | pub fn appendNTimes(self: *Self, value: T, n: usize) error{Overflow}!void { | |
| 262 | const old_len = self.len; | |
| 263 | try self.resize(old_len + n); | |
| 264 | @memset(self.slice()[old_len..self.len], value); | |
| 265 | } | |
| 266 | ||
| 267 | /// Append a value to the slice `n` times. | |
| 268 | /// Asserts the capacity is enough. | |
| 269 | pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { | |
| 270 | const old_len = self.len; | |
| 271 | self.len += n; | |
| 272 | assert(self.len <= buffer_capacity); | |
| 273 | @memset(self.slice()[old_len..self.len], value); | |
| 274 | } | |
| 275 | ||
| 276 | pub const Writer = if (T != u8) | |
| 277 | @compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++ | |
| 278 | "but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)") | |
| 279 | else | |
| 280 | std.io.GenericWriter(*Self, error{Overflow}, appendWrite); | |
| 281 | ||
| 282 | /// Initializes a writer which will write into the array. | |
| 283 | pub fn writer(self: *Self) Writer { | |
| 284 | return .{ .context = self }; | |
| 285 | } | |
| 286 | ||
| 287 | /// Same as `appendSlice` except it returns the number of bytes written, which is always the same | |
| 288 | /// as `m.len`. The purpose of this function existing is to match `std.io.GenericWriter` API. | |
| 289 | fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize { | |
| 290 | try self.appendSlice(m); | |
| 291 | return m.len; | |
| 292 | } | |
| 293 | }; | |
| 294 | } | |
| 295 | ||
| 296 | test BoundedArray { | |
| 297 | var a = try BoundedArray(u8, 64).init(32); | |
| 298 | ||
| 299 | try testing.expectEqual(a.capacity(), 64); | |
| 300 | try testing.expectEqual(a.slice().len, 32); | |
| 301 | try testing.expectEqual(a.constSlice().len, 32); | |
| 302 | ||
| 303 | try a.resize(48); | |
| 304 | try testing.expectEqual(a.len, 48); | |
| 305 | ||
| 306 | const x = [_]u8{1} ** 10; | |
| 307 | a = try BoundedArray(u8, 64).fromSlice(&x); | |
| 308 | try testing.expectEqualSlices(u8, &x, a.constSlice()); | |
| 309 | ||
| 310 | var a2 = a; | |
| 311 | try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice()); | |
| 312 | a2.set(0, 0); | |
| 313 | try testing.expect(a.get(0) != a2.get(0)); | |
| 314 | ||
| 315 | try testing.expectError(error.Overflow, a.resize(100)); | |
| 316 | try testing.expectError(error.Overflow, BoundedArray(u8, x.len - 1).fromSlice(&x)); | |
| 317 | ||
| 318 | try a.resize(0); | |
| 319 | try a.ensureUnusedCapacity(a.capacity()); | |
| 320 | (try a.addOne()).* = 0; | |
| 321 | try a.ensureUnusedCapacity(a.capacity() - 1); | |
| 322 | try testing.expectEqual(a.len, 1); | |
| 323 | ||
| 324 | const uninitialized = try a.addManyAsArray(4); | |
| 325 | try testing.expectEqual(uninitialized.len, 4); | |
| 326 | try testing.expectEqual(a.len, 5); | |
| 327 | ||
| 328 | try a.append(0xff); | |
| 329 | try testing.expectEqual(a.len, 6); | |
| 330 | try testing.expectEqual(a.pop(), 0xff); | |
| 331 | ||
| 332 | a.appendAssumeCapacity(0xff); | |
| 333 | try testing.expectEqual(a.len, 6); | |
| 334 | try testing.expectEqual(a.pop(), 0xff); | |
| 335 | ||
| 336 | try a.resize(1); | |
| 337 | try testing.expectEqual(a.pop(), 0); | |
| 338 | try testing.expectEqual(a.pop(), null); | |
| 339 | var unused = a.unusedCapacitySlice(); | |
| 340 | @memset(unused[0..8], 2); | |
| 341 | unused[8] = 3; | |
| 342 | unused[9] = 4; | |
| 343 | try testing.expectEqual(unused.len, a.capacity()); | |
| 344 | try a.resize(10); | |
| 345 | ||
| 346 | try a.insert(5, 0xaa); | |
| 347 | try testing.expectEqual(a.len, 11); | |
| 348 | try testing.expectEqual(a.get(5), 0xaa); | |
| 349 | try testing.expectEqual(a.get(9), 3); | |
| 350 | try testing.expectEqual(a.get(10), 4); | |
| 351 | ||
| 352 | try a.insert(11, 0xbb); | |
| 353 | try testing.expectEqual(a.len, 12); | |
| 354 | try testing.expectEqual(a.pop(), 0xbb); | |
| 355 | ||
| 356 | try a.appendSlice(&x); | |
| 357 | try testing.expectEqual(a.len, 11 + x.len); | |
| 358 | ||
| 359 | try a.appendNTimes(0xbb, 5); | |
| 360 | try testing.expectEqual(a.len, 11 + x.len + 5); | |
| 361 | try testing.expectEqual(a.pop(), 0xbb); | |
| 362 | ||
| 363 | a.appendNTimesAssumeCapacity(0xcc, 5); | |
| 364 | try testing.expectEqual(a.len, 11 + x.len + 5 - 1 + 5); | |
| 365 | try testing.expectEqual(a.pop(), 0xcc); | |
| 366 | ||
| 367 | try testing.expectEqual(a.len, 29); | |
| 368 | try a.replaceRange(1, 20, &x); | |
| 369 | try testing.expectEqual(a.len, 29 + x.len - 20); | |
| 370 | ||
| 371 | try a.insertSlice(0, &x); | |
| 372 | try testing.expectEqual(a.len, 29 + x.len - 20 + x.len); | |
| 373 | ||
| 374 | try a.replaceRange(1, 5, &x); | |
| 375 | try testing.expectEqual(a.len, 29 + x.len - 20 + x.len + x.len - 5); | |
| 376 | ||
| 377 | try a.append(10); | |
| 378 | try testing.expectEqual(a.pop(), 10); | |
| 379 | ||
| 380 | try a.append(20); | |
| 381 | const removed = a.orderedRemove(5); | |
| 382 | try testing.expectEqual(removed, 1); | |
| 383 | try testing.expectEqual(a.len, 34); | |
| 384 | ||
| 385 | a.set(0, 0xdd); | |
| 386 | a.set(a.len - 1, 0xee); | |
| 387 | const swapped = a.swapRemove(0); | |
| 388 | try testing.expectEqual(swapped, 0xdd); | |
| 389 | try testing.expectEqual(a.get(0), 0xee); | |
| 390 | ||
| 391 | const added_slice = try a.addManyAsSlice(3); | |
| 392 | try testing.expectEqual(added_slice.len, 3); | |
| 393 | try testing.expectEqual(a.len, 36); | |
| 394 | ||
| 395 | while (a.pop()) |_| {} | |
| 396 | const w = a.writer(); | |
| 397 | const s = "hello, this is a test string"; | |
| 398 | try w.writeAll(s); | |
| 399 | try testing.expectEqualStrings(s, a.constSlice()); | |
| 400 | } | |
| 401 | ||
| 402 | test "BoundedArrayAligned" { | |
| 403 | var a = try BoundedArrayAligned(u8, .@"16", 4).init(0); | |
| 404 | try a.append(0); | |
| 405 | try a.append(0); | |
| 406 | try a.append(255); | |
| 407 | try a.append(255); | |
| 408 | ||
| 409 | const b = @as(*const [2]u16, @ptrCast(a.constSlice().ptr)); | |
| 410 | try testing.expectEqual(@as(u16, 0), b[0]); | |
| 411 | try testing.expectEqual(@as(u16, 65535), b[1]); | |
| 412 | } |
lib/std/math/big/int.zig+3-5| ... | ... | @@ -1710,7 +1710,7 @@ pub const Mutable = struct { |
| 1710 | 1710 | |
| 1711 | 1711 | if (xy_trailing != 0 and r.limbs[r.len - 1] != 0) { |
| 1712 | 1712 | // Manually shift here since we know its limb aligned. |
| 1713 | mem.copyBackwards(Limb, r.limbs[xy_trailing..], r.limbs[0..r.len]); | |
| 1713 | @memmove(r.limbs[xy_trailing..][0..r.len], r.limbs[0..r.len]); | |
| 1714 | 1714 | @memset(r.limbs[0..xy_trailing], 0); |
| 1715 | 1715 | r.len += xy_trailing; |
| 1716 | 1716 | } |
| ... | ... | @@ -3836,8 +3836,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) usize { |
| 3836 | 3836 | std.debug.assert(@intFromPtr(r.ptr) >= @intFromPtr(a.ptr)); |
| 3837 | 3837 | |
| 3838 | 3838 | if (shift == 0) { |
| 3839 | if (a.ptr != r.ptr) | |
| 3840 | std.mem.copyBackwards(Limb, r[0..a.len], a); | |
| 3839 | if (a.ptr != r.ptr) @memmove(r[0..a.len], a); | |
| 3841 | 3840 | return a.len; |
| 3842 | 3841 | } |
| 3843 | 3842 | if (shift >= limb_bits) { |
| ... | ... | @@ -3891,8 +3890,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) usize { |
| 3891 | 3890 | if (shift == 0) { |
| 3892 | 3891 | std.debug.assert(r.len >= a.len); |
| 3893 | 3892 | |
| 3894 | if (a.ptr != r.ptr) | |
| 3895 | std.mem.copyForwards(Limb, r[0..a.len], a); | |
| 3893 | if (a.ptr != r.ptr) @memmove(r[0..a.len], a); | |
| 3896 | 3894 | return a.len; |
| 3897 | 3895 | } |
| 3898 | 3896 | if (shift >= limb_bits) { |
lib/std/os/windows.zig+3-8| ... | ... | @@ -1332,7 +1332,7 @@ pub fn GetFinalPathNameByHandle( |
| 1332 | 1332 | // dropping the \Device\Mup\ and making sure the path begins with \\ |
| 1333 | 1333 | if (mem.eql(u16, device_name_u16, std.unicode.utf8ToUtf16LeStringLiteral("Mup"))) { |
| 1334 | 1334 | out_buffer[0] = '\\'; |
| 1335 | mem.copyForwards(u16, out_buffer[1..][0..file_name_u16.len], file_name_u16); | |
| 1335 | @memmove(out_buffer[1..][0..file_name_u16.len], file_name_u16); | |
| 1336 | 1336 | return out_buffer[0 .. 1 + file_name_u16.len]; |
| 1337 | 1337 | } |
| 1338 | 1338 | |
| ... | ... | @@ -1400,7 +1400,7 @@ pub fn GetFinalPathNameByHandle( |
| 1400 | 1400 | if (out_buffer.len < drive_letter.len + file_name_u16.len) return error.NameTooLong; |
| 1401 | 1401 | |
| 1402 | 1402 | @memcpy(out_buffer[0..drive_letter.len], drive_letter); |
| 1403 | mem.copyForwards(u16, out_buffer[drive_letter.len..][0..file_name_u16.len], file_name_u16); | |
| 1403 | @memmove(out_buffer[drive_letter.len..][0..file_name_u16.len], file_name_u16); | |
| 1404 | 1404 | const total_len = drive_letter.len + file_name_u16.len; |
| 1405 | 1405 | |
| 1406 | 1406 | // Validate that DOS does not contain any spurious nul bytes. |
| ... | ... | @@ -1449,12 +1449,7 @@ pub fn GetFinalPathNameByHandle( |
| 1449 | 1449 | // to copy backwards. We also need to do this before copying the volume path because |
| 1450 | 1450 | // it could overwrite the file_name_u16 memory. |
| 1451 | 1451 | const file_name_dest = out_buffer[volume_path.len..][0..file_name_u16.len]; |
| 1452 | const file_name_byte_offset = @intFromPtr(file_name_u16.ptr) - @intFromPtr(out_buffer.ptr); | |
| 1453 | const file_name_index = file_name_byte_offset / @sizeOf(u16); | |
| 1454 | if (volume_path.len > file_name_index) | |
| 1455 | mem.copyBackwards(u16, file_name_dest, file_name_u16) | |
| 1456 | else | |
| 1457 | mem.copyForwards(u16, file_name_dest, file_name_u16); | |
| 1452 | @memmove(file_name_dest, file_name_u16); | |
| 1458 | 1453 | @memcpy(out_buffer[0..volume_path.len], volume_path); |
| 1459 | 1454 | const total_len = volume_path.len + file_name_u16.len; |
| 1460 | 1455 |
lib/std/std.zig-3| ... | ... | @@ -9,8 +9,6 @@ pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged; |
| 9 | 9 | pub const AutoHashMap = hash_map.AutoHashMap; |
| 10 | 10 | pub const AutoHashMapUnmanaged = hash_map.AutoHashMapUnmanaged; |
| 11 | 11 | pub const BitStack = @import("BitStack.zig"); |
| 12 | pub const BoundedArray = @import("bounded_array.zig").BoundedArray; | |
| 13 | pub const BoundedArrayAligned = @import("bounded_array.zig").BoundedArrayAligned; | |
| 14 | 12 | pub const Build = @import("Build.zig"); |
| 15 | 13 | pub const BufMap = @import("buf_map.zig").BufMap; |
| 16 | 14 | pub const BufSet = @import("buf_set.zig").BufSet; |
| ... | ... | @@ -31,7 +29,6 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue; |
| 31 | 29 | pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue; |
| 32 | 30 | pub const Progress = @import("Progress.zig"); |
| 33 | 31 | pub const Random = @import("Random.zig"); |
| 34 | pub const RingBuffer = @import("RingBuffer.zig"); | |
| 35 | 32 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 36 | 33 | pub const SemanticVersion = @import("SemanticVersion.zig"); |
| 37 | 34 | pub const SinglyLinkedList = @import("SinglyLinkedList.zig"); |
src/Compilation.zig+12-6| ... | ... | @@ -2103,6 +2103,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 2103 | 2103 | .local_zir_cache = local_zir_cache, |
| 2104 | 2104 | .error_limit = error_limit, |
| 2105 | 2105 | .llvm_object = null, |
| 2106 | .analysis_roots_buffer = undefined, | |
| 2107 | .analysis_roots_len = 0, | |
| 2106 | 2108 | }; |
| 2107 | 2109 | try zcu.init(options.thread_pool.getIdCount()); |
| 2108 | 2110 | break :blk zcu; |
| ... | ... | @@ -2933,22 +2935,26 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { |
| 2933 | 2935 | try comp.appendFileSystemInput(embed_file.path); |
| 2934 | 2936 | } |
| 2935 | 2937 | |
| 2936 | zcu.analysis_roots.clear(); | |
| 2938 | zcu.analysis_roots_len = 0; | |
| 2937 | 2939 | |
| 2938 | zcu.analysis_roots.appendAssumeCapacity(zcu.std_mod); | |
| 2940 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; | |
| 2941 | zcu.analysis_roots_len += 1; | |
| 2939 | 2942 | |
| 2940 | 2943 | // Normally we rely on importing std to in turn import the root source file in the start code. |
| 2941 | 2944 | // However, the main module is distinct from the root module in tests, so that won't happen there. |
| 2942 | 2945 | if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { |
| 2943 | zcu.analysis_roots.appendAssumeCapacity(zcu.main_mod); | |
| 2946 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; | |
| 2947 | zcu.analysis_roots_len += 1; | |
| 2944 | 2948 | } |
| 2945 | 2949 | |
| 2946 | 2950 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { |
| 2947 | zcu.analysis_roots.appendAssumeCapacity(compiler_rt_mod); | |
| 2951 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; | |
| 2952 | zcu.analysis_roots_len += 1; | |
| 2948 | 2953 | } |
| 2949 | 2954 | |
| 2950 | 2955 | if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { |
| 2951 | zcu.analysis_roots.appendAssumeCapacity(ubsan_rt_mod); | |
| 2956 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; | |
| 2957 | zcu.analysis_roots_len += 1; | |
| 2952 | 2958 | } |
| 2953 | 2959 | } |
| 2954 | 2960 | |
| ... | ... | @@ -4745,7 +4751,7 @@ fn performAllTheWork( |
| 4745 | 4751 | try zcu.flushRetryableFailures(); |
| 4746 | 4752 | |
| 4747 | 4753 | // It's analysis time! Queue up our initial analysis. |
| 4748 | for (zcu.analysis_roots.slice()) |mod| { | |
| 4754 | for (zcu.analysisRoots()) |mod| { | |
| 4749 | 4755 | try comp.queueJob(.{ .analyze_mod = mod }); |
| 4750 | 4756 | } |
| 4751 | 4757 |
src/Sema.zig+3-3| ... | ... | @@ -2631,7 +2631,7 @@ fn reparentOwnedErrorMsg( |
| 2631 | 2631 | |
| 2632 | 2632 | const orig_notes = msg.notes.len; |
| 2633 | 2633 | msg.notes = try sema.gpa.realloc(msg.notes, orig_notes + 1); |
| 2634 | std.mem.copyBackwards(Zcu.ErrorMsg, msg.notes[1..], msg.notes[0..orig_notes]); | |
| 2634 | @memmove(msg.notes[1..][0..orig_notes], msg.notes[0..orig_notes]); | |
| 2635 | 2635 | msg.notes[0] = .{ |
| 2636 | 2636 | .src_loc = msg.src_loc, |
| 2637 | 2637 | .msg = msg.msg, |
| ... | ... | @@ -14464,8 +14464,8 @@ fn analyzeTupleMul( |
| 14464 | 14464 | } |
| 14465 | 14465 | } |
| 14466 | 14466 | for (0..factor) |i| { |
| 14467 | mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); | |
| 14468 | mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); | |
| 14467 | @memmove(types[tuple_len * i ..][0..tuple_len], types[0..tuple_len]); | |
| 14468 | @memmove(values[tuple_len * i ..][0..tuple_len], values[0..tuple_len]); | |
| 14469 | 14469 | } |
| 14470 | 14470 | break :rs runtime_src; |
| 14471 | 14471 | }; |
src/Zcu.zig+8-3| ... | ... | @@ -268,7 +268,8 @@ nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, voi |
| 268 | 268 | |
| 269 | 269 | /// These are the modules which we initially queue for analysis in `Compilation.update`. |
| 270 | 270 | /// `resolveReferences` will use these as the root of its reachability traversal. |
| 271 | analysis_roots: std.BoundedArray(*Package.Module, 4) = .{}, | |
| 271 | analysis_roots_buffer: [4]*Package.Module, | |
| 272 | analysis_roots_len: usize = 0, | |
| 272 | 273 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and |
| 273 | 274 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). |
| 274 | 275 | /// Allocated into `gpa`. |
| ... | ... | @@ -4013,8 +4014,8 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4013 | 4014 | // This is not a sufficient size, but a lower bound. |
| 4014 | 4015 | try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); |
| 4015 | 4016 | |
| 4016 | try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots.len); | |
| 4017 | for (zcu.analysis_roots.slice()) |mod| { | |
| 4017 | try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots_len); | |
| 4018 | for (zcu.analysisRoots()) |mod| { | |
| 4018 | 4019 | const file = zcu.module_roots.get(mod).?.unwrap() orelse continue; |
| 4019 | 4020 | const root_ty = zcu.fileRootType(file); |
| 4020 | 4021 | if (root_ty == .none) continue; |
| ... | ... | @@ -4202,6 +4203,10 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4202 | 4203 | return result; |
| 4203 | 4204 | } |
| 4204 | 4205 | |
| 4206 | pub fn analysisRoots(zcu: *Zcu) []*Package.Module { | |
| 4207 | return zcu.analysis_roots_buffer[0..zcu.analysis_roots_len]; | |
| 4208 | } | |
| 4209 | ||
| 4205 | 4210 | pub fn fileByIndex(zcu: *const Zcu, file_index: File.Index) *File { |
| 4206 | 4211 | return zcu.intern_pool.filePtr(file_index); |
| 4207 | 4212 | } |
src/Zcu/PerThread.zig+3-2| ... | ... | @@ -2116,8 +2116,9 @@ pub fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool { |
| 2116 | 2116 | // multi-threaded environment (where things like file indices could differ between compiler runs). |
| 2117 | 2117 | |
| 2118 | 2118 | // The roots of our file liveness analysis will be the analysis roots. |
| 2119 | try zcu.alive_files.ensureTotalCapacity(gpa, zcu.analysis_roots.len); | |
| 2120 | for (zcu.analysis_roots.slice()) |mod| { | |
| 2119 | const analysis_roots = zcu.analysisRoots(); | |
| 2120 | try zcu.alive_files.ensureTotalCapacity(gpa, analysis_roots.len); | |
| 2121 | for (analysis_roots) |mod| { | |
| 2121 | 2122 | const file_index = zcu.module_roots.get(mod).?.unwrap() orelse continue; |
| 2122 | 2123 | const file = zcu.fileByIndex(file_index); |
| 2123 | 2124 |