Coverage Report

Created: 2026-08-31 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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