Coverage Report

Created: 2026-10-17 07:16

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