Ruby 4.1.0dev (2026-10-27 revision db563a357875d4efbadec58b0fd8695ac9a82f42)
char.c
1#include "prism/internal/char.h"
2
4#include "prism/internal/line_offset_list.h"
5
6#define PRISM_CHAR_BIT_REGEXP_OPTION (1 << 2)
7
8#define PRISM_NUMBER_BIT_BINARY_DIGIT (1 << 0)
9#define PRISM_NUMBER_BIT_BINARY_NUMBER (1 << 1)
10#define PRISM_NUMBER_BIT_OCTAL_DIGIT (1 << 2)
11#define PRISM_NUMBER_BIT_OCTAL_NUMBER (1 << 3)
12#define PRISM_NUMBER_BIT_DECIMAL_DIGIT (1 << 4)
13#define PRISM_NUMBER_BIT_DECIMAL_NUMBER (1 << 5)
14#define PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT (1 << 6)
15#define PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER (1 << 7)
16
17const uint8_t pm_byte_table[256] = {
18// 0 1 2 3 4 5 6 7 8 9 A B C D E F
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, 0, 0, // 0x
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
21 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
22 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x
23 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4x
24 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5x
25 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6x
26 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 7x
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
35};
36
37static const uint8_t pm_number_table[256] = {
38 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1x
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2x
42 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3x
43 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4x
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, // 5x
45 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6x
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7x
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8x
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9x
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ax
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bx
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Cx
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dx
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ex
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fx
55};
56
61static PRISM_INLINE size_t
62pm_strspn_char_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
63 if (length <= 0) return 0;
64
65 size_t size = 0;
66 size_t maximum = (size_t) length;
67
68 while (size < maximum && (pm_byte_table[string[size]] & kind)) size++;
69 return size;
70}
71
76size_t
77pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length) {
78 return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_WHITESPACE);
79}
80
85size_t
86pm_strrspn_whitespace(const uint8_t *string, ptrdiff_t length) {
87 if (length <= 0) return 0;
88
89 size_t size = 0;
90 size_t maximum = (size_t) length;
91
92 while (size < maximum && (pm_byte_table[string[maximum - size - 1]] & PRISM_CHAR_BIT_WHITESPACE)) size++;
93 return size;
94}
95
101size_t
102pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset) {
103 if (length <= 0) return 0;
104
105 uint32_t size = 0;
106 uint32_t maximum = (uint32_t) length;
107
108 while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
109 if (string[size] == '\n') {
110 pm_line_offset_list_append(arena, line_offsets, start_offset + size + 1);
111 }
112
113 size++;
114 }
115
116 return size;
117}
118
123size_t
124pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length) {
125 return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_REGEXP_OPTION);
126}
127
128
134static PRISM_INLINE size_t
135pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
136 if (length <= 0) return 0;
137
138 size_t size = 0;
139 size_t maximum = (size_t) length;
140
141 while (size < maximum && (pm_number_table[string[size]] & kind)) size++;
142 return size;
143}
144
153static PRISM_INLINE size_t
154pm_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
155 if (length <= 0) return 0;
156
157 size_t size = 0;
158 size_t maximum = (size_t) length;
159
160 bool underscore = false;
161 while (size < maximum && (pm_number_table[string[size]] & kind)) {
162 if (string[size] == '_') {
163 if (underscore) *invalid = string + size;
164 underscore = true;
165 } else {
166 underscore = false;
167 }
168
169 size++;
170 }
171
172 if (size > 0 && string[size - 1] == '_') *invalid = string + size - 1;
173 return size;
174}
175
185size_t
186pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
187 return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_BINARY_NUMBER);
188}
189
199size_t
200pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
201 return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_OCTAL_NUMBER);
202}
203
208size_t
209pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) {
210 return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
211}
212
222size_t
223pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
224 return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_DECIMAL_NUMBER);
225}
226
232size_t
233pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) {
234 return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
235}
236
246size_t
247pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
248 return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER);
249}
250
254static PRISM_INLINE bool
255pm_char_is_number_kind(const uint8_t b, uint8_t kind) {
256 return (pm_number_table[b] & kind) != 0;
257}
258
262bool
263pm_char_is_binary_digit(const uint8_t b) {
264 return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_BINARY_DIGIT);
265}
266
270bool
271pm_char_is_octal_digit(const uint8_t b) {
272 return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_OCTAL_DIGIT);
273}
274
278bool
279pm_char_is_decimal_digit(const uint8_t b) {
280 return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
281}
282
286bool
287pm_char_is_hexadecimal_digit(const uint8_t b) {
288 return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
289}
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
Definition inline.h:12
A list of offsets of the start of lines in a string.