| ... | @@ -78,27 +78,22 @@ pub const URL = struct { | ... | @@ -78,27 +78,22 @@ pub const URL = struct { |
| 78 | | 78 | |
| 79 | var href = ManyArrayList(8 + 7, u8).init(alloc); | 79 | var href = ManyArrayList(8 + 7, u8).init(alloc); |
| 80 | defer href.deinit(); | 80 | defer href.deinit(); |
| | 81 | // scheme |
| 81 | // : | 82 | // : |
| 82 | // // | 83 | // // |
| 83 | var username = std.ArrayList(u8).init(alloc); | 84 | // username |
| 84 | defer username.deinit(); | | |
| 85 | // : | 85 | // : |
| 86 | var password = std.ArrayList(u8).init(alloc); | 86 | // password |
| 87 | defer password.deinit(); | | |
| 88 | // @ | 87 | // @ |
| 89 | var host: Host = .{ .name = "" }; | 88 | var host: Host = .{ .name = "" }; |
| 90 | defer if (host == .name) alloc.free(host.name); | 89 | defer if (host == .name) alloc.free(host.name); |
| 91 | // : | 90 | // : |
| 92 | var port = std.ArrayList(u8).init(alloc); | 91 | // port |
| 93 | defer port.deinit(); | 92 | // path |
| 94 | var path = std.ArrayList(u8).init(alloc); | | |
| 95 | defer path.deinit(); | | |
| 96 | // ? | 93 | // ? |
| 97 | var query = std.ArrayList(u8).init(alloc); | 94 | // query |
| 98 | defer query.deinit(); | | |
| 99 | // # | 95 | // # |
| 100 | var fragment = std.ArrayList(u8).init(alloc); | 96 | // fragment |
| 101 | defer fragment.deinit(); | | |
| 102 | | 97 | |
| 103 | // 9. | 98 | // 9. |
| 104 | while (true) { | 99 | while (true) { |
| ... | @@ -172,7 +167,7 @@ pub const URL = struct { | ... | @@ -172,7 +167,7 @@ pub const URL = struct { |
| 172 | } | 167 | } |
| 173 | // 9. Otherwise, set url’s path to the empty string and set state to opaque path state. | 168 | // 9. Otherwise, set url’s path to the empty string and set state to opaque path state. |
| 174 | else { | 169 | else { |
| 175 | path.clearRetainingCapacity(); | 170 | href.clear(10); |
| 176 | state = .opaque_path; | 171 | state = .opaque_path; |
| 177 | } | 172 | } |
| 178 | } | 173 | } |
| ... | @@ -248,18 +243,18 @@ pub const URL = struct { | ... | @@ -248,18 +243,18 @@ pub const URL = struct { |
| 248 | // try query.appendSlice(base.?.query.?); | 243 | // try query.appendSlice(base.?.query.?); |
| 249 | // 2. If c is U+003F (?), then set url’s query to the empty string, and state to query state. | 244 | // 2. If c is U+003F (?), then set url’s query to the empty string, and state to query state. |
| 250 | if (c == '?') { | 245 | if (c == '?') { |
| 251 | query.clearRetainingCapacity(); | 246 | href.clear(12); |
| 252 | state = .query; | 247 | state = .query; |
| 253 | } | 248 | } |
| 254 | // 3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. | 249 | // 3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. |
| 255 | else if (c == '#') { | 250 | else if (c == '#') { |
| 256 | fragment.clearRetainingCapacity(); | 251 | href.clear(14); |
| 257 | state = .fragment; | 252 | state = .fragment; |
| 258 | } | 253 | } |
| 259 | // 4. Otherwise, if c is not the EOF code point: | 254 | // 4. Otherwise, if c is not the EOF code point: |
| 260 | else if (i < length) { | 255 | else if (i < length) { |
| 261 | // 1. Set url’s query to null. | 256 | // 1. Set url’s query to null. |
| 262 | query.clearRetainingCapacity(); | 257 | href.clear(12); |
| 263 | // 2. Shorten url’s path. | 258 | // 2. Shorten url’s path. |
| 264 | @panic("TODO"); | 259 | @panic("TODO"); |
| 265 | // 3. Set state to path state and decrease pointer by 1. | 260 | // 3. Set state to path state and decrease pointer by 1. |
| ... | @@ -380,6 +375,7 @@ pub const URL = struct { | ... | @@ -380,6 +375,7 @@ pub const URL = struct { |
| 380 | // 4. If host is failure, then return failure. | 375 | // 4. If host is failure, then return failure. |
| 381 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); | 376 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); |
| 382 | // 5. Set url’s host to host, buffer to the empty string, and state to port state. | 377 | // 5. Set url’s host to host, buffer to the empty string, and state to port state. |
| | 378 | // try href.set(7, h); |
| 383 | host = h; | 379 | host = h; |
| 384 | buffer.clearRetainingCapacity(); | 380 | buffer.clearRetainingCapacity(); |
| 385 | state = .port; | 381 | state = .port; |
| ... | @@ -395,11 +391,12 @@ pub const URL = struct { | ... | @@ -395,11 +391,12 @@ pub const URL = struct { |
| 395 | // 1. If url is special and buffer is the empty string, host-missing validation error, return failure. | 391 | // 1. If url is special and buffer is the empty string, host-missing validation error, return failure. |
| 396 | if (isSchemeSpecial(href.items(0)) and buffer.items.len == 0) return error.InvalidURL | 392 | if (isSchemeSpecial(href.items(0)) and buffer.items.len == 0) return error.InvalidURL |
| 397 | // 2. Otherwise, if state override is given, buffer is the empty string, and either url includes credentials or url’s port is non-null, then return failure. | 393 | // 2. Otherwise, if state override is given, buffer is the empty string, and either url includes credentials or url’s port is non-null, then return failure. |
| 398 | else if (state_override != null and buffer.items.len == 0 and (username.items.len > 0 or password.items.len > 0)) return error.InvalidURL; | 394 | else if (state_override != null and buffer.items.len == 0 and (href.items(3).len > 0 or href.items(5).len > 0)) return error.InvalidURL; |
| 399 | // 3. Let host be the result of host parsing buffer with url is not special. | 395 | // 3. Let host be the result of host parsing buffer with url is not special. |
| 400 | // 4. If host is failure, then return failure. | 396 | // 4. If host is failure, then return failure. |
| 401 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); | 397 | const h = try parseHost(alloc, buffer.items, !isSchemeSpecial(href.items(0))); |
| 402 | // 5. Set url’s host to host, buffer to the empty string, and state to path start state. | 398 | // 5. Set url’s host to host, buffer to the empty string, and state to path start state. |
| | 399 | // try href.set(7, h); |
| 403 | host = h; | 400 | host = h; |
| 404 | buffer.clearRetainingCapacity(); | 401 | buffer.clearRetainingCapacity(); |
| 405 | state = .path_start; | 402 | state = .path_start; |
| ... | @@ -433,7 +430,7 @@ pub const URL = struct { | ... | @@ -433,7 +430,7 @@ pub const URL = struct { |
| 433 | // 2. If port is not a 16-bit unsigned integer, port-out-of-range validation error, return failure. | 430 | // 2. If port is not a 16-bit unsigned integer, port-out-of-range validation error, return failure. |
| 434 | const p = std.fmt.parseInt(u16, buffer.items, 10) catch return error.InvalidURL; | 431 | const p = std.fmt.parseInt(u16, buffer.items, 10) catch return error.InvalidURL; |
| 435 | // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port. | 432 | // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port. |
| 436 | if (schemeDefaultPort(href.items(0)) != p) try port.writer().print("{d}", .{p}); | 433 | if (schemeDefaultPort(href.items(0)) != p) try href.print(9, "{d}", .{p}); |
| 437 | // 4. Set buffer to the empty string. | 434 | // 4. Set buffer to the empty string. |
| 438 | buffer.clearRetainingCapacity(); | 435 | buffer.clearRetainingCapacity(); |
| 439 | // 5. If state override is given, then return. | 436 | // 5. If state override is given, then return. |
| ... | @@ -456,7 +453,7 @@ pub const URL = struct { | ... | @@ -456,7 +453,7 @@ pub const URL = struct { |
| 456 | // 1. Set url’s scheme to "file". | 453 | // 1. Set url’s scheme to "file". |
| 457 | try href.set(0, "file"); | 454 | try href.set(0, "file"); |
| 458 | // 2. Set url’s host to the empty string. | 455 | // 2. Set url’s host to the empty string. |
| 459 | host = .{ .name = "" }; | 456 | href.clear(7); |
| 460 | // 3. If c is U+002F (/) or U+005C (\), then: | 457 | // 3. If c is U+002F (/) or U+005C (\), then: |
| 461 | if (c == '/' or c == '\\') { | 458 | if (c == '/' or c == '\\') { |
| 462 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. | 459 | // 1. If c is U+005C (\), invalid-reverse-solidus validation error. |
| ... | @@ -472,18 +469,18 @@ pub const URL = struct { | ... | @@ -472,18 +469,18 @@ pub const URL = struct { |
| 472 | // try query.appendSlice(base.?.query.?); | 469 | // try query.appendSlice(base.?.query.?); |
| 473 | // 2. If c is U+003F (?), then set url’s query to the empty string and state to query state. | 470 | // 2. If c is U+003F (?), then set url’s query to the empty string and state to query state. |
| 474 | if (c == '?') { | 471 | if (c == '?') { |
| 475 | query.clearRetainingCapacity(); | 472 | href.clear(12); |
| 476 | state = .query; | 473 | state = .query; |
| 477 | } | 474 | } |
| 478 | // 3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. | 475 | // 3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. |
| 479 | else if (c == '#') { | 476 | else if (c == '#') { |
| 480 | fragment.clearRetainingCapacity(); | 477 | href.clear(14); |
| 481 | state = .fragment; | 478 | state = .fragment; |
| 482 | } | 479 | } |
| 483 | // 4. Otherwise, if c is not the EOF code point: | 480 | // 4. Otherwise, if c is not the EOF code point: |
| 484 | else if (i < length) { | 481 | else if (i < length) { |
| 485 | // 1. Set url’s query to null. | 482 | // 1. Set url’s query to null. |
| 486 | query.clearRetainingCapacity(); | 483 | href.clear(12); |
| 487 | // 2. If the code point substring from pointer to the end of input does not start with a Windows drive letter, then shorten url’s path. | 484 | // 2. If the code point substring from pointer to the end of input does not start with a Windows drive letter, then shorten url’s path. |
| 488 | // 3. Otherwise: | 485 | // 3. Otherwise: |
| 489 | // This is a (platform-independent) Windows drive letter quirk. | 486 | // This is a (platform-independent) Windows drive letter quirk. |
| ... | @@ -546,7 +543,7 @@ pub const URL = struct { | ... | @@ -546,7 +543,7 @@ pub const URL = struct { |
| 546 | // 2. Otherwise, if buffer is the empty string, then: | 543 | // 2. Otherwise, if buffer is the empty string, then: |
| 547 | else if (buffer.items.len == 0) { | 544 | else if (buffer.items.len == 0) { |
| 548 | // 1. Set url’s host to the empty string. | 545 | // 1. Set url’s host to the empty string. |
| 549 | host = .{ .name = "" }; | 546 | href.clear(7); |
| 550 | // 2. If state override is given, then return. | 547 | // 2. If state override is given, then return. |
| 551 | if (state_override != null) break; | 548 | if (state_override != null) break; |
| 552 | // 3. Set state to path start state. | 549 | // 3. Set state to path start state. |
| ... | @@ -563,6 +560,7 @@ pub const URL = struct { | ... | @@ -563,6 +560,7 @@ pub const URL = struct { |
| 563 | h = .{ .name = "" }; | 560 | h = .{ .name = "" }; |
| 564 | } | 561 | } |
| 565 | // 4. Set url’s host to host. | 562 | // 4. Set url’s host to host. |
| | 563 | // try href.set(7, h); |
| 566 | host = h; | 564 | host = h; |
| 567 | // 5. If state override is given, then return. | 565 | // 5. If state override is given, then return. |
| 568 | if (state_override != null) break; | 566 | if (state_override != null) break; |
| ... | @@ -590,12 +588,12 @@ pub const URL = struct { | ... | @@ -590,12 +588,12 @@ pub const URL = struct { |
| 590 | } | 588 | } |
| 591 | // 2. Otherwise, if state override is not given and c is U+003F (?), set url’s query to the empty string and state to query state. | 589 | // 2. Otherwise, if state override is not given and c is U+003F (?), set url’s query to the empty string and state to query state. |
| 592 | else if (state_override == null and c == '?') { | 590 | else if (state_override == null and c == '?') { |
| 593 | query.clearRetainingCapacity(); | 591 | href.clear(12); |
| 594 | state = .query; | 592 | state = .query; |
| 595 | } | 593 | } |
| 596 | // 3. Otherwise, if state override is not given and c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. | 594 | // 3. Otherwise, if state override is not given and c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. |
| 597 | else if (state_override == null and c == '#') { | 595 | else if (state_override == null and c == '#') { |
| 598 | fragment.clearRetainingCapacity(); | 596 | href.clear(14); |
| 599 | state = .fragment; | 597 | state = .fragment; |
| 600 | } | 598 | } |
| 601 | // 4. Otherwise, if c is not the EOF code point: | 599 | // 4. Otherwise, if c is not the EOF code point: |
| ... | @@ -638,22 +636,22 @@ pub const URL = struct { | ... | @@ -638,22 +636,22 @@ pub const URL = struct { |
| 638 | else if (!isSingleDotPathSeg(buffer.items)) { | 636 | else if (!isSingleDotPathSeg(buffer.items)) { |
| 639 | // 1. If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then replace the second code point in buffer with U+003A (:). | 637 | // 1. If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then replace the second code point in buffer with U+003A (:). |
| 640 | // > This is a (platform-independent) Windows drive letter quirk. | 638 | // > This is a (platform-independent) Windows drive letter quirk. |
| 641 | if (std.mem.eql(u8, href.items(0), "file") and path.items.len == 0 and isWindowsDriveLetter(buffer.items)) { | 639 | if (std.mem.eql(u8, href.items(0), "file") and href.items(10).len == 0 and isWindowsDriveLetter(buffer.items)) { |
| 642 | buffer.items[1] = ':'; | 640 | buffer.items[1] = ':'; |
| 643 | } | 641 | } |
| 644 | // 2. Append buffer to url’s path. | 642 | // 2. Append buffer to url’s path. |
| 645 | try path.appendSlice(buffer.items); | 643 | try href.appendSlice(10, buffer.items); |
| 646 | } | 644 | } |
| 647 | // 5. Set buffer to the empty string. | 645 | // 5. Set buffer to the empty string. |
| 648 | buffer.clearRetainingCapacity(); | 646 | buffer.clearRetainingCapacity(); |
| 649 | // 6. If c is U+003F (?), then set url’s query to the empty string and state to query state. | 647 | // 6. If c is U+003F (?), then set url’s query to the empty string and state to query state. |
| 650 | if (c == '?') { | 648 | if (c == '?') { |
| 651 | query.clearRetainingCapacity(); | 649 | href.clear(12); |
| 652 | state = .query; | 650 | state = .query; |
| 653 | } | 651 | } |
| 654 | // 7. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. | 652 | // 7. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. |
| 655 | if (c == '#') { | 653 | if (c == '#') { |
| 656 | fragment.clearRetainingCapacity(); | 654 | href.clear(14); |
| 657 | state = .fragment; | 655 | state = .fragment; |
| 658 | } | 656 | } |
| 659 | } | 657 | } |
| ... | @@ -676,12 +674,12 @@ pub const URL = struct { | ... | @@ -676,12 +674,12 @@ pub const URL = struct { |
| 676 | .opaque_path => { | 674 | .opaque_path => { |
| 677 | // 1. If c is U+003F (?), then set url’s query to the empty string and state to query state. | 675 | // 1. If c is U+003F (?), then set url’s query to the empty string and state to query state. |
| 678 | if (c == '?') { | 676 | if (c == '?') { |
| 679 | query.clearRetainingCapacity(); | 677 | href.clear(12); |
| 680 | state = .query; | 678 | state = .query; |
| 681 | } | 679 | } |
| 682 | // 2. Otherwise, if c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. | 680 | // 2. Otherwise, if c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. |
| 683 | else if (c == '#') { | 681 | else if (c == '#') { |
| 684 | fragment.clearRetainingCapacity(); | 682 | href.clear(14); |
| 685 | state = .fragment; | 683 | state = .fragment; |
| 686 | } | 684 | } |
| 687 | // 3. Otherwise, if c is U+0020 SPACE: | 685 | // 3. Otherwise, if c is U+0020 SPACE: |
| ... | @@ -689,11 +687,11 @@ pub const URL = struct { | ... | @@ -689,11 +687,11 @@ pub const URL = struct { |
| 689 | // 1. If remaining starts with U+003F (?) or U+003F (#), then append "%20" to url’s path. | 687 | // 1. If remaining starts with U+003F (?) or U+003F (#), then append "%20" to url’s path. |
| 690 | const rem = inputl.items[i + l(c) ..]; | 688 | const rem = inputl.items[i + l(c) ..]; |
| 691 | if (std.mem.startsWith(u8, rem, "?") or std.mem.startsWith(u8, rem, "#")) { | 689 | if (std.mem.startsWith(u8, rem, "?") or std.mem.startsWith(u8, rem, "#")) { |
| 692 | try path.appendSlice("%20"); | 690 | try href.appendSlice(10, "%20"); |
| 693 | } | 691 | } |
| 694 | // 2. Otherwise, append U+0020 SPACE to url’s path. | 692 | // 2. Otherwise, append U+0020 SPACE to url’s path. |
| 695 | else { | 693 | else { |
| 696 | try path.append(' '); | 694 | try href.appendSlice(10, " "); |
| 697 | } | 695 | } |
| 698 | } | 696 | } |
| 699 | // 4. Otherwise, if c is not the EOF code point: | 697 | // 4. Otherwise, if c is not the EOF code point: |
| ... | @@ -703,7 +701,7 @@ pub const URL = struct { | ... | @@ -703,7 +701,7 @@ pub const URL = struct { |
| 703 | // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error. | 701 | // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error. |
| 704 | {} | 702 | {} |
| 705 | // 3. UTF-8 percent-encode c using the C0 control percent-encode set and append the result to url’s path. | 703 | // 3. UTF-8 percent-encode c using the C0 control percent-encode set and append the result to url’s path. |
| 706 | try percentEncodeScalarAL(&path, inputl.items[i..][0..l(c)], is_c0control_percent_char); | 704 | try percentEncodeScalarML(&href, 10, inputl.items[i..][0..l(c)], is_c0control_percent_char); |
| 707 | } | 705 | } |
| 708 | }, | 706 | }, |
| 709 | .query => { | 707 | .query => { |
| ... | @@ -720,15 +718,15 @@ pub const URL = struct { | ... | @@ -720,15 +718,15 @@ pub const URL = struct { |
| 720 | // 2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the result to url’s query. | 718 | // 2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the result to url’s query. |
| 721 | // > This operation cannot be invoked code-point-for-code-point due to the stateful ISO-2022-JP encoder. | 719 | // > This operation cannot be invoked code-point-for-code-point due to the stateful ISO-2022-JP encoder. |
| 722 | if (isSchemeSpecial(href.items(0))) { | 720 | if (isSchemeSpecial(href.items(0))) { |
| 723 | try percentEncodeAL(&query, buffer.items, is_special_query_percent_char); | 721 | try percentEncodeML(&href, 12, buffer.items, is_special_query_percent_char); |
| 724 | } else { | 722 | } else { |
| 725 | try percentEncodeAL(&query, buffer.items, is_query_percent_char); | 723 | try percentEncodeML(&href, 12, buffer.items, is_query_percent_char); |
| 726 | } | 724 | } |
| 727 | // 3. Set buffer to the empty string. | 725 | // 3. Set buffer to the empty string. |
| 728 | buffer.clearRetainingCapacity(); | 726 | buffer.clearRetainingCapacity(); |
| 729 | // 4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. | 727 | // 4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. |
| 730 | if (c == '#') { | 728 | if (c == '#') { |
| 731 | fragment.clearRetainingCapacity(); | 729 | href.clear(14); |
| 732 | state = .fragment; | 730 | state = .fragment; |
| 733 | } | 731 | } |
| 734 | } | 732 | } |
| ... | @@ -750,7 +748,7 @@ pub const URL = struct { | ... | @@ -750,7 +748,7 @@ pub const URL = struct { |
| 750 | // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error. | 748 | // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error. |
| 751 | {} | 749 | {} |
| 752 | // 3. UTF-8 percent-encode c using the fragment percent-encode set and append the result to url’s fragment. | 750 | // 3. UTF-8 percent-encode c using the fragment percent-encode set and append the result to url’s fragment. |
| 753 | try percentEncodeScalarAL(&fragment, inputl.items[i..][0..l(c)], is_fragment_percent_char); | 751 | try percentEncodeScalarML(&href, 14, inputl.items[i..][0..l(c)], is_fragment_percent_char); |
| 754 | } | 752 | } |
| 755 | }, | 753 | }, |
| 756 | } | 754 | } |
| ... | @@ -1381,6 +1379,29 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn | ... | @@ -1381,6 +1379,29 @@ fn percentEncodeAL(list: *std.ArrayList(u8), input: []const u8, comptime set: fn |
| 1381 | } | 1379 | } |
| 1382 | } | 1380 | } |
| 1383 | } | 1381 | } |
| | 1382 | fn percentEncodeScalarML(list: *ManyArrayList(15, u8), n: usize, cp: []const u8, comptime set: fn (u8) bool) !void { |
| | 1383 | if (set(cp[0])) { |
| | 1384 | for (cp) |b| { |
| | 1385 | try list.appendSlice(n, &.{'%'}); |
| | 1386 | try list.print(n, "{d:0<2}", .{b}); |
| | 1387 | } |
| | 1388 | } else { |
| | 1389 | try list.appendSlice(n, &.{cp[0]}); |
| | 1390 | } |
| | 1391 | } |
| | 1392 | fn percentEncodeML(list: *ManyArrayList(15, u8), n: usize, input: []const u8, comptime set: fn (u8) bool) !void { |
| | 1393 | var it = std.unicode.Utf8View.initUnchecked(input).iterator(); |
| | 1394 | while (it.nextCodepointSlice()) |sl| { |
| | 1395 | if (set(sl[0])) { |
| | 1396 | for (sl) |b| { |
| | 1397 | try list.appendSlice(n, &.{'%'}); |
| | 1398 | try list.print(n, "{d:0<2}", .{b}); |
| | 1399 | } |
| | 1400 | } else { |
| | 1401 | try list.appendSlice(n, sl); |
| | 1402 | } |
| | 1403 | } |
| | 1404 | } |
| 1384 | | 1405 | |
| 1385 | pub fn ManyArrayList(N: usize, T: type) type { | 1406 | pub fn ManyArrayList(N: usize, T: type) type { |
| 1386 | return struct { | 1407 | return struct { |
| ... | @@ -1409,5 +1430,23 @@ pub fn ManyArrayList(N: usize, T: type) type { | ... | @@ -1409,5 +1430,23 @@ pub fn ManyArrayList(N: usize, T: type) type { |
| 1409 | const len = self.lengths[n]; | 1430 | const len = self.lengths[n]; |
| 1410 | return self.list.items[real_n..][0..len]; | 1431 | return self.list.items[real_n..][0..len]; |
| 1411 | } | 1432 | } |
| | 1433 | |
| | 1434 | pub fn clear(self: *@This(), n: usize) void { |
| | 1435 | const real_n = extras.sum(usize, self.lengths[0..n]); |
| | 1436 | self.list.replaceRangeAssumeCapacity(real_n, self.lengths[n], &.{}); |
| | 1437 | self.lengths[n] = 0; |
| | 1438 | } |
| | 1439 | |
| | 1440 | pub fn print(self: *@This(), n: usize, comptime fmt: []const u8, args: anytype) !void { |
| | 1441 | var buffer: [64]u8 = undefined; |
| | 1442 | const slice = std.fmt.bufPrint(&buffer, fmt, args) catch unreachable; |
| | 1443 | return self.appendSlice(n, slice); |
| | 1444 | } |
| | 1445 | |
| | 1446 | pub fn appendSlice(self: *@This(), n: usize, slice: []const T) !void { |
| | 1447 | const real_n = extras.sum(usize, self.lengths[0 .. n + 1]); |
| | 1448 | try self.list.insertSlice(real_n, slice); |
| | 1449 | self.lengths[n] += slice.len; |
| | 1450 | } |
| 1412 | }; | 1451 | }; |
| 1413 | } | 1452 | } |