7pm_strpbrk_invalid_multibyte_character(
pm_parser_t *parser, uint32_t start, uint32_t length) {
8 pm_diagnostic_list_append_format(&parser->
metadata_arena, &parser->
error_list, start, length, PM_ERR_INVALID_MULTIBYTE_CHARACTER, parser->
start[start]);
15pm_strpbrk_explicit_encoding_set(
pm_parser_t *parser, uint32_t start, uint32_t length) {
25 assert(
false &&
"unreachable");
48#if defined(PRISM_HAS_NEON) || defined(PRISM_HAS_SSSE3) || defined(PRISM_HAS_SWAR)
61pm_strpbrk_cache_update(
pm_parser_t *parser,
const uint8_t *charset) {
65 if (memcmp(parser->strpbrk_cache.charset, charset,
sizeof(parser->strpbrk_cache.charset)) == 0)
return;
67 memset(parser->strpbrk_cache.low_lut, 0,
sizeof(parser->strpbrk_cache.low_lut));
68 memset(parser->strpbrk_cache.high_lut, 0,
sizeof(parser->strpbrk_cache.high_lut));
69 memset(parser->strpbrk_cache.table, 0,
sizeof(parser->strpbrk_cache.table));
75 parser->strpbrk_cache.low_lut[0x00] |= (uint8_t) (1 << 0);
76 parser->strpbrk_cache.high_lut[0x00] = (uint8_t) (1 << 0);
77 parser->strpbrk_cache.table[0] |= (uint64_t) 1;
79 size_t charset_len = 0;
80 for (
const uint8_t *c = charset; *c !=
'\0'; c++) {
81 parser->strpbrk_cache.low_lut[*c & 0x0F] |= (uint8_t) (1 << (*c >> 4));
82 parser->strpbrk_cache.high_lut[*c >> 4] = (uint8_t) (1 << (*c >> 4));
83 parser->strpbrk_cache.table[*c >> 6] |= (uint64_t) 1 << (*c & 0x3F);
88 memcpy(parser->strpbrk_cache.charset, charset, charset_len + 1);
89 memset(parser->strpbrk_cache.charset + charset_len + 1, 0,
sizeof(parser->strpbrk_cache.charset) - charset_len - 1);
94#if defined(PRISM_HAS_NEON)
98scan_strpbrk_ascii(
pm_parser_t *parser,
const uint8_t *source,
size_t maximum,
const uint8_t *charset,
size_t *index) {
99 pm_strpbrk_cache_update(parser, charset);
101 uint8x16_t low_lut = vld1q_u8(parser->strpbrk_cache.low_lut);
102 uint8x16_t high_lut = vld1q_u8(parser->strpbrk_cache.high_lut);
103 uint8x16_t mask_0f = vdupq_n_u8(0x0F);
104 uint8x16_t mask_80 = vdupq_n_u8(0x80);
108 while (idx + 16 <= maximum) {
109 uint8x16_t v = vld1q_u8(source + idx);
113 if (vmaxvq_u8(vandq_u8(v, mask_80)) != 0)
break;
115 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
116 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
117 uint8x16_t matched = vtstq_u8(lo_class, hi_class);
119 if (vmaxvq_u8(matched) == 0) {
125 uint64_t lo64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 0);
130 uint64_t hi64 = vgetq_lane_u64(vreinterpretq_u64_u8(matched), 1);
131 *index = idx + 8 +
pm_ctzll(hi64) / 8;
136 while (idx < maximum && source[idx] < 0x80) {
137 uint8_t
byte = source[idx];
138 if (parser->strpbrk_cache.table[
byte >> 6] & ((uint64_t) 1 << (
byte & 0x3F))) {
149#elif defined(PRISM_HAS_SSSE3)
150#include <tmmintrin.h>
153scan_strpbrk_ascii(
pm_parser_t *parser,
const uint8_t *source,
size_t maximum,
const uint8_t *charset,
size_t *index) {
154 pm_strpbrk_cache_update(parser, charset);
156 __m128i low_lut = _mm_loadu_si128((
const __m128i *) parser->strpbrk_cache.low_lut);
157 __m128i high_lut = _mm_loadu_si128((
const __m128i *) parser->strpbrk_cache.high_lut);
158 __m128i mask_0f = _mm_set1_epi8(0x0F);
162 while (idx + 16 <= maximum) {
163 __m128i v = _mm_loadu_si128((
const __m128i *) (source + idx));
166 if (_mm_movemask_epi8(v) != 0)
break;
170 __m128i lo_class = _mm_shuffle_epi8(low_lut, _mm_and_si128(v, mask_0f));
171 __m128i hi_class = _mm_shuffle_epi8(high_lut, _mm_and_si128(_mm_srli_epi16(v, 4), mask_0f));
172 __m128i matched = _mm_and_si128(lo_class, hi_class);
175 int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(matched, _mm_setzero_si128()));
177 if (mask == 0xFFFF) {
184 *index = idx +
pm_ctzll((uint64_t) (~mask & 0xFFFF));
189 while (idx < maximum && source[idx] < 0x80) {
190 uint8_t
byte = source[idx];
191 if (parser->strpbrk_cache.table[
byte >> 6] & ((uint64_t) 1 << (
byte & 0x3F))) {
202#elif defined(PRISM_HAS_SWAR)
205scan_strpbrk_ascii(
pm_parser_t *parser,
const uint8_t *source,
size_t maximum,
const uint8_t *charset,
size_t *index) {
206 pm_strpbrk_cache_update(parser, charset);
208 static const uint64_t highs = 0x8080808080808080ULL;
211 while (idx + 8 <= maximum) {
213 memcpy(&word, source + idx, 8);
216 if (word & highs)
break;
219 for (
size_t j = 0; j < 8; j++) {
220 uint8_t
byte = source[idx + j];
221 if (parser->strpbrk_cache.table[
byte >> 6] & ((uint64_t) 1 << (
byte & 0x3F))) {
231 while (idx < maximum && source[idx] < 0x80) {
232 uint8_t
byte = source[idx];
233 if (parser->strpbrk_cache.table[
byte >> 6] & ((uint64_t) 1 << (
byte & 0x3F))) {
257static inline const uint8_t *
258pm_strpbrk_utf8(
pm_parser_t *parser,
const uint8_t *source,
const uint8_t *charset,
size_t index,
size_t maximum,
bool validate) {
259 while (index < maximum) {
260 if (strchr((
const char *) charset, source[index]) != NULL) {
261 return source + index;
264 if (source[index] < 0x80) {
267 size_t width = pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index));
271 }
else if (!validate) {
278 const size_t start = index;
282 }
while (index < maximum && pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
284 pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->
start), (uint32_t) (index - start));
295static inline const uint8_t *
296pm_strpbrk_ascii_8bit(
pm_parser_t *parser,
const uint8_t *source,
const uint8_t *charset,
size_t index,
size_t maximum,
bool validate) {
297 while (index < maximum) {
298 if (strchr((
const char *) charset, source[index]) != NULL) {
299 return source + index;
302 if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->
start), 1);
312static inline const uint8_t *
313pm_strpbrk_multi_byte(
pm_parser_t *parser,
const uint8_t *source,
const uint8_t *charset,
size_t index,
size_t maximum,
bool validate) {
316 while (index < maximum) {
317 if (strchr((
const char *) charset, source[index]) != NULL) {
318 return source + index;
321 if (source[index] < 0x80) {
324 size_t width = encoding->
char_width(source + index, (ptrdiff_t) (maximum - index));
325 if (validate) pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->
start), (uint32_t) width);
329 }
else if (!validate) {
336 const size_t start = index;
340 }
while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
342 pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->
start), (uint32_t) (index - start));
354static inline const uint8_t *
355pm_strpbrk_single_byte(
pm_parser_t *parser,
const uint8_t *source,
const uint8_t *charset,
size_t index,
size_t maximum,
bool validate) {
358 while (index < maximum) {
359 if (strchr((
const char *) charset, source[index]) != NULL) {
360 return source + index;
363 if (source[index] < 0x80 || !validate) {
366 size_t width = encoding->
char_width(source + index, (ptrdiff_t) (maximum - index));
367 pm_strpbrk_explicit_encoding_set(parser, (uint32_t) (source - parser->
start), (uint32_t) width);
376 const size_t start = index;
380 }
while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
382 pm_strpbrk_invalid_multibyte_character(parser, (uint32_t) ((source + start) - parser->
start), (uint32_t) (index - start));
410pm_strpbrk(
pm_parser_t *parser,
const uint8_t *source,
const uint8_t *charset, ptrdiff_t length,
bool validate) {
411 if (length <= 0)
return NULL;
413 size_t maximum = (size_t) length;
415 if (scan_strpbrk_ascii(parser, source, maximum, charset, &index))
return source + index;
418 return pm_strpbrk_utf8(parser, source, charset, index, maximum, validate);
420 return pm_strpbrk_ascii_8bit(parser, source, charset, index, maximum, validate);
422 return pm_strpbrk_multi_byte(parser, source, charset, index, maximum, validate);
424 return pm_strpbrk_single_byte(parser, source, charset, index, maximum, validate);
A custom strpbrk implementation.
#define pm_ctzll(v)
Platform detection for SIMD / fast-path implementations.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PM_ENCODING_ASCII_8BIT_ENTRY
This is the ASCII-8BIT encoding.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool multibyte
Return true if the encoding is a multibyte encoding.
const char * name
The name of the encoding.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
const uint8_t * start
The pointer to the start of the source.
pm_arena_t metadata_arena
The arena used for parser metadata (comments, diagnostics, etc.).
pm_list_t error_list
The list of errors that have been found while parsing.