google-protobuf 4.29.3-x86_64-darwin → 4.30.0.rc.1-x86_64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/google/protobuf_c/convert.c +3 -10
- data/ext/google/protobuf_c/defs.c +161 -2
- data/ext/google/protobuf_c/extconf.rb +12 -0
- data/ext/google/protobuf_c/glue.c +63 -0
- data/ext/google/protobuf_c/message.c +2 -4
- data/ext/google/protobuf_c/protobuf.c +2 -1
- data/ext/google/protobuf_c/ruby-upb.c +7728 -6620
- data/ext/google/protobuf_c/ruby-upb.h +2391 -1671
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range.c +15 -275
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_neon.inc +117 -0
- data/ext/google/protobuf_c/third_party/utf8_range/utf8_range_sse.inc +272 -0
- data/lib/google/3.0/protobuf_c.bundle +0 -0
- data/lib/google/3.1/protobuf_c.bundle +0 -0
- data/lib/google/3.2/protobuf_c.bundle +0 -0
- data/lib/google/3.3/protobuf_c.bundle +0 -0
- data/lib/google/3.4/protobuf_c.bundle +0 -0
- data/lib/google/protobuf/descriptor_pb.rb +2 -1
- data/lib/google/protobuf/ffi/descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/enum_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/ffi.rb +0 -1
- data/lib/google/protobuf/ffi/field_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/file_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/internal/convert.rb +1 -5
- data/lib/google/protobuf/ffi/message.rb +1 -3
- data/lib/google/protobuf/ffi/method_descriptor.rb +11 -1
- data/lib/google/protobuf/ffi/oneof_descriptor.rb +10 -0
- data/lib/google/protobuf/ffi/service_descriptor.rb +11 -1
- data/lib/google/protobuf_ffi.rb +2 -1
- metadata +5 -3
@@ -21,12 +21,6 @@
|
|
21
21
|
#include <stdint.h>
|
22
22
|
#include <string.h>
|
23
23
|
|
24
|
-
#ifdef __SSE4_1__
|
25
|
-
#include <emmintrin.h>
|
26
|
-
#include <smmintrin.h>
|
27
|
-
#include <tmmintrin.h>
|
28
|
-
#endif
|
29
|
-
|
30
24
|
#if defined(__GNUC__)
|
31
25
|
#define FORCE_INLINE_ATTR __attribute__((always_inline))
|
32
26
|
#elif defined(_MSC_VER)
|
@@ -143,7 +137,7 @@ static size_t utf8_range_ValidateUTF8Naive(const char* data, const char* end,
|
|
143
137
|
return err_pos + (1 - return_position);
|
144
138
|
}
|
145
139
|
|
146
|
-
#
|
140
|
+
#if defined(__SSE4_1__) || (defined(__ARM_NEON) && defined(__ARM_64BIT_STATE))
|
147
141
|
/* Returns the number of bytes needed to skip backwards to get to the first
|
148
142
|
byte of codepoint.
|
149
143
|
*/
|
@@ -175,286 +169,32 @@ static inline const char* utf8_range_SkipAscii(const char* data,
|
|
175
169
|
return data;
|
176
170
|
}
|
177
171
|
|
172
|
+
#if defined(__SSE4_1__)
|
173
|
+
#include "utf8_range_sse.inc"
|
174
|
+
#elif defined(__ARM_NEON) && defined(__ARM_64BIT_STATE)
|
175
|
+
#include "utf8_range_neon.inc"
|
176
|
+
#endif
|
177
|
+
|
178
178
|
static FORCE_INLINE_ATTR inline size_t utf8_range_Validate(
|
179
179
|
const char* data, size_t len, int return_position) {
|
180
180
|
if (len == 0) return 1 - return_position;
|
181
|
+
// Save buffer start address for later use
|
182
|
+
const char* const data_original = data;
|
181
183
|
const char* const end = data + len;
|
182
184
|
data = utf8_range_SkipAscii(data, end);
|
183
185
|
/* SIMD algorithm always outperforms the naive version for any data of
|
184
186
|
length >=16.
|
185
187
|
*/
|
186
188
|
if (end - data < 16) {
|
187
|
-
return (return_position ? (data -
|
189
|
+
return (return_position ? (data - data_original) : 0) +
|
188
190
|
utf8_range_ValidateUTF8Naive(data, end, return_position);
|
189
191
|
}
|
190
|
-
#
|
191
|
-
return (
|
192
|
-
|
192
|
+
#if defined(__SSE4_1__) || (defined(__ARM_NEON) && defined(__ARM_64BIT_STATE))
|
193
|
+
return utf8_range_ValidateUTF8Simd(
|
194
|
+
data_original, data, end, return_position);
|
193
195
|
#else
|
194
|
-
|
195
|
-
|
196
|
-
* The mapping between ranges of codepoint and their corresponding utf-8
|
197
|
-
* sequences is below.
|
198
|
-
*/
|
199
|
-
|
200
|
-
/*
|
201
|
-
* U+0000...U+007F 00...7F
|
202
|
-
* U+0080...U+07FF C2...DF 80...BF
|
203
|
-
* U+0800...U+0FFF E0 A0...BF 80...BF
|
204
|
-
* U+1000...U+CFFF E1...EC 80...BF 80...BF
|
205
|
-
* U+D000...U+D7FF ED 80...9F 80...BF
|
206
|
-
* U+E000...U+FFFF EE...EF 80...BF 80...BF
|
207
|
-
* U+10000...U+3FFFF F0 90...BF 80...BF 80...BF
|
208
|
-
* U+40000...U+FFFFF F1...F3 80...BF 80...BF 80...BF
|
209
|
-
* U+100000...U+10FFFF F4 80...8F 80...BF 80...BF
|
210
|
-
*/
|
211
|
-
|
212
|
-
/* First we compute the type for each byte, as given by the table below.
|
213
|
-
* This type will be used as an index later on.
|
214
|
-
*/
|
215
|
-
|
216
|
-
/*
|
217
|
-
* Index Min Max Byte Type
|
218
|
-
* 0 00 7F Single byte sequence
|
219
|
-
* 1,2,3 80 BF Second, third and fourth byte for many of the sequences.
|
220
|
-
* 4 A0 BF Second byte after E0
|
221
|
-
* 5 80 9F Second byte after ED
|
222
|
-
* 6 90 BF Second byte after F0
|
223
|
-
* 7 80 8F Second byte after F4
|
224
|
-
* 8 C2 F4 First non ASCII byte
|
225
|
-
* 9..15 7F 80 Invalid byte
|
226
|
-
*/
|
227
|
-
|
228
|
-
/* After the first step we compute the index for all bytes, then we permute
|
229
|
-
the bytes according to their indices to check the ranges from the range
|
230
|
-
table.
|
231
|
-
* The range for a given type can be found in the range_min_table and
|
232
|
-
range_max_table, the range for type/index X is in range_min_table[X] ...
|
233
|
-
range_max_table[X].
|
234
|
-
*/
|
235
|
-
|
236
|
-
/* Algorithm:
|
237
|
-
* Put index zero to all bytes.
|
238
|
-
* Find all non ASCII characters, give them index 8.
|
239
|
-
* For each tail byte in a codepoint sequence, give it an index corresponding
|
240
|
-
to the 1 based index from the end.
|
241
|
-
* If the first byte of the codepoint is in the [C0...DF] range, we write
|
242
|
-
index 1 in the following byte.
|
243
|
-
* If the first byte of the codepoint is in the range [E0...EF], we write
|
244
|
-
indices 2 and 1 in the next two bytes.
|
245
|
-
* If the first byte of the codepoint is in the range [F0...FF] we write
|
246
|
-
indices 3,2,1 into the next three bytes.
|
247
|
-
* For finding the number of bytes we need to look at high nibbles (4 bits)
|
248
|
-
and do the lookup from the table, it can be done with shift by 4 + shuffle
|
249
|
-
instructions. We call it `first_len`.
|
250
|
-
* Then we shift first_len by 8 bits to get the indices of the 2nd bytes.
|
251
|
-
* Saturating sub 1 and shift by 8 bits to get the indices of the 3rd bytes.
|
252
|
-
* Again to get the indices of the 4th bytes.
|
253
|
-
* Take OR of all that 4 values and check within range.
|
254
|
-
*/
|
255
|
-
/* For example:
|
256
|
-
* input C3 80 68 E2 80 20 A6 F0 A0 80 AC 20 F0 93 80 80
|
257
|
-
* first_len 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 0
|
258
|
-
* 1st byte 8 0 0 8 0 0 0 8 0 0 0 0 8 0 0 0
|
259
|
-
* 2nd byte 0 1 0 0 2 0 0 0 3 0 0 0 0 3 0 0 // Shift + sub
|
260
|
-
* 3rd byte 0 0 0 0 0 1 0 0 0 2 0 0 0 0 2 0 // Shift + sub
|
261
|
-
* 4th byte 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 // Shift + sub
|
262
|
-
* Index 8 1 0 8 2 1 0 8 3 2 1 0 8 3 2 1 // OR of results
|
263
|
-
*/
|
264
|
-
|
265
|
-
/* Checking for errors:
|
266
|
-
* Error checking is done by looking up the high nibble (4 bits) of each byte
|
267
|
-
against an error checking table.
|
268
|
-
* Because the lookup value for the second byte depends of the value of the
|
269
|
-
first byte in codepoint, we use saturated operations to adjust the index.
|
270
|
-
* Specifically we need to add 2 for E0, 3 for ED, 3 for F0 and 4 for F4 to
|
271
|
-
match the correct index.
|
272
|
-
* If we subtract from all bytes EF then EO -> 241, ED -> 254, F0 -> 1,
|
273
|
-
F4 -> 5
|
274
|
-
* Do saturating sub 240, then E0 -> 1, ED -> 14 and we can do lookup to
|
275
|
-
match the adjustment
|
276
|
-
* Add saturating 112, then F0 -> 113, F4 -> 117, all that were > 16 will
|
277
|
-
be more 128 and lookup in ef_fe_table will return 0 but for F0
|
278
|
-
and F4 it will be 4 and 5 accordingly
|
279
|
-
*/
|
280
|
-
/*
|
281
|
-
* Then just check the appropriate ranges with greater/smaller equal
|
282
|
-
instructions. Check tail with a naive algorithm.
|
283
|
-
* To save from previous 16 byte checks we just align previous_first_len to
|
284
|
-
get correct continuations of the codepoints.
|
285
|
-
*/
|
286
|
-
|
287
|
-
/*
|
288
|
-
* Map high nibble of "First Byte" to legal character length minus 1
|
289
|
-
* 0x00 ~ 0xBF --> 0
|
290
|
-
* 0xC0 ~ 0xDF --> 1
|
291
|
-
* 0xE0 ~ 0xEF --> 2
|
292
|
-
* 0xF0 ~ 0xFF --> 3
|
293
|
-
*/
|
294
|
-
const __m128i first_len_table =
|
295
|
-
_mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3);
|
296
|
-
|
297
|
-
/* Map "First Byte" to 8-th item of range table (0xC2 ~ 0xF4) */
|
298
|
-
const __m128i first_range_table =
|
299
|
-
_mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8);
|
300
|
-
|
301
|
-
/*
|
302
|
-
* Range table, map range index to min and max values
|
303
|
-
*/
|
304
|
-
const __m128i range_min_table =
|
305
|
-
_mm_setr_epi8(0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, 0xC2, 0x7F,
|
306
|
-
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F);
|
307
|
-
|
308
|
-
const __m128i range_max_table =
|
309
|
-
_mm_setr_epi8(0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, 0xF4, 0x80,
|
310
|
-
0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
|
311
|
-
|
312
|
-
/*
|
313
|
-
* Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after
|
314
|
-
* which the Second Byte are not 80~BF. It contains "range index adjustment".
|
315
|
-
* +------------+---------------+------------------+----------------+
|
316
|
-
* | First Byte | original range| range adjustment | adjusted range |
|
317
|
-
* +------------+---------------+------------------+----------------+
|
318
|
-
* | E0 | 2 | 2 | 4 |
|
319
|
-
* +------------+---------------+------------------+----------------+
|
320
|
-
* | ED | 2 | 3 | 5 |
|
321
|
-
* +------------+---------------+------------------+----------------+
|
322
|
-
* | F0 | 3 | 3 | 6 |
|
323
|
-
* +------------+---------------+------------------+----------------+
|
324
|
-
* | F4 | 4 | 4 | 8 |
|
325
|
-
* +------------+---------------+------------------+----------------+
|
326
|
-
*/
|
327
|
-
|
328
|
-
/* df_ee_table[1] -> E0, df_ee_table[14] -> ED as ED - E0 = 13 */
|
329
|
-
// The values represent the adjustment in the Range Index table for a correct
|
330
|
-
// index.
|
331
|
-
const __m128i df_ee_table =
|
332
|
-
_mm_setr_epi8(0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0);
|
333
|
-
|
334
|
-
/* ef_fe_table[1] -> F0, ef_fe_table[5] -> F4, F4 - F0 = 4 */
|
335
|
-
// The values represent the adjustment in the Range Index table for a correct
|
336
|
-
// index.
|
337
|
-
const __m128i ef_fe_table =
|
338
|
-
_mm_setr_epi8(0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
339
|
-
|
340
|
-
__m128i prev_input = _mm_set1_epi8(0);
|
341
|
-
__m128i prev_first_len = _mm_set1_epi8(0);
|
342
|
-
__m128i error = _mm_set1_epi8(0);
|
343
|
-
while (end - data >= 16) {
|
344
|
-
const __m128i input =
|
345
|
-
_mm_loadu_si128((const __m128i*)(data));
|
346
|
-
|
347
|
-
/* high_nibbles = input >> 4 */
|
348
|
-
const __m128i high_nibbles =
|
349
|
-
_mm_and_si128(_mm_srli_epi16(input, 4), _mm_set1_epi8(0x0F));
|
350
|
-
|
351
|
-
/* first_len = legal character length minus 1 */
|
352
|
-
/* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */
|
353
|
-
/* first_len = first_len_table[high_nibbles] */
|
354
|
-
__m128i first_len = _mm_shuffle_epi8(first_len_table, high_nibbles);
|
355
|
-
|
356
|
-
/* First Byte: set range index to 8 for bytes within 0xC0 ~ 0xFF */
|
357
|
-
/* range = first_range_table[high_nibbles] */
|
358
|
-
__m128i range = _mm_shuffle_epi8(first_range_table, high_nibbles);
|
359
|
-
|
360
|
-
/* Second Byte: set range index to first_len */
|
361
|
-
/* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */
|
362
|
-
/* range |= (first_len, prev_first_len) << 1 byte */
|
363
|
-
range = _mm_or_si128(range, _mm_alignr_epi8(first_len, prev_first_len, 15));
|
364
|
-
|
365
|
-
/* Third Byte: set range index to saturate_sub(first_len, 1) */
|
366
|
-
/* 0 for 00~7F, 0 for C0~DF, 1 for E0~EF, 2 for F0~FF */
|
367
|
-
__m128i tmp1;
|
368
|
-
__m128i tmp2;
|
369
|
-
/* tmp1 = saturate_sub(first_len, 1) */
|
370
|
-
tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(1));
|
371
|
-
/* tmp2 = saturate_sub(prev_first_len, 1) */
|
372
|
-
tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(1));
|
373
|
-
/* range |= (tmp1, tmp2) << 2 bytes */
|
374
|
-
range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 14));
|
375
|
-
|
376
|
-
/* Fourth Byte: set range index to saturate_sub(first_len, 2) */
|
377
|
-
/* 0 for 00~7F, 0 for C0~DF, 0 for E0~EF, 1 for F0~FF */
|
378
|
-
/* tmp1 = saturate_sub(first_len, 2) */
|
379
|
-
tmp1 = _mm_subs_epu8(first_len, _mm_set1_epi8(2));
|
380
|
-
/* tmp2 = saturate_sub(prev_first_len, 2) */
|
381
|
-
tmp2 = _mm_subs_epu8(prev_first_len, _mm_set1_epi8(2));
|
382
|
-
/* range |= (tmp1, tmp2) << 3 bytes */
|
383
|
-
range = _mm_or_si128(range, _mm_alignr_epi8(tmp1, tmp2, 13));
|
384
|
-
|
385
|
-
/*
|
386
|
-
* Now we have below range indices calculated
|
387
|
-
* Correct cases:
|
388
|
-
* - 8 for C0~FF
|
389
|
-
* - 3 for 1st byte after F0~FF
|
390
|
-
* - 2 for 1st byte after E0~EF or 2nd byte after F0~FF
|
391
|
-
* - 1 for 1st byte after C0~DF or 2nd byte after E0~EF or
|
392
|
-
* 3rd byte after F0~FF
|
393
|
-
* - 0 for others
|
394
|
-
* Error cases:
|
395
|
-
* >9 for non ascii First Byte overlapping
|
396
|
-
* E.g., F1 80 C2 90 --> 8 3 10 2, where 10 indicates error
|
397
|
-
*/
|
398
|
-
|
399
|
-
/* Adjust Second Byte range for special First Bytes(E0,ED,F0,F4) */
|
400
|
-
/* Overlaps lead to index 9~15, which are illegal in range table */
|
401
|
-
__m128i shift1;
|
402
|
-
__m128i pos;
|
403
|
-
__m128i range2;
|
404
|
-
/* shift1 = (input, prev_input) << 1 byte */
|
405
|
-
shift1 = _mm_alignr_epi8(input, prev_input, 15);
|
406
|
-
pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF));
|
407
|
-
/*
|
408
|
-
* shift1: | EF F0 ... FE | FF 00 ... ... DE | DF E0 ... EE |
|
409
|
-
* pos: | 0 1 15 | 16 17 239| 240 241 255|
|
410
|
-
* pos-240: | 0 0 0 | 0 0 0 | 0 1 15 |
|
411
|
-
* pos+112: | 112 113 127| >= 128 | >= 128 |
|
412
|
-
*/
|
413
|
-
tmp1 = _mm_subs_epu8(pos, _mm_set1_epi8(-16));
|
414
|
-
range2 = _mm_shuffle_epi8(df_ee_table, tmp1);
|
415
|
-
tmp2 = _mm_adds_epu8(pos, _mm_set1_epi8(112));
|
416
|
-
range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_table, tmp2));
|
417
|
-
|
418
|
-
range = _mm_add_epi8(range, range2);
|
419
|
-
|
420
|
-
/* Load min and max values per calculated range index */
|
421
|
-
__m128i min_range = _mm_shuffle_epi8(range_min_table, range);
|
422
|
-
__m128i max_range = _mm_shuffle_epi8(range_max_table, range);
|
423
|
-
|
424
|
-
/* Check value range */
|
425
|
-
if (return_position) {
|
426
|
-
error = _mm_cmplt_epi8(input, min_range);
|
427
|
-
error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range));
|
428
|
-
/* 5% performance drop from this conditional branch */
|
429
|
-
if (!_mm_testz_si128(error, error)) {
|
430
|
-
break;
|
431
|
-
}
|
432
|
-
} else {
|
433
|
-
error = _mm_or_si128(error, _mm_cmplt_epi8(input, min_range));
|
434
|
-
error = _mm_or_si128(error, _mm_cmpgt_epi8(input, max_range));
|
435
|
-
}
|
436
|
-
|
437
|
-
prev_input = input;
|
438
|
-
prev_first_len = first_len;
|
439
|
-
|
440
|
-
data += 16;
|
441
|
-
}
|
442
|
-
/* If we got to the end, we don't need to skip any bytes backwards */
|
443
|
-
if (return_position && (data - (end - len)) == 0) {
|
444
|
-
return utf8_range_ValidateUTF8Naive(data, end, return_position);
|
445
|
-
}
|
446
|
-
/* Find previous codepoint (not 80~BF) */
|
447
|
-
data -= utf8_range_CodepointSkipBackwards(_mm_extract_epi32(prev_input, 3));
|
448
|
-
if (return_position) {
|
449
|
-
return (data - (end - len)) +
|
450
|
-
utf8_range_ValidateUTF8Naive(data, end, return_position);
|
451
|
-
}
|
452
|
-
/* Test if there was any error */
|
453
|
-
if (!_mm_testz_si128(error, error)) {
|
454
|
-
return 0;
|
455
|
-
}
|
456
|
-
/* Check the tail */
|
457
|
-
return utf8_range_ValidateUTF8Naive(data, end, return_position);
|
196
|
+
return (return_position ? (data - data_original) : 0) +
|
197
|
+
utf8_range_ValidateUTF8Naive(data, end, return_position);
|
458
198
|
#endif
|
459
199
|
}
|
460
200
|
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#include <arm_neon.h>
|
2
|
+
|
3
|
+
/* This code is almost the same as SSE implementation, please reference
|
4
|
+
* utf8-range-sse.inc for detailed explanation.
|
5
|
+
* The only difference is the range adjustment step. NEON code is more
|
6
|
+
* straightforward.
|
7
|
+
*/
|
8
|
+
|
9
|
+
static FORCE_INLINE_ATTR inline size_t utf8_range_ValidateUTF8Simd(
|
10
|
+
const char* data_original, const char* data, const char* end,
|
11
|
+
int return_position) {
|
12
|
+
const uint8x16_t first_len_tbl = {
|
13
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
|
14
|
+
};
|
15
|
+
const uint8x16_t first_range_tbl = {
|
16
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
|
17
|
+
};
|
18
|
+
const uint8x16_t range_min_tbl = {
|
19
|
+
0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80,
|
20
|
+
0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
21
|
+
};
|
22
|
+
const uint8x16_t range_max_tbl = {
|
23
|
+
0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F,
|
24
|
+
0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
25
|
+
};
|
26
|
+
/* Range adjustment in NEON uint8x16x2 table. Note that lanes are interleaved
|
27
|
+
* in register. The table below is plotted vertically to ease understanding.
|
28
|
+
* The 1st column is for E0~EF, 2nd column for F0~FF.
|
29
|
+
*/
|
30
|
+
// clang-format off
|
31
|
+
const uint8_t range_adjust_tbl_data[] = {
|
32
|
+
/* index -> 0~15 16~31 <- index */
|
33
|
+
/* E0 -> */ 2, 3, /* <- F0 */
|
34
|
+
0, 0,
|
35
|
+
0, 0,
|
36
|
+
0, 0,
|
37
|
+
0, 4, /* <- F4 */
|
38
|
+
0, 0,
|
39
|
+
0, 0,
|
40
|
+
0, 0,
|
41
|
+
0, 0,
|
42
|
+
0, 0,
|
43
|
+
0, 0,
|
44
|
+
0, 0,
|
45
|
+
0, 0,
|
46
|
+
/* ED -> */ 3, 0,
|
47
|
+
0, 0,
|
48
|
+
0, 0,
|
49
|
+
};
|
50
|
+
// clang-format on
|
51
|
+
const uint8x16x2_t range_adjust_tbl = vld2q_u8(range_adjust_tbl_data);
|
52
|
+
|
53
|
+
const uint8x16_t const_1 = vdupq_n_u8(1);
|
54
|
+
const uint8x16_t const_2 = vdupq_n_u8(2);
|
55
|
+
const uint8x16_t const_e0 = vdupq_n_u8(0xE0);
|
56
|
+
|
57
|
+
uint8x16_t prev_input = vdupq_n_u8(0);
|
58
|
+
uint8x16_t prev_first_len = vdupq_n_u8(0);
|
59
|
+
uint8x16_t error = vdupq_n_u8(0);
|
60
|
+
|
61
|
+
while (end - data >= 16) {
|
62
|
+
const uint8x16_t input = vld1q_u8((const uint8_t*)data);
|
63
|
+
|
64
|
+
const uint8x16_t high_nibbles = vshrq_n_u8(input, 4);
|
65
|
+
|
66
|
+
const uint8x16_t first_len = vqtbl1q_u8(first_len_tbl, high_nibbles);
|
67
|
+
|
68
|
+
uint8x16_t range = vqtbl1q_u8(first_range_tbl, high_nibbles);
|
69
|
+
|
70
|
+
range = vorrq_u8(range, vextq_u8(prev_first_len, first_len, 15));
|
71
|
+
|
72
|
+
uint8x16_t shift2 = vextq_u8(prev_first_len, first_len, 14);
|
73
|
+
shift2 = vqsubq_u8(shift2, const_1);
|
74
|
+
range = vorrq_u8(range, shift2);
|
75
|
+
|
76
|
+
uint8x16_t shift3 = vextq_u8(prev_first_len, first_len, 13);
|
77
|
+
shift3 = vqsubq_u8(shift3, const_2);
|
78
|
+
range = vorrq_u8(range, shift3);
|
79
|
+
|
80
|
+
uint8x16_t shift1 = vextq_u8(prev_input, input, 15);
|
81
|
+
shift1 = vsubq_u8(shift1, const_e0);
|
82
|
+
range = vaddq_u8(range, vqtbl2q_u8(range_adjust_tbl, shift1));
|
83
|
+
|
84
|
+
const uint8x16_t min_range = vqtbl1q_u8(range_min_tbl, range);
|
85
|
+
const uint8x16_t max_range = vqtbl1q_u8(range_max_tbl, range);
|
86
|
+
|
87
|
+
if (return_position) {
|
88
|
+
error = vcltq_u8(input, min_range);
|
89
|
+
error = vorrq_u8(error, vcgtq_u8(input, max_range));
|
90
|
+
if (vmaxvq_u32(vreinterpretq_u32_u8(error))) {
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
} else {
|
94
|
+
error = vorrq_u8(error, vcltq_u8(input, min_range));
|
95
|
+
error = vorrq_u8(error, vcgtq_u8(input, max_range));
|
96
|
+
}
|
97
|
+
|
98
|
+
prev_input = input;
|
99
|
+
prev_first_len = first_len;
|
100
|
+
|
101
|
+
data += 16;
|
102
|
+
}
|
103
|
+
|
104
|
+
if (return_position && data == data_original) {
|
105
|
+
return utf8_range_ValidateUTF8Naive(data, end, return_position);
|
106
|
+
}
|
107
|
+
const int32_t prev = vgetq_lane_s32(vreinterpretq_s32_u8(prev_input), 3);
|
108
|
+
data -= utf8_range_CodepointSkipBackwards(prev);
|
109
|
+
if (return_position) {
|
110
|
+
return (data - data_original) +
|
111
|
+
utf8_range_ValidateUTF8Naive(data, end, return_position);
|
112
|
+
}
|
113
|
+
if (vmaxvq_u32(vreinterpretq_u32_u8(error))) {
|
114
|
+
return 0;
|
115
|
+
}
|
116
|
+
return utf8_range_ValidateUTF8Naive(data, end, return_position);
|
117
|
+
}
|