| ... | @@ -2,6 +2,7 @@ const std = @import("./std.zig"); | ... | @@ -2,6 +2,7 @@ const std = @import("./std.zig"); |
| 2 | const assert = std.debug.assert; | 2 | const assert = std.debug.assert; |
| 3 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| | 5 | const builtin = @import("builtin"); |
| 5 | | 6 | |
| 6 | /// Use this to replace an unknown, unrecognized, or unrepresentable character. | 7 | /// Use this to replace an unknown, unrecognized, or unrepresentable character. |
| 7 | /// | 8 | /// |
| ... | @@ -863,7 +864,27 @@ pub fn utf8ToUtf16LeWithNull(allocator: mem.Allocator, utf8: []const u8) ![:0]u1 | ... | @@ -863,7 +864,27 @@ pub fn utf8ToUtf16LeWithNull(allocator: mem.Allocator, utf8: []const u8) ![:0]u1 |
| 863 | var result = try std.ArrayList(u16).initCapacity(allocator, utf8.len + 1); | 864 | var result = try std.ArrayList(u16).initCapacity(allocator, utf8.len + 1); |
| 864 | errdefer result.deinit(); | 865 | errdefer result.deinit(); |
| 865 | | 866 | |
| 866 | const view = try Utf8View.init(utf8); | 867 | var remaining = utf8; |
| | 868 | if (builtin.zig_backend != .stage2_x86_64) { |
| | 869 | const chunk_len = std.simd.suggestVectorSize(u8) orelse 1; |
| | 870 | const Chunk = @Vector(chunk_len, u8); |
| | 871 | |
| | 872 | // Fast path. Check for and encode ASCII characters at the start of the input. |
| | 873 | while (remaining.len >= chunk_len) { |
| | 874 | const chunk: Chunk = remaining[0..chunk_len].*; |
| | 875 | const mask: Chunk = @splat(0x80); |
| | 876 | if (@reduce(.Or, chunk & mask == mask)) { |
| | 877 | // found a non ASCII code unit |
| | 878 | break; |
| | 879 | } |
| | 880 | const zeroes: Chunk = @splat(0); |
| | 881 | const utf16_chunk: [chunk_len * 2]u8 align(@alignOf(u16)) = std.simd.interlace(.{ chunk, zeroes }); |
| | 882 | result.appendSliceAssumeCapacity(std.mem.bytesAsSlice(u16, &utf16_chunk)); |
| | 883 | remaining = remaining[chunk_len..]; |
| | 884 | } |
| | 885 | } |
| | 886 | |
| | 887 | const view = try Utf8View.init(remaining); |
| 867 | var it = view.iterator(); | 888 | var it = view.iterator(); |
| 868 | while (it.nextCodepoint()) |codepoint| { | 889 | while (it.nextCodepoint()) |codepoint| { |
| 869 | if (codepoint < 0x10000) { | 890 | if (codepoint < 0x10000) { |
| ... | @@ -886,11 +907,33 @@ pub fn utf8ToUtf16LeWithNull(allocator: mem.Allocator, utf8: []const u8) ![:0]u1 | ... | @@ -886,11 +907,33 @@ pub fn utf8ToUtf16LeWithNull(allocator: mem.Allocator, utf8: []const u8) ![:0]u1 |
| 886 | /// Assumes there is enough space for the output. | 907 | /// Assumes there is enough space for the output. |
| 887 | pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { | 908 | pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { |
| 888 | var dest_i: usize = 0; | 909 | var dest_i: usize = 0; |
| | 910 | |
| | 911 | var remaining = utf8; |
| | 912 | if (builtin.zig_backend != .stage2_x86_64) { |
| | 913 | const chunk_len = std.simd.suggestVectorSize(u8) orelse 1; |
| | 914 | const Chunk = @Vector(chunk_len, u8); |
| | 915 | |
| | 916 | // Fast path. Check for and encode ASCII characters at the start of the input. |
| | 917 | while (remaining.len >= chunk_len) { |
| | 918 | const chunk: Chunk = remaining[0..chunk_len].*; |
| | 919 | const mask: Chunk = @splat(0x80); |
| | 920 | if (@reduce(.Or, chunk & mask == mask)) { |
| | 921 | // found a non ASCII code unit |
| | 922 | break; |
| | 923 | } |
| | 924 | const zeroes: Chunk = @splat(0); |
| | 925 | const utf16_bytes: [chunk_len * 2]u8 align(@alignOf(u16)) = std.simd.interlace(.{ chunk, zeroes }); |
| | 926 | @memcpy(utf16le[dest_i..][0..chunk_len], std.mem.bytesAsSlice(u16, &utf16_bytes)); |
| | 927 | dest_i += chunk_len; |
| | 928 | remaining = remaining[chunk_len..]; |
| | 929 | } |
| | 930 | } |
| | 931 | |
| 889 | var src_i: usize = 0; | 932 | var src_i: usize = 0; |
| 890 | while (src_i < utf8.len) { | 933 | while (src_i < remaining.len) { |
| 891 | const n = utf8ByteSequenceLength(utf8[src_i]) catch return error.InvalidUtf8; | 934 | const n = utf8ByteSequenceLength(remaining[src_i]) catch return error.InvalidUtf8; |
| 892 | const next_src_i = src_i + n; | 935 | const next_src_i = src_i + n; |
| 893 | const codepoint = utf8Decode(utf8[src_i..next_src_i]) catch return error.InvalidUtf8; | 936 | const codepoint = utf8Decode(remaining[src_i..next_src_i]) catch return error.InvalidUtf8; |
| 894 | if (codepoint < 0x10000) { | 937 | if (codepoint < 0x10000) { |
| 895 | const short = @as(u16, @intCast(codepoint)); | 938 | const short = @as(u16, @intCast(codepoint)); |
| 896 | utf16le[dest_i] = mem.nativeToLittle(u16, short); | 939 | utf16le[dest_i] = mem.nativeToLittle(u16, short); |