/src/simdutf/include/simdutf/scalar/utf16.h
Line | Count | Source |
1 | | #ifndef SIMDUTF_UTF16_H |
2 | | #define SIMDUTF_UTF16_H |
3 | | |
4 | | namespace simdutf { |
5 | | namespace scalar { |
6 | | namespace utf16 { |
7 | | |
8 | | template <endianness big_endian> |
9 | | simdutf_warn_unused simdutf_constexpr23 bool |
10 | 406 | validate_as_ascii(const char16_t *data, size_t len) noexcept { |
11 | 17.2k | for (size_t pos = 0; pos < len; pos++) { |
12 | 17.2k | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
13 | 17.2k | if (word >= 0x80) { |
14 | 360 | return false; |
15 | 360 | } |
16 | 17.2k | } |
17 | 46 | return true; |
18 | 406 | } bool simdutf::scalar::utf16::validate_as_ascii<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 10 | 203 | validate_as_ascii(const char16_t *data, size_t len) noexcept { | 11 | 8.30k | for (size_t pos = 0; pos < len; pos++) { | 12 | 8.28k | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 13 | 8.28k | if (word >= 0x80) { | 14 | 181 | return false; | 15 | 181 | } | 16 | 8.28k | } | 17 | 22 | return true; | 18 | 203 | } |
bool simdutf::scalar::utf16::validate_as_ascii<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 10 | 203 | validate_as_ascii(const char16_t *data, size_t len) noexcept { | 11 | 8.99k | for (size_t pos = 0; pos < len; pos++) { | 12 | 8.96k | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 13 | 8.96k | if (word >= 0x80) { | 14 | 179 | return false; | 15 | 179 | } | 16 | 8.96k | } | 17 | 24 | return true; | 18 | 203 | } |
|
19 | | |
20 | | template <endianness big_endian> |
21 | | inline simdutf_warn_unused simdutf_constexpr23 bool |
22 | 58.9k | validate(const char16_t *data, size_t len) noexcept { |
23 | 58.9k | uint64_t pos = 0; |
24 | 68.1M | while (pos < len) { |
25 | 68.0M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
26 | 68.0M | if ((word & 0xF800) == 0xD800) { |
27 | 167k | if (pos + 1 >= len) { |
28 | 792 | return false; |
29 | 792 | } |
30 | 167k | char16_t diff = char16_t(word - 0xD800); |
31 | 167k | if (diff > 0x3FF) { |
32 | 1.32k | return false; |
33 | 1.32k | } |
34 | 165k | char16_t next_word = !match_system(big_endian) |
35 | 165k | ? u16_swap_bytes(data[pos + 1]) |
36 | 165k | : data[pos + 1]; |
37 | 165k | char16_t diff2 = char16_t(next_word - 0xDC00); |
38 | 165k | if (diff2 > 0x3FF) { |
39 | 1.95k | return false; |
40 | 1.95k | } |
41 | 163k | pos += 2; |
42 | 67.8M | } else { |
43 | 67.8M | pos++; |
44 | 67.8M | } |
45 | 68.0M | } |
46 | 54.8k | return true; |
47 | 58.9k | } bool simdutf::scalar::utf16::validate<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 22 | 30.2k | validate(const char16_t *data, size_t len) noexcept { | 23 | 30.2k | uint64_t pos = 0; | 24 | 37.6M | while (pos < len) { | 25 | 37.6M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 26 | 37.6M | if ((word & 0xF800) == 0xD800) { | 27 | 90.1k | if (pos + 1 >= len) { | 28 | 476 | return false; | 29 | 476 | } | 30 | 89.7k | char16_t diff = char16_t(word - 0xD800); | 31 | 89.7k | if (diff > 0x3FF) { | 32 | 840 | return false; | 33 | 840 | } | 34 | 88.8k | char16_t next_word = !match_system(big_endian) | 35 | 88.8k | ? u16_swap_bytes(data[pos + 1]) | 36 | 88.8k | : data[pos + 1]; | 37 | 88.8k | char16_t diff2 = char16_t(next_word - 0xDC00); | 38 | 88.8k | if (diff2 > 0x3FF) { | 39 | 1.12k | return false; | 40 | 1.12k | } | 41 | 87.7k | pos += 2; | 42 | 37.5M | } else { | 43 | 37.5M | pos++; | 44 | 37.5M | } | 45 | 37.6M | } | 46 | 27.8k | return true; | 47 | 30.2k | } |
bool simdutf::scalar::utf16::validate<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 22 | 28.6k | validate(const char16_t *data, size_t len) noexcept { | 23 | 28.6k | uint64_t pos = 0; | 24 | 30.4M | while (pos < len) { | 25 | 30.4M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 26 | 30.4M | if ((word & 0xF800) == 0xD800) { | 27 | 77.6k | if (pos + 1 >= len) { | 28 | 316 | return false; | 29 | 316 | } | 30 | 77.3k | char16_t diff = char16_t(word - 0xD800); | 31 | 77.3k | if (diff > 0x3FF) { | 32 | 483 | return false; | 33 | 483 | } | 34 | 76.8k | char16_t next_word = !match_system(big_endian) | 35 | 76.8k | ? u16_swap_bytes(data[pos + 1]) | 36 | 76.8k | : data[pos + 1]; | 37 | 76.8k | char16_t diff2 = char16_t(next_word - 0xDC00); | 38 | 76.8k | if (diff2 > 0x3FF) { | 39 | 829 | return false; | 40 | 829 | } | 41 | 76.0k | pos += 2; | 42 | 30.3M | } else { | 43 | 30.3M | pos++; | 44 | 30.3M | } | 45 | 30.4M | } | 46 | 27.0k | return true; | 47 | 28.6k | } |
|
48 | | |
49 | | template <endianness big_endian> |
50 | | inline simdutf_warn_unused simdutf_constexpr23 result |
51 | 21.5k | validate_with_errors(const char16_t *data, size_t len) noexcept { |
52 | 21.5k | size_t pos = 0; |
53 | 42.2M | while (pos < len) { |
54 | 42.1M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); |
55 | 42.1M | if ((word & 0xF800) == 0xD800) { |
56 | 53.0k | if (pos + 1 >= len) { |
57 | 554 | return result(error_code::SURROGATE, pos); |
58 | 554 | } |
59 | 52.5k | char16_t diff = char16_t(word - 0xD800); |
60 | 52.5k | if (diff > 0x3FF) { |
61 | 1.10k | return result(error_code::SURROGATE, pos); |
62 | 1.10k | } |
63 | 51.4k | char16_t next_word = !match_system(big_endian) |
64 | 51.4k | ? u16_swap_bytes(data[pos + 1]) |
65 | 51.4k | : data[pos + 1]; |
66 | 51.4k | char16_t diff2 = uint16_t(next_word - 0xDC00); |
67 | 51.4k | if (diff2 > 0x3FF) { |
68 | 1.72k | return result(error_code::SURROGATE, pos); |
69 | 1.72k | } |
70 | 49.7k | pos += 2; |
71 | 42.1M | } else { |
72 | 42.1M | pos++; |
73 | 42.1M | } |
74 | 42.1M | } |
75 | 18.2k | return result(error_code::SUCCESS, pos); |
76 | 21.5k | } simdutf::result simdutf::scalar::utf16::validate_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 51 | 10.9k | validate_with_errors(const char16_t *data, size_t len) noexcept { | 52 | 10.9k | size_t pos = 0; | 53 | 21.0M | while (pos < len) { | 54 | 20.9M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 55 | 20.9M | if ((word & 0xF800) == 0xD800) { | 56 | 32.2k | if (pos + 1 >= len) { | 57 | 276 | return result(error_code::SURROGATE, pos); | 58 | 276 | } | 59 | 31.9k | char16_t diff = char16_t(word - 0xD800); | 60 | 31.9k | if (diff > 0x3FF) { | 61 | 594 | return result(error_code::SURROGATE, pos); | 62 | 594 | } | 63 | 31.3k | char16_t next_word = !match_system(big_endian) | 64 | 31.3k | ? u16_swap_bytes(data[pos + 1]) | 65 | 31.3k | : data[pos + 1]; | 66 | 31.3k | char16_t diff2 = uint16_t(next_word - 0xDC00); | 67 | 31.3k | if (diff2 > 0x3FF) { | 68 | 839 | return result(error_code::SURROGATE, pos); | 69 | 839 | } | 70 | 30.5k | pos += 2; | 71 | 20.9M | } else { | 72 | 20.9M | pos++; | 73 | 20.9M | } | 74 | 20.9M | } | 75 | 9.23k | return result(error_code::SUCCESS, pos); | 76 | 10.9k | } |
simdutf::result simdutf::scalar::utf16::validate_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 51 | 10.6k | validate_with_errors(const char16_t *data, size_t len) noexcept { | 52 | 10.6k | size_t pos = 0; | 53 | 21.1M | while (pos < len) { | 54 | 21.1M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]); | 55 | 21.1M | if ((word & 0xF800) == 0xD800) { | 56 | 20.8k | if (pos + 1 >= len) { | 57 | 278 | return result(error_code::SURROGATE, pos); | 58 | 278 | } | 59 | 20.5k | char16_t diff = char16_t(word - 0xD800); | 60 | 20.5k | if (diff > 0x3FF) { | 61 | 514 | return result(error_code::SURROGATE, pos); | 62 | 514 | } | 63 | 20.0k | char16_t next_word = !match_system(big_endian) | 64 | 20.0k | ? u16_swap_bytes(data[pos + 1]) | 65 | 20.0k | : data[pos + 1]; | 66 | 20.0k | char16_t diff2 = uint16_t(next_word - 0xDC00); | 67 | 20.0k | if (diff2 > 0x3FF) { | 68 | 886 | return result(error_code::SURROGATE, pos); | 69 | 886 | } | 70 | 19.1k | pos += 2; | 71 | 21.1M | } else { | 72 | 21.1M | pos++; | 73 | 21.1M | } | 74 | 21.1M | } | 75 | 8.97k | return result(error_code::SUCCESS, pos); | 76 | 10.6k | } |
|
77 | | |
78 | | template <endianness big_endian> |
79 | 9.92k | simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { |
80 | | // We are not BOM aware. |
81 | 9.92k | size_t counter{0}; |
82 | 54.0M | for (size_t i = 0; i < len; i++) { |
83 | 54.0M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
84 | 54.0M | counter += ((word & 0xFC00) != 0xDC00); |
85 | 54.0M | } |
86 | 9.92k | return counter; |
87 | 9.92k | } unsigned long simdutf::scalar::utf16::count_code_points<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 79 | 5.08k | simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { | 80 | | // We are not BOM aware. | 81 | 5.08k | size_t counter{0}; | 82 | 26.2M | for (size_t i = 0; i < len; i++) { | 83 | 26.2M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 84 | 26.2M | counter += ((word & 0xFC00) != 0xDC00); | 85 | 26.2M | } | 86 | 5.08k | return counter; | 87 | 5.08k | } |
unsigned long simdutf::scalar::utf16::count_code_points<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 79 | 4.84k | simdutf_constexpr23 size_t count_code_points(const char16_t *p, size_t len) { | 80 | | // We are not BOM aware. | 81 | 4.84k | size_t counter{0}; | 82 | 27.7M | for (size_t i = 0; i < len; i++) { | 83 | 27.7M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 84 | 27.7M | counter += ((word & 0xFC00) != 0xDC00); | 85 | 27.7M | } | 86 | 4.84k | return counter; | 87 | 4.84k | } |
|
88 | | |
89 | | template <endianness big_endian> |
90 | | simdutf_constexpr23 size_t utf8_length_from_utf16(const char16_t *p, |
91 | 77.5k | size_t len) { |
92 | | // We are not BOM aware. |
93 | 77.5k | size_t counter{0}; |
94 | 63.9M | for (size_t i = 0; i < len; i++) { |
95 | 63.9M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
96 | 63.9M | counter++; // ASCII |
97 | 63.9M | counter += static_cast<size_t>( |
98 | 63.9M | word > |
99 | 63.9M | 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes |
100 | 63.9M | counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) || |
101 | 43.8M | (word >= 0xE000)); // three-byte |
102 | 63.9M | } |
103 | 77.5k | return counter; |
104 | 77.5k | } unsigned long simdutf::scalar::utf16::utf8_length_from_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 91 | 39.4k | size_t len) { | 92 | | // We are not BOM aware. | 93 | 39.4k | size_t counter{0}; | 94 | 39.0M | for (size_t i = 0; i < len; i++) { | 95 | 38.9M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 96 | 38.9M | counter++; // ASCII | 97 | 38.9M | counter += static_cast<size_t>( | 98 | 38.9M | word > | 99 | 38.9M | 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes | 100 | 38.9M | counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) || | 101 | 26.6M | (word >= 0xE000)); // three-byte | 102 | 38.9M | } | 103 | 39.4k | return counter; | 104 | 39.4k | } |
unsigned long simdutf::scalar::utf16::utf8_length_from_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 91 | 38.1k | size_t len) { | 92 | | // We are not BOM aware. | 93 | 38.1k | size_t counter{0}; | 94 | 24.9M | for (size_t i = 0; i < len; i++) { | 95 | 24.9M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 96 | 24.9M | counter++; // ASCII | 97 | 24.9M | counter += static_cast<size_t>( | 98 | 24.9M | word > | 99 | 24.9M | 0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes | 100 | 24.9M | counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) || | 101 | 17.1M | (word >= 0xE000)); // three-byte | 102 | 24.9M | } | 103 | 38.1k | return counter; | 104 | 38.1k | } |
|
105 | | |
106 | | template <endianness big_endian> |
107 | | simdutf_constexpr23 size_t utf32_length_from_utf16(const char16_t *p, |
108 | 833 | size_t len) { |
109 | | // We are not BOM aware. |
110 | 833 | size_t counter{0}; |
111 | 11.9M | for (size_t i = 0; i < len; i++) { |
112 | 11.9M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); |
113 | 11.9M | counter += ((word & 0xFC00) != 0xDC00); |
114 | 11.9M | } |
115 | 833 | return counter; |
116 | 833 | } unsigned long simdutf::scalar::utf16::utf32_length_from_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 108 | 413 | size_t len) { | 109 | | // We are not BOM aware. | 110 | 413 | size_t counter{0}; | 111 | 5.10M | for (size_t i = 0; i < len; i++) { | 112 | 5.10M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 113 | 5.10M | counter += ((word & 0xFC00) != 0xDC00); | 114 | 5.10M | } | 115 | 413 | return counter; | 116 | 413 | } |
unsigned long simdutf::scalar::utf16::utf32_length_from_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 108 | 420 | size_t len) { | 109 | | // We are not BOM aware. | 110 | 420 | size_t counter{0}; | 111 | 6.81M | for (size_t i = 0; i < len; i++) { | 112 | 6.81M | char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]); | 113 | 6.81M | counter += ((word & 0xFC00) != 0xDC00); | 114 | 6.81M | } | 115 | 420 | return counter; | 116 | 420 | } |
|
117 | | |
118 | | simdutf_really_inline simdutf_constexpr23 void |
119 | 381 | change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) { |
120 | 2.10M | for (size_t i = 0; i < size; i++) { |
121 | 2.10M | *output++ = char16_t(input[i] >> 8 | input[i] << 8); |
122 | 2.10M | } |
123 | 381 | } |
124 | | |
125 | | template <endianness big_endian> |
126 | | simdutf_warn_unused simdutf_constexpr23 size_t |
127 | 62 | trim_partial_utf16(const char16_t *input, size_t length) { |
128 | 62 | if (length == 0) { |
129 | 2 | return 0; |
130 | 2 | } |
131 | 60 | uint16_t last_word = uint16_t(input[length - 1]); |
132 | 60 | last_word = scalar::utf16::swap_if_needed<big_endian>(last_word); |
133 | 60 | length -= ((last_word & 0xFC00) == 0xD800); |
134 | 60 | return length; |
135 | 62 | } unsigned long simdutf::scalar::utf16::trim_partial_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 127 | 27 | trim_partial_utf16(const char16_t *input, size_t length) { | 128 | 27 | if (length == 0) { | 129 | 1 | return 0; | 130 | 1 | } | 131 | 26 | uint16_t last_word = uint16_t(input[length - 1]); | 132 | 26 | last_word = scalar::utf16::swap_if_needed<big_endian>(last_word); | 133 | 26 | length -= ((last_word & 0xFC00) == 0xD800); | 134 | 26 | return length; | 135 | 27 | } |
unsigned long simdutf::scalar::utf16::trim_partial_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 127 | 35 | trim_partial_utf16(const char16_t *input, size_t length) { | 128 | 35 | if (length == 0) { | 129 | 1 | return 0; | 130 | 1 | } | 131 | 34 | uint16_t last_word = uint16_t(input[length - 1]); | 132 | 34 | last_word = scalar::utf16::swap_if_needed<big_endian>(last_word); | 133 | 34 | length -= ((last_word & 0xFC00) == 0xD800); | 134 | 34 | return length; | 135 | 35 | } |
|
136 | | |
137 | 76.9M | template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) { |
138 | 76.9M | c = scalar::utf16::swap_if_needed<big_endian>(c); |
139 | 76.9M | return (0xd800 <= c && c <= 0xdbff); |
140 | 76.9M | } bool simdutf::scalar::utf16::is_high_surrogate<(simdutf::endianness)0>(char16_t) Line | Count | Source | 137 | 39.2M | template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) { | 138 | 39.2M | c = scalar::utf16::swap_if_needed<big_endian>(c); | 139 | 39.2M | return (0xd800 <= c && c <= 0xdbff); | 140 | 39.2M | } |
bool simdutf::scalar::utf16::is_high_surrogate<(simdutf::endianness)1>(char16_t) Line | Count | Source | 137 | 37.7M | template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) { | 138 | 37.7M | c = scalar::utf16::swap_if_needed<big_endian>(c); | 139 | 37.7M | return (0xd800 <= c && c <= 0xdbff); | 140 | 37.7M | } |
|
141 | | |
142 | 86.9M | template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) { |
143 | 86.9M | c = scalar::utf16::swap_if_needed<big_endian>(c); |
144 | 86.9M | return (0xdc00 <= c && c <= 0xdfff); |
145 | 86.9M | } bool simdutf::scalar::utf16::is_low_surrogate<(simdutf::endianness)0>(char16_t) Line | Count | Source | 142 | 44.4M | template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) { | 143 | 44.4M | c = scalar::utf16::swap_if_needed<big_endian>(c); | 144 | 44.4M | return (0xdc00 <= c && c <= 0xdfff); | 145 | 44.4M | } |
bool simdutf::scalar::utf16::is_low_surrogate<(simdutf::endianness)1>(char16_t) Line | Count | Source | 142 | 42.4M | template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) { | 143 | 42.4M | c = scalar::utf16::swap_if_needed<big_endian>(c); | 144 | 42.4M | return (0xdc00 <= c && c <= 0xdfff); | 145 | 42.4M | } |
|
146 | | |
147 | 792 | simdutf_unused simdutf_really_inline constexpr bool high_surrogate(char16_t c) { |
148 | 792 | return (0xd800 <= c && c <= 0xdbff); |
149 | 792 | } |
150 | | |
151 | | template <endianness big_endian> |
152 | | simdutf_constexpr23 result |
153 | 7.18k | utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { |
154 | 7.18k | bool any_surrogates = false; |
155 | | // We are not BOM aware. |
156 | 7.18k | size_t counter{0}; |
157 | 59.0M | for (size_t i = 0; i < len; i++) { |
158 | 59.0M | if (is_high_surrogate<big_endian>(p[i])) { |
159 | 1.93M | any_surrogates = true; |
160 | | // surrogate pair |
161 | 1.93M | if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) { |
162 | 120k | counter += 4; |
163 | 120k | i++; // skip low surrogate |
164 | 1.81M | } else { |
165 | 1.81M | counter += 3; // unpaired high surrogate replaced by U+FFFD |
166 | 1.81M | } |
167 | 1.93M | continue; |
168 | 57.0M | } else if (is_low_surrogate<big_endian>(p[i])) { |
169 | 1.72M | any_surrogates = true; |
170 | 1.72M | counter += 3; // unpaired low surrogate replaced by U+FFFD |
171 | 1.72M | continue; |
172 | 1.72M | } |
173 | 55.3M | char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; |
174 | 55.3M | counter++; // at least 1 byte |
175 | 55.3M | counter += |
176 | 55.3M | static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes |
177 | 55.3M | counter += static_cast<size_t>(word > 0x7FF); // three-byte |
178 | 55.3M | } |
179 | 7.18k | return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, |
180 | 7.18k | counter}; |
181 | 7.18k | } simdutf::result simdutf::scalar::utf16::utf8_length_from_utf16_with_replacement<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 153 | 3.59k | utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { | 154 | 3.59k | bool any_surrogates = false; | 155 | | // We are not BOM aware. | 156 | 3.59k | size_t counter{0}; | 157 | 30.3M | for (size_t i = 0; i < len; i++) { | 158 | 30.3M | if (is_high_surrogate<big_endian>(p[i])) { | 159 | 818k | any_surrogates = true; | 160 | | // surrogate pair | 161 | 818k | if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) { | 162 | 79.4k | counter += 4; | 163 | 79.4k | i++; // skip low surrogate | 164 | 739k | } else { | 165 | 739k | counter += 3; // unpaired high surrogate replaced by U+FFFD | 166 | 739k | } | 167 | 818k | continue; | 168 | 29.4M | } else if (is_low_surrogate<big_endian>(p[i])) { | 169 | 707k | any_surrogates = true; | 170 | 707k | counter += 3; // unpaired low surrogate replaced by U+FFFD | 171 | 707k | continue; | 172 | 707k | } | 173 | 28.7M | char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; | 174 | 28.7M | counter++; // at least 1 byte | 175 | 28.7M | counter += | 176 | 28.7M | static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes | 177 | 28.7M | counter += static_cast<size_t>(word > 0x7FF); // three-byte | 178 | 28.7M | } | 179 | 3.59k | return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, | 180 | 3.59k | counter}; | 181 | 3.59k | } |
simdutf::result simdutf::scalar::utf16::utf8_length_from_utf16_with_replacement<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 153 | 3.59k | utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) { | 154 | 3.59k | bool any_surrogates = false; | 155 | | // We are not BOM aware. | 156 | 3.59k | size_t counter{0}; | 157 | 28.7M | for (size_t i = 0; i < len; i++) { | 158 | 28.7M | if (is_high_surrogate<big_endian>(p[i])) { | 159 | 1.11M | any_surrogates = true; | 160 | | // surrogate pair | 161 | 1.11M | if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) { | 162 | 40.9k | counter += 4; | 163 | 40.9k | i++; // skip low surrogate | 164 | 1.07M | } else { | 165 | 1.07M | counter += 3; // unpaired high surrogate replaced by U+FFFD | 166 | 1.07M | } | 167 | 1.11M | continue; | 168 | 27.6M | } else if (is_low_surrogate<big_endian>(p[i])) { | 169 | 1.02M | any_surrogates = true; | 170 | 1.02M | counter += 3; // unpaired low surrogate replaced by U+FFFD | 171 | 1.02M | continue; | 172 | 1.02M | } | 173 | 26.5M | char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i]; | 174 | 26.5M | counter++; // at least 1 byte | 175 | 26.5M | counter += | 176 | 26.5M | static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes | 177 | 26.5M | counter += static_cast<size_t>(word > 0x7FF); // three-byte | 178 | 26.5M | } | 179 | 3.59k | return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS, | 180 | 3.59k | counter}; | 181 | 3.59k | } |
|
182 | | |
183 | | // variable templates are a C++14 extension |
184 | 0 | template <endianness big_endian> constexpr char16_t replacement() { |
185 | 0 | return !match_system(big_endian) ? scalar::u16_swap_bytes(0xfffd) : 0xfffd; |
186 | 0 | } Unexecuted instantiation: char16_t simdutf::scalar::utf16::replacement<(simdutf::endianness)0>() Unexecuted instantiation: char16_t simdutf::scalar::utf16::replacement<(simdutf::endianness)1>() |
187 | | |
188 | | template <endianness big_endian> |
189 | | simdutf_constexpr23 void to_well_formed_utf16(const char16_t *input, size_t len, |
190 | 1.84k | char16_t *output) { |
191 | 1.84k | const char16_t replacement = utf16::replacement<big_endian>(); |
192 | 1.84k | bool high_surrogate_prev = false, high_surrogate, low_surrogate; |
193 | 1.84k | size_t i = 0; |
194 | 17.9M | for (; i < len; i++) { |
195 | 17.9M | char16_t c = input[i]; |
196 | 17.9M | high_surrogate = is_high_surrogate<big_endian>(c); |
197 | 17.9M | low_surrogate = is_low_surrogate<big_endian>(c); |
198 | 17.9M | if (high_surrogate_prev && !low_surrogate) { |
199 | 82.5k | output[i - 1] = replacement; |
200 | 82.5k | } |
201 | | |
202 | 17.9M | if (!high_surrogate_prev && low_surrogate) { |
203 | 1.44M | output[i] = replacement; |
204 | 16.5M | } else { |
205 | 16.5M | output[i] = input[i]; |
206 | 16.5M | } |
207 | 17.9M | high_surrogate_prev = high_surrogate; |
208 | 17.9M | } |
209 | | |
210 | | /* string may not end with high surrogate */ |
211 | 1.84k | if (high_surrogate_prev) { |
212 | 223 | output[i - 1] = replacement; |
213 | 223 | } |
214 | 1.84k | } void simdutf::scalar::utf16::to_well_formed_utf16<(simdutf::endianness)0>(char16_t const*, unsigned long, char16_t*) Line | Count | Source | 190 | 922 | char16_t *output) { | 191 | 922 | const char16_t replacement = utf16::replacement<big_endian>(); | 192 | 922 | bool high_surrogate_prev = false, high_surrogate, low_surrogate; | 193 | 922 | size_t i = 0; | 194 | 8.98M | for (; i < len; i++) { | 195 | 8.97M | char16_t c = input[i]; | 196 | 8.97M | high_surrogate = is_high_surrogate<big_endian>(c); | 197 | 8.97M | low_surrogate = is_low_surrogate<big_endian>(c); | 198 | 8.97M | if (high_surrogate_prev && !low_surrogate) { | 199 | 41.2k | output[i - 1] = replacement; | 200 | 41.2k | } | 201 | | | 202 | 8.97M | if (!high_surrogate_prev && low_surrogate) { | 203 | 723k | output[i] = replacement; | 204 | 8.25M | } else { | 205 | 8.25M | output[i] = input[i]; | 206 | 8.25M | } | 207 | 8.97M | high_surrogate_prev = high_surrogate; | 208 | 8.97M | } | 209 | | | 210 | | /* string may not end with high surrogate */ | 211 | 922 | if (high_surrogate_prev) { | 212 | 109 | output[i - 1] = replacement; | 213 | 109 | } | 214 | 922 | } |
void simdutf::scalar::utf16::to_well_formed_utf16<(simdutf::endianness)1>(char16_t const*, unsigned long, char16_t*) Line | Count | Source | 190 | 922 | char16_t *output) { | 191 | 922 | const char16_t replacement = utf16::replacement<big_endian>(); | 192 | 922 | bool high_surrogate_prev = false, high_surrogate, low_surrogate; | 193 | 922 | size_t i = 0; | 194 | 8.98M | for (; i < len; i++) { | 195 | 8.97M | char16_t c = input[i]; | 196 | 8.97M | high_surrogate = is_high_surrogate<big_endian>(c); | 197 | 8.97M | low_surrogate = is_low_surrogate<big_endian>(c); | 198 | 8.97M | if (high_surrogate_prev && !low_surrogate) { | 199 | 41.2k | output[i - 1] = replacement; | 200 | 41.2k | } | 201 | | | 202 | 8.97M | if (!high_surrogate_prev && low_surrogate) { | 203 | 723k | output[i] = replacement; | 204 | 8.25M | } else { | 205 | 8.25M | output[i] = input[i]; | 206 | 8.25M | } | 207 | 8.97M | high_surrogate_prev = high_surrogate; | 208 | 8.97M | } | 209 | | | 210 | | /* string may not end with high surrogate */ | 211 | 922 | if (high_surrogate_prev) { | 212 | 114 | output[i - 1] = replacement; | 213 | 114 | } | 214 | 922 | } |
|
215 | | |
216 | | } // namespace utf16 |
217 | | } // namespace scalar |
218 | | } // namespace simdutf |
219 | | |
220 | | #endif |