/src/simdutf/src/generic/validate_utf16.h
Line | Count | Source |
1 | | namespace simdutf { |
2 | | namespace SIMDUTF_IMPLEMENTATION { |
3 | | namespace { |
4 | | namespace utf16 { |
5 | | /* |
6 | | UTF-16 validation |
7 | | -------------------------------------------------- |
8 | | |
9 | | In UTF-16 code units in range 0xD800 to 0xDFFF have special meaning. |
10 | | |
11 | | In a vectorized algorithm we want to examine the most significant |
12 | | nibble in order to select a fast path. If none of highest nibbles |
13 | | are 0xD (13), than we are sure that UTF-16 chunk in a vector |
14 | | register is valid. |
15 | | |
16 | | Let us analyze what we need to check if the nibble is 0xD. The |
17 | | value of the preceding nibble determines what we have: |
18 | | |
19 | | 0xd000 .. 0xd7ff - a valid word |
20 | | 0xd800 .. 0xdbff - low surrogate |
21 | | 0xdc00 .. 0xdfff - high surrogate |
22 | | |
23 | | Other constraints we have to consider: |
24 | | - there must not be two consecutive low surrogates (0xd800 .. 0xdbff) |
25 | | - there must not be two consecutive high surrogates (0xdc00 .. 0xdfff) |
26 | | - there must not be sole low surrogate nor high surrogate |
27 | | |
28 | | We are going to build three bitmasks based on the 3rd nibble: |
29 | | - V = valid word, |
30 | | - L = low surrogate (0xd800 .. 0xdbff) |
31 | | - H = high surrogate (0xdc00 .. 0xdfff) |
32 | | |
33 | | 0 1 2 3 4 5 6 7 <--- word index |
34 | | [ V | L | H | L | H | V | V | L ] |
35 | | 1 0 0 0 0 1 1 0 - V = valid masks |
36 | | 0 1 0 1 0 0 0 1 - L = low surrogate |
37 | | 0 0 1 0 1 0 0 0 - H high surrogate |
38 | | |
39 | | |
40 | | 1 0 0 0 0 1 1 0 V = valid masks |
41 | | 0 1 0 1 0 0 0 0 a = L & (H >> 1) |
42 | | 0 0 1 0 1 0 0 0 b = a << 1 |
43 | | 1 1 1 1 1 1 1 0 c = V | a | b |
44 | | ^ |
45 | | the last bit can be zero, we just consume 7 |
46 | | code units and recheck this word in the next iteration |
47 | | */ |
48 | | template <endianness big_endian> |
49 | 4.65k | const result validate_utf16_with_errors(const char16_t *input, size_t size) { |
50 | 4.65k | if (simdutf_unlikely(size == 0)) { |
51 | 0 | return result(error_code::SUCCESS, 0); |
52 | 0 | } |
53 | | |
54 | 4.65k | const char16_t *start = input; |
55 | 4.65k | const char16_t *end = input + size; |
56 | | |
57 | 4.65k | const auto v_d8 = simd8<uint8_t>::splat(0xd8); |
58 | 4.65k | const auto v_f8 = simd8<uint8_t>::splat(0xf8); |
59 | 4.65k | const auto v_fc = simd8<uint8_t>::splat(0xfc); |
60 | 4.65k | const auto v_dc = simd8<uint8_t>::splat(0xdc); |
61 | | |
62 | 2.35M | while (input + simd16<uint16_t>::SIZE * 2 < end) { |
63 | | // 0. Load data: since the validation takes into account only higher |
64 | | // byte of each word, we compress the two vectors into one which |
65 | | // consists only the higher bytes. |
66 | 2.34M | auto in0 = simd16<uint16_t>(input); |
67 | 2.34M | auto in1 = |
68 | 2.34M | simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t)); |
69 | | |
70 | | // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16 |
71 | | // and yields a single vector having only higher bytes of characters. |
72 | 2.34M | const auto in = utf16_gather_high_bytes<big_endian>(in0, in1); |
73 | | |
74 | | // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy). |
75 | 2.34M | const auto surrogates_wordmask = (in & v_f8) == v_d8; |
76 | 2.34M | const uint16_t surrogates_bitmask = |
77 | 2.34M | static_cast<uint16_t>(surrogates_wordmask.to_bitmask()); |
78 | 2.34M | if (surrogates_bitmask == 0x0000) { |
79 | 2.29M | input += 16; |
80 | 2.29M | } else { |
81 | | // 2. We have some surrogates that have to be distinguished: |
82 | | // - low surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF) |
83 | | // - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF) |
84 | | // |
85 | | // Fact: high surrogate has 11th bit set (3rd bit in the higher byte) |
86 | | |
87 | | // V - non-surrogate code units |
88 | | // V = not surrogates_wordmask |
89 | 50.0k | const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask); |
90 | | |
91 | | // H - word-mask for high surrogates: the six highest bits are 0b1101'11 |
92 | 50.0k | const auto vH = (in & v_fc) == v_dc; |
93 | 50.0k | const uint16_t H = static_cast<uint16_t>(vH.to_bitmask()); |
94 | | |
95 | | // L - word mask for low surrogates |
96 | | // L = not H and surrogates_wordmask |
97 | 50.0k | const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask); |
98 | | |
99 | 50.0k | const uint16_t a = static_cast<uint16_t>( |
100 | 50.0k | L & (H >> 1)); // A low surrogate must be followed by high one. |
101 | | // (A low surrogate placed in the 7th register's word |
102 | | // is an exception we handle.) |
103 | 50.0k | const uint16_t b = static_cast<uint16_t>( |
104 | 50.0k | a << 1); // Just mark that the opinput - startite fact is hold, |
105 | | // thanks to that we have only two masks for valid case. |
106 | 50.0k | const uint16_t c = static_cast<uint16_t>( |
107 | 50.0k | V | a | b); // Combine all the masks into the final one. |
108 | | |
109 | 50.0k | if (c == 0xffff) { |
110 | | // The whole input register contains valid UTF-16, i.e., |
111 | | // either single code units or proper surrogate pairs. |
112 | 42.7k | input += 16; |
113 | 42.7k | } else if (c == 0x7fff) { |
114 | | // The 15 lower code units of the input register contains valid UTF-16. |
115 | | // The 15th word may be either a low or high surrogate. It the next |
116 | | // iteration we 1) check if the low surrogate is followed by a high |
117 | | // one, 2) reject sole high surrogate. |
118 | 6.77k | input += 15; |
119 | 6.77k | } else { |
120 | 528 | return result(error_code::SURROGATE, input - start); |
121 | 528 | } |
122 | 50.0k | } |
123 | 2.34M | } |
124 | | |
125 | 4.12k | return result(error_code::SUCCESS, input - start); |
126 | 4.65k | } simdutf.cpp:simdutf::result const simdutf::haswell::(anonymous namespace)::utf16::validate_utf16_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 49 | 1.67k | const result validate_utf16_with_errors(const char16_t *input, size_t size) { | 50 | 1.67k | if (simdutf_unlikely(size == 0)) { | 51 | 0 | return result(error_code::SUCCESS, 0); | 52 | 0 | } | 53 | | | 54 | 1.67k | const char16_t *start = input; | 55 | 1.67k | const char16_t *end = input + size; | 56 | | | 57 | 1.67k | const auto v_d8 = simd8<uint8_t>::splat(0xd8); | 58 | 1.67k | const auto v_f8 = simd8<uint8_t>::splat(0xf8); | 59 | 1.67k | const auto v_fc = simd8<uint8_t>::splat(0xfc); | 60 | 1.67k | const auto v_dc = simd8<uint8_t>::splat(0xdc); | 61 | | | 62 | 727k | while (input + simd16<uint16_t>::SIZE * 2 < end) { | 63 | | // 0. Load data: since the validation takes into account only higher | 64 | | // byte of each word, we compress the two vectors into one which | 65 | | // consists only the higher bytes. | 66 | 726k | auto in0 = simd16<uint16_t>(input); | 67 | 726k | auto in1 = | 68 | 726k | simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t)); | 69 | | | 70 | | // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16 | 71 | | // and yields a single vector having only higher bytes of characters. | 72 | 726k | const auto in = utf16_gather_high_bytes<big_endian>(in0, in1); | 73 | | | 74 | | // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy). | 75 | 726k | const auto surrogates_wordmask = (in & v_f8) == v_d8; | 76 | 726k | const uint16_t surrogates_bitmask = | 77 | 726k | static_cast<uint16_t>(surrogates_wordmask.to_bitmask()); | 78 | 726k | if (surrogates_bitmask == 0x0000) { | 79 | 713k | input += 16; | 80 | 713k | } else { | 81 | | // 2. We have some surrogates that have to be distinguished: | 82 | | // - low surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF) | 83 | | // - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF) | 84 | | // | 85 | | // Fact: high surrogate has 11th bit set (3rd bit in the higher byte) | 86 | | | 87 | | // V - non-surrogate code units | 88 | | // V = not surrogates_wordmask | 89 | 12.6k | const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask); | 90 | | | 91 | | // H - word-mask for high surrogates: the six highest bits are 0b1101'11 | 92 | 12.6k | const auto vH = (in & v_fc) == v_dc; | 93 | 12.6k | const uint16_t H = static_cast<uint16_t>(vH.to_bitmask()); | 94 | | | 95 | | // L - word mask for low surrogates | 96 | | // L = not H and surrogates_wordmask | 97 | 12.6k | const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask); | 98 | | | 99 | 12.6k | const uint16_t a = static_cast<uint16_t>( | 100 | 12.6k | L & (H >> 1)); // A low surrogate must be followed by high one. | 101 | | // (A low surrogate placed in the 7th register's word | 102 | | // is an exception we handle.) | 103 | 12.6k | const uint16_t b = static_cast<uint16_t>( | 104 | 12.6k | a << 1); // Just mark that the opinput - startite fact is hold, | 105 | | // thanks to that we have only two masks for valid case. | 106 | 12.6k | const uint16_t c = static_cast<uint16_t>( | 107 | 12.6k | V | a | b); // Combine all the masks into the final one. | 108 | | | 109 | 12.6k | if (c == 0xffff) { | 110 | | // The whole input register contains valid UTF-16, i.e., | 111 | | // either single code units or proper surrogate pairs. | 112 | 10.7k | input += 16; | 113 | 10.7k | } else if (c == 0x7fff) { | 114 | | // The 15 lower code units of the input register contains valid UTF-16. | 115 | | // The 15th word may be either a low or high surrogate. It the next | 116 | | // iteration we 1) check if the low surrogate is followed by a high | 117 | | // one, 2) reject sole high surrogate. | 118 | 1.65k | input += 15; | 119 | 1.65k | } else { | 120 | 250 | return result(error_code::SURROGATE, input - start); | 121 | 250 | } | 122 | 12.6k | } | 123 | 726k | } | 124 | | | 125 | 1.42k | return result(error_code::SUCCESS, input - start); | 126 | 1.67k | } |
simdutf.cpp:simdutf::result const simdutf::haswell::(anonymous namespace)::utf16::validate_utf16_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 49 | 1.28k | const result validate_utf16_with_errors(const char16_t *input, size_t size) { | 50 | 1.28k | if (simdutf_unlikely(size == 0)) { | 51 | 0 | return result(error_code::SUCCESS, 0); | 52 | 0 | } | 53 | | | 54 | 1.28k | const char16_t *start = input; | 55 | 1.28k | const char16_t *end = input + size; | 56 | | | 57 | 1.28k | const auto v_d8 = simd8<uint8_t>::splat(0xd8); | 58 | 1.28k | const auto v_f8 = simd8<uint8_t>::splat(0xf8); | 59 | 1.28k | const auto v_fc = simd8<uint8_t>::splat(0xfc); | 60 | 1.28k | const auto v_dc = simd8<uint8_t>::splat(0xdc); | 61 | | | 62 | 522k | while (input + simd16<uint16_t>::SIZE * 2 < end) { | 63 | | // 0. Load data: since the validation takes into account only higher | 64 | | // byte of each word, we compress the two vectors into one which | 65 | | // consists only the higher bytes. | 66 | 521k | auto in0 = simd16<uint16_t>(input); | 67 | 521k | auto in1 = | 68 | 521k | simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t)); | 69 | | | 70 | | // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16 | 71 | | // and yields a single vector having only higher bytes of characters. | 72 | 521k | const auto in = utf16_gather_high_bytes<big_endian>(in0, in1); | 73 | | | 74 | | // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy). | 75 | 521k | const auto surrogates_wordmask = (in & v_f8) == v_d8; | 76 | 521k | const uint16_t surrogates_bitmask = | 77 | 521k | static_cast<uint16_t>(surrogates_wordmask.to_bitmask()); | 78 | 521k | if (surrogates_bitmask == 0x0000) { | 79 | 508k | input += 16; | 80 | 508k | } else { | 81 | | // 2. We have some surrogates that have to be distinguished: | 82 | | // - low surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF) | 83 | | // - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF) | 84 | | // | 85 | | // Fact: high surrogate has 11th bit set (3rd bit in the higher byte) | 86 | | | 87 | | // V - non-surrogate code units | 88 | | // V = not surrogates_wordmask | 89 | 12.8k | const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask); | 90 | | | 91 | | // H - word-mask for high surrogates: the six highest bits are 0b1101'11 | 92 | 12.8k | const auto vH = (in & v_fc) == v_dc; | 93 | 12.8k | const uint16_t H = static_cast<uint16_t>(vH.to_bitmask()); | 94 | | | 95 | | // L - word mask for low surrogates | 96 | | // L = not H and surrogates_wordmask | 97 | 12.8k | const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask); | 98 | | | 99 | 12.8k | const uint16_t a = static_cast<uint16_t>( | 100 | 12.8k | L & (H >> 1)); // A low surrogate must be followed by high one. | 101 | | // (A low surrogate placed in the 7th register's word | 102 | | // is an exception we handle.) | 103 | 12.8k | const uint16_t b = static_cast<uint16_t>( | 104 | 12.8k | a << 1); // Just mark that the opinput - startite fact is hold, | 105 | | // thanks to that we have only two masks for valid case. | 106 | 12.8k | const uint16_t c = static_cast<uint16_t>( | 107 | 12.8k | V | a | b); // Combine all the masks into the final one. | 108 | | | 109 | 12.8k | if (c == 0xffff) { | 110 | | // The whole input register contains valid UTF-16, i.e., | 111 | | // either single code units or proper surrogate pairs. | 112 | 10.7k | input += 16; | 113 | 10.7k | } else if (c == 0x7fff) { | 114 | | // The 15 lower code units of the input register contains valid UTF-16. | 115 | | // The 15th word may be either a low or high surrogate. It the next | 116 | | // iteration we 1) check if the low surrogate is followed by a high | 117 | | // one, 2) reject sole high surrogate. | 118 | 1.85k | input += 15; | 119 | 1.85k | } else { | 120 | 187 | return result(error_code::SURROGATE, input - start); | 121 | 187 | } | 122 | 12.8k | } | 123 | 521k | } | 124 | | | 125 | 1.09k | return result(error_code::SUCCESS, input - start); | 126 | 1.28k | } |
simdutf.cpp:simdutf::result const simdutf::westmere::(anonymous namespace)::utf16::validate_utf16_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 49 | 1.04k | const result validate_utf16_with_errors(const char16_t *input, size_t size) { | 50 | 1.04k | if (simdutf_unlikely(size == 0)) { | 51 | 0 | return result(error_code::SUCCESS, 0); | 52 | 0 | } | 53 | | | 54 | 1.04k | const char16_t *start = input; | 55 | 1.04k | const char16_t *end = input + size; | 56 | | | 57 | 1.04k | const auto v_d8 = simd8<uint8_t>::splat(0xd8); | 58 | 1.04k | const auto v_f8 = simd8<uint8_t>::splat(0xf8); | 59 | 1.04k | const auto v_fc = simd8<uint8_t>::splat(0xfc); | 60 | 1.04k | const auto v_dc = simd8<uint8_t>::splat(0xdc); | 61 | | | 62 | 654k | while (input + simd16<uint16_t>::SIZE * 2 < end) { | 63 | | // 0. Load data: since the validation takes into account only higher | 64 | | // byte of each word, we compress the two vectors into one which | 65 | | // consists only the higher bytes. | 66 | 653k | auto in0 = simd16<uint16_t>(input); | 67 | 653k | auto in1 = | 68 | 653k | simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t)); | 69 | | | 70 | | // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16 | 71 | | // and yields a single vector having only higher bytes of characters. | 72 | 653k | const auto in = utf16_gather_high_bytes<big_endian>(in0, in1); | 73 | | | 74 | | // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy). | 75 | 653k | const auto surrogates_wordmask = (in & v_f8) == v_d8; | 76 | 653k | const uint16_t surrogates_bitmask = | 77 | 653k | static_cast<uint16_t>(surrogates_wordmask.to_bitmask()); | 78 | 653k | if (surrogates_bitmask == 0x0000) { | 79 | 640k | input += 16; | 80 | 640k | } else { | 81 | | // 2. We have some surrogates that have to be distinguished: | 82 | | // - low surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF) | 83 | | // - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF) | 84 | | // | 85 | | // Fact: high surrogate has 11th bit set (3rd bit in the higher byte) | 86 | | | 87 | | // V - non-surrogate code units | 88 | | // V = not surrogates_wordmask | 89 | 12.2k | const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask); | 90 | | | 91 | | // H - word-mask for high surrogates: the six highest bits are 0b1101'11 | 92 | 12.2k | const auto vH = (in & v_fc) == v_dc; | 93 | 12.2k | const uint16_t H = static_cast<uint16_t>(vH.to_bitmask()); | 94 | | | 95 | | // L - word mask for low surrogates | 96 | | // L = not H and surrogates_wordmask | 97 | 12.2k | const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask); | 98 | | | 99 | 12.2k | const uint16_t a = static_cast<uint16_t>( | 100 | 12.2k | L & (H >> 1)); // A low surrogate must be followed by high one. | 101 | | // (A low surrogate placed in the 7th register's word | 102 | | // is an exception we handle.) | 103 | 12.2k | const uint16_t b = static_cast<uint16_t>( | 104 | 12.2k | a << 1); // Just mark that the opinput - startite fact is hold, | 105 | | // thanks to that we have only two masks for valid case. | 106 | 12.2k | const uint16_t c = static_cast<uint16_t>( | 107 | 12.2k | V | a | b); // Combine all the masks into the final one. | 108 | | | 109 | 12.2k | if (c == 0xffff) { | 110 | | // The whole input register contains valid UTF-16, i.e., | 111 | | // either single code units or proper surrogate pairs. | 112 | 10.5k | input += 16; | 113 | 10.5k | } else if (c == 0x7fff) { | 114 | | // The 15 lower code units of the input register contains valid UTF-16. | 115 | | // The 15th word may be either a low or high surrogate. It the next | 116 | | // iteration we 1) check if the low surrogate is followed by a high | 117 | | // one, 2) reject sole high surrogate. | 118 | 1.55k | input += 15; | 119 | 1.55k | } else { | 120 | 91 | return result(error_code::SURROGATE, input - start); | 121 | 91 | } | 122 | 12.2k | } | 123 | 653k | } | 124 | | | 125 | 951 | return result(error_code::SUCCESS, input - start); | 126 | 1.04k | } |
simdutf.cpp:simdutf::result const simdutf::westmere::(anonymous namespace)::utf16::validate_utf16_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 49 | 653 | const result validate_utf16_with_errors(const char16_t *input, size_t size) { | 50 | 653 | if (simdutf_unlikely(size == 0)) { | 51 | 0 | return result(error_code::SUCCESS, 0); | 52 | 0 | } | 53 | | | 54 | 653 | const char16_t *start = input; | 55 | 653 | const char16_t *end = input + size; | 56 | | | 57 | 653 | const auto v_d8 = simd8<uint8_t>::splat(0xd8); | 58 | 653 | const auto v_f8 = simd8<uint8_t>::splat(0xf8); | 59 | 653 | const auto v_fc = simd8<uint8_t>::splat(0xfc); | 60 | 653 | const auto v_dc = simd8<uint8_t>::splat(0xdc); | 61 | | | 62 | 447k | while (input + simd16<uint16_t>::SIZE * 2 < end) { | 63 | | // 0. Load data: since the validation takes into account only higher | 64 | | // byte of each word, we compress the two vectors into one which | 65 | | // consists only the higher bytes. | 66 | 446k | auto in0 = simd16<uint16_t>(input); | 67 | 446k | auto in1 = | 68 | 446k | simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t)); | 69 | | | 70 | | // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16 | 71 | | // and yields a single vector having only higher bytes of characters. | 72 | 446k | const auto in = utf16_gather_high_bytes<big_endian>(in0, in1); | 73 | | | 74 | | // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy). | 75 | 446k | const auto surrogates_wordmask = (in & v_f8) == v_d8; | 76 | 446k | const uint16_t surrogates_bitmask = | 77 | 446k | static_cast<uint16_t>(surrogates_wordmask.to_bitmask()); | 78 | 446k | if (surrogates_bitmask == 0x0000) { | 79 | 434k | input += 16; | 80 | 434k | } else { | 81 | | // 2. We have some surrogates that have to be distinguished: | 82 | | // - low surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF) | 83 | | // - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF) | 84 | | // | 85 | | // Fact: high surrogate has 11th bit set (3rd bit in the higher byte) | 86 | | | 87 | | // V - non-surrogate code units | 88 | | // V = not surrogates_wordmask | 89 | 12.3k | const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask); | 90 | | | 91 | | // H - word-mask for high surrogates: the six highest bits are 0b1101'11 | 92 | 12.3k | const auto vH = (in & v_fc) == v_dc; | 93 | 12.3k | const uint16_t H = static_cast<uint16_t>(vH.to_bitmask()); | 94 | | | 95 | | // L - word mask for low surrogates | 96 | | // L = not H and surrogates_wordmask | 97 | 12.3k | const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask); | 98 | | | 99 | 12.3k | const uint16_t a = static_cast<uint16_t>( | 100 | 12.3k | L & (H >> 1)); // A low surrogate must be followed by high one. | 101 | | // (A low surrogate placed in the 7th register's word | 102 | | // is an exception we handle.) | 103 | 12.3k | const uint16_t b = static_cast<uint16_t>( | 104 | 12.3k | a << 1); // Just mark that the opinput - startite fact is hold, | 105 | | // thanks to that we have only two masks for valid case. | 106 | 12.3k | const uint16_t c = static_cast<uint16_t>( | 107 | 12.3k | V | a | b); // Combine all the masks into the final one. | 108 | | | 109 | 12.3k | if (c == 0xffff) { | 110 | | // The whole input register contains valid UTF-16, i.e., | 111 | | // either single code units or proper surrogate pairs. | 112 | 10.6k | input += 16; | 113 | 10.6k | } else if (c == 0x7fff) { | 114 | | // The 15 lower code units of the input register contains valid UTF-16. | 115 | | // The 15th word may be either a low or high surrogate. It the next | 116 | | // iteration we 1) check if the low surrogate is followed by a high | 117 | | // one, 2) reject sole high surrogate. | 118 | 1.71k | input += 15; | 119 | 1.71k | } else { | 120 | 0 | return result(error_code::SURROGATE, input - start); | 121 | 0 | } | 122 | 12.3k | } | 123 | 446k | } | 124 | | | 125 | 653 | return result(error_code::SUCCESS, input - start); | 126 | 653 | } |
|
127 | | |
128 | | template <endianness big_endian> |
129 | | const result validate_utf16_as_ascii_with_errors(const char16_t *input, |
130 | 928 | size_t size) { |
131 | 928 | if (simdutf_unlikely(size == 0)) { |
132 | 4 | return result(error_code::SUCCESS, 0); |
133 | 4 | } |
134 | 924 | size_t pos = 0; |
135 | 2.14k | for (; pos < size / 32 * 32; pos += 32) { |
136 | 1.93k | simd16x32<uint16_t> input_vec( |
137 | 1.93k | reinterpret_cast<const uint16_t *>(input + pos)); |
138 | 1.93k | if constexpr (!match_system(big_endian)) { |
139 | 966 | input_vec.swap_bytes(); |
140 | 966 | } |
141 | 1.93k | uint64_t matches = input_vec.lteq(uint16_t(0x7f)); |
142 | 1.93k | if (~matches) { |
143 | | // Found a match, return the first one |
144 | 712 | int index = trailing_zeroes(~matches) / 2; |
145 | 712 | return result(error_code::TOO_LARGE, pos + index); |
146 | 712 | } |
147 | 1.93k | } |
148 | | |
149 | | // Scalar tail |
150 | 596 | while (pos < size) { |
151 | | |
152 | 510 | char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]); |
153 | 510 | if (v > 0x7F) { |
154 | 126 | return result(error_code::TOO_LARGE, pos); |
155 | 126 | } |
156 | 384 | pos++; |
157 | 384 | } |
158 | 86 | return result(error_code::SUCCESS, size); |
159 | 212 | } simdutf.cpp:simdutf::result const simdutf::haswell::(anonymous namespace)::utf16::validate_utf16_as_ascii_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 130 | 232 | size_t size) { | 131 | 232 | if (simdutf_unlikely(size == 0)) { | 132 | 1 | return result(error_code::SUCCESS, 0); | 133 | 1 | } | 134 | 231 | size_t pos = 0; | 135 | 537 | for (; pos < size / 32 * 32; pos += 32) { | 136 | 483 | simd16x32<uint16_t> input_vec( | 137 | 483 | reinterpret_cast<const uint16_t *>(input + pos)); | 138 | | if constexpr (!match_system(big_endian)) { | 139 | | input_vec.swap_bytes(); | 140 | | } | 141 | 483 | uint64_t matches = input_vec.lteq(uint16_t(0x7f)); | 142 | 483 | if (~matches) { | 143 | | // Found a match, return the first one | 144 | 177 | int index = trailing_zeroes(~matches) / 2; | 145 | 177 | return result(error_code::TOO_LARGE, pos + index); | 146 | 177 | } | 147 | 483 | } | 148 | | | 149 | | // Scalar tail | 150 | 143 | while (pos < size) { | 151 | | | 152 | 121 | char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]); | 153 | 121 | if (v > 0x7F) { | 154 | 32 | return result(error_code::TOO_LARGE, pos); | 155 | 32 | } | 156 | 89 | pos++; | 157 | 89 | } | 158 | 22 | return result(error_code::SUCCESS, size); | 159 | 54 | } |
simdutf.cpp:simdutf::result const simdutf::haswell::(anonymous namespace)::utf16::validate_utf16_as_ascii_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 130 | 232 | size_t size) { | 131 | 232 | if (simdutf_unlikely(size == 0)) { | 132 | 1 | return result(error_code::SUCCESS, 0); | 133 | 1 | } | 134 | 231 | size_t pos = 0; | 135 | 535 | for (; pos < size / 32 * 32; pos += 32) { | 136 | 483 | simd16x32<uint16_t> input_vec( | 137 | 483 | reinterpret_cast<const uint16_t *>(input + pos)); | 138 | 483 | if constexpr (!match_system(big_endian)) { | 139 | 483 | input_vec.swap_bytes(); | 140 | 483 | } | 141 | 483 | uint64_t matches = input_vec.lteq(uint16_t(0x7f)); | 142 | 483 | if (~matches) { | 143 | | // Found a match, return the first one | 144 | 179 | int index = trailing_zeroes(~matches) / 2; | 145 | 179 | return result(error_code::TOO_LARGE, pos + index); | 146 | 179 | } | 147 | 483 | } | 148 | | | 149 | | // Scalar tail | 150 | 155 | while (pos < size) { | 151 | | | 152 | 134 | char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]); | 153 | 134 | if (v > 0x7F) { | 154 | 31 | return result(error_code::TOO_LARGE, pos); | 155 | 31 | } | 156 | 103 | pos++; | 157 | 103 | } | 158 | 21 | return result(error_code::SUCCESS, size); | 159 | 52 | } |
simdutf.cpp:simdutf::result const simdutf::westmere::(anonymous namespace)::utf16::validate_utf16_as_ascii_with_errors<(simdutf::endianness)0>(char16_t const*, unsigned long) Line | Count | Source | 130 | 232 | size_t size) { | 131 | 232 | if (simdutf_unlikely(size == 0)) { | 132 | 1 | return result(error_code::SUCCESS, 0); | 133 | 1 | } | 134 | 231 | size_t pos = 0; | 135 | 537 | for (; pos < size / 32 * 32; pos += 32) { | 136 | 483 | simd16x32<uint16_t> input_vec( | 137 | 483 | reinterpret_cast<const uint16_t *>(input + pos)); | 138 | | if constexpr (!match_system(big_endian)) { | 139 | | input_vec.swap_bytes(); | 140 | | } | 141 | 483 | uint64_t matches = input_vec.lteq(uint16_t(0x7f)); | 142 | 483 | if (~matches) { | 143 | | // Found a match, return the first one | 144 | 177 | int index = trailing_zeroes(~matches) / 2; | 145 | 177 | return result(error_code::TOO_LARGE, pos + index); | 146 | 177 | } | 147 | 483 | } | 148 | | | 149 | | // Scalar tail | 150 | 143 | while (pos < size) { | 151 | | | 152 | 121 | char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]); | 153 | 121 | if (v > 0x7F) { | 154 | 32 | return result(error_code::TOO_LARGE, pos); | 155 | 32 | } | 156 | 89 | pos++; | 157 | 89 | } | 158 | 22 | return result(error_code::SUCCESS, size); | 159 | 54 | } |
simdutf.cpp:simdutf::result const simdutf::westmere::(anonymous namespace)::utf16::validate_utf16_as_ascii_with_errors<(simdutf::endianness)1>(char16_t const*, unsigned long) Line | Count | Source | 130 | 232 | size_t size) { | 131 | 232 | if (simdutf_unlikely(size == 0)) { | 132 | 1 | return result(error_code::SUCCESS, 0); | 133 | 1 | } | 134 | 231 | size_t pos = 0; | 135 | 535 | for (; pos < size / 32 * 32; pos += 32) { | 136 | 483 | simd16x32<uint16_t> input_vec( | 137 | 483 | reinterpret_cast<const uint16_t *>(input + pos)); | 138 | 483 | if constexpr (!match_system(big_endian)) { | 139 | 483 | input_vec.swap_bytes(); | 140 | 483 | } | 141 | 483 | uint64_t matches = input_vec.lteq(uint16_t(0x7f)); | 142 | 483 | if (~matches) { | 143 | | // Found a match, return the first one | 144 | 179 | int index = trailing_zeroes(~matches) / 2; | 145 | 179 | return result(error_code::TOO_LARGE, pos + index); | 146 | 179 | } | 147 | 483 | } | 148 | | | 149 | | // Scalar tail | 150 | 155 | while (pos < size) { | 151 | | | 152 | 134 | char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]); | 153 | 134 | if (v > 0x7F) { | 154 | 31 | return result(error_code::TOO_LARGE, pos); | 155 | 31 | } | 156 | 103 | pos++; | 157 | 103 | } | 158 | 21 | return result(error_code::SUCCESS, size); | 159 | 52 | } |
|
160 | | |
161 | | } // namespace utf16 |
162 | | } // unnamed namespace |
163 | | } // namespace SIMDUTF_IMPLEMENTATION |
164 | | } // namespace simdutf |