authorgravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2022-05-17 13:00:07+02:00
committergravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2022-05-17 18:54:29+02:00
log405f4286f729f395ab1f9eb228fdf9cad9434b7c
tree7c4d9d0d31cc2d17008eb94d036ec472aac93bbc
parentf3517a1aa6058e9b09d57e81ecc81f27f086d163
signaturelock-open Commit is signed but in an unrecognized format.

std.unicode: add utf16 byte length and codepoints counting routines

* comptime and runtime tests are based on tests for counting utf8 code points

1 files changed, 58 insertions(+), 5 deletions(-)

lib/std/unicode.zig+58-5
......@@ -325,6 +325,42 @@ pub const Utf16LeIterator = struct {
325325 }
326326};
327327
328/// Returns the length of a supplied UTF-16 string literal in terms of unicode
329/// codepoints.
330pub fn utf16CountCodepoints(utf16le: []const u16) !usize {
331 var len: usize = 0;
332 var it = Utf16LeIterator.init(utf16le);
333 while (try it.nextCodepoint()) |_| len += 1;
334 return len;
335}
336
337fn testUtf16CountCodepoints() !void {
338 try testing.expectEqual(
339 @as(usize, 1),
340 try utf16CountCodepoints(utf8ToUtf16LeStringLiteral("a")),
341 );
342 try testing.expectEqual(
343 @as(usize, 10),
344 try utf16CountCodepoints(utf8ToUtf16LeStringLiteral("abcdefghij")),
345 );
346 try testing.expectEqual(
347 @as(usize, 10),
348 try utf16CountCodepoints(utf8ToUtf16LeStringLiteral("äåéëþüúíóö")),
349 );
350 try testing.expectEqual(
351 @as(usize, 5),
352 try utf16CountCodepoints(utf8ToUtf16LeStringLiteral("こんにちは")),
353 );
354 // testing.expectError(error.Utf8EncodesSurrogateHalf, utf8CountCodepoints("\xED\xA0\x80"));
355}
356
357test "utf16 count codepoints" {
358 try testUtf16CountCodepoints();
359 // TODO stage1 error: out of bounds slice
360 if (@import("builtin").zig_backend != .stage1)
361 comptime try testUtf16CountCodepoints();
362}
363
328364test "utf8 encode" {
329365 comptime try testUtf8Encode();
330366 try testUtf8Encode();
......@@ -748,9 +784,9 @@ test "utf8ToUtf16LeWithNull" {
748784}
749785
750786/// Converts a UTF-8 string literal into a UTF-16LE string literal.
751pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 {
787pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) catch unreachable:0]u16 {
752788 comptime {
753 const len: usize = calcUtf16LeLen(utf8);
789 const len: usize = calcUtf16LeLen(utf8) catch |err| @compileError(err);
754790 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
755791 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
756792 assert(len == utf16le_len);
......@@ -758,13 +794,17 @@ pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16Le
758794 }
759795}
760796
761fn calcUtf16LeLen(utf8: []const u8) usize {
797const CalcUtf16LeLenError = Utf8DecodeError || error{Utf8InvalidStartByte};
798
799/// Returns length in UTF-16 of UTF-8 slice as length of []u16.
800/// Length in []u8 is 2*len16.
801pub fn calcUtf16LeLen(utf8: []const u8) CalcUtf16LeLenError!usize {
762802 var src_i: usize = 0;
763803 var dest_len: usize = 0;
764804 while (src_i < utf8.len) {
765 const n = utf8ByteSequenceLength(utf8[src_i]) catch unreachable;
805 const n = try utf8ByteSequenceLength(utf8[src_i]);
766806 const next_src_i = src_i + n;
767 const codepoint = utf8Decode(utf8[src_i..next_src_i]) catch unreachable;
807 const codepoint = try utf8Decode(utf8[src_i..next_src_i]);
768808 if (codepoint < 0x10000) {
769809 dest_len += 1;
770810 } else {
......@@ -775,6 +815,19 @@ fn calcUtf16LeLen(utf8: []const u8) usize {
775815 return dest_len;
776816}
777817
818fn testCalcUtf16LeLen() !void {
819 try testing.expectEqual(@as(usize, 1), try calcUtf16LeLen("a"));
820 try testing.expectEqual(@as(usize, 10), try calcUtf16LeLen("abcdefghij"));
821 try testing.expectEqual(@as(usize, 10), try calcUtf16LeLen("äåéëþüúíóö"));
822 try testing.expectEqual(@as(usize, 5), try calcUtf16LeLen("こんにちは"));
823 // testing.expectError(error.Utf8EncodesSurrogateHalf, utf8CountCodepoints("\xED\xA0\x80"));
824}
825
826test "calculate utf16 string length of given utf8 string in u16" {
827 try testCalcUtf16LeLen();
828 comptime try testCalcUtf16LeLen();
829}
830
778831/// Print the given `utf16le` string
779832fn formatUtf16le(
780833 utf16le: []const u16,