Ruby: prism/util/pm_buffer.c Source File

Ruby 3.4.6p54 (2025-09-16 revision dbd83256b1cec76c69756ecb8758b9e1079833de)

pm_buffer.c
1#include "prism/util/pm_buffer.h"
2
6size_t
7pm_buffer_sizeof(void) {
8 return sizeof(pm_buffer_t);
9}
10
14bool
15pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) {
16 buffer->length = 0;
17 buffer->capacity = capacity;
18
19 buffer->value = (char *) xmalloc(capacity);
20 return buffer->value != NULL;
21}
22
26bool
27pm_buffer_init(pm_buffer_t *buffer) {
28 return pm_buffer_init_capacity(buffer, 1024);
29}
30
34char *
35pm_buffer_value(const pm_buffer_t *buffer) {
36 return buffer->value;
37}
38
42size_t
43pm_buffer_length(const pm_buffer_t *buffer) {
44 return buffer->length;
45}
46
50static inline bool
51pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
52 size_t next_length = buffer->length + length;
53
54 if (next_length > buffer->capacity) {
55 if (buffer->capacity == 0) {
56 buffer->capacity = 1;
57 }
58
59 while (next_length > buffer->capacity) {
60 buffer->capacity *= 2;
61 }
62
63 buffer->value = xrealloc(buffer->value, buffer->capacity);
64 if (buffer->value == NULL) return false;
65 }
66
67 buffer->length = next_length;
68 return true;
69}
70
74static inline void
75pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
76 size_t cursor = buffer->length;
77 if (pm_buffer_append_length(buffer, length)) {
78 memcpy(buffer->value + cursor, source, length);
79 }
80}
81
85void
86pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length) {
87 size_t cursor = buffer->length;
88 if (pm_buffer_append_length(buffer, length)) {
89 memset(buffer->value + cursor, 0, length);
90 }
91}
92
96void
97pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) {
98 va_list arguments;
99 va_start(arguments, format);
100 int result = vsnprintf(NULL, 0, format, arguments);
101 va_end(arguments);
102
103 if (result < 0) return;
104 size_t length = (size_t) (result + 1);
105
106 size_t cursor = buffer->length;
107 if (pm_buffer_append_length(buffer, length)) {
108 va_start(arguments, format);
109 vsnprintf(buffer->value + cursor, length, format, arguments);
110 va_end(arguments);
111 buffer->length--;
112 }
113}
114
118void
119pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length) {
120 pm_buffer_append(buffer, value, length);
121}
122
126void
127pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length) {
128 pm_buffer_append(buffer, (const char *) value, length);
129}
130
134void
135pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value) {
136 const void *source = &value;
137 pm_buffer_append(buffer, source, sizeof(uint8_t));
138}
139
143void
144pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value) {
145 if (value < 128) {
146 pm_buffer_append_byte(buffer, (uint8_t) value);
147 } else {
148 uint32_t n = value;
149 while (n >= 128) {
150 pm_buffer_append_byte(buffer, (uint8_t) (n | 128));
151 n >>= 7;
152 }
153 pm_buffer_append_byte(buffer, (uint8_t) n);
154 }
155}
156
160void
161pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
162 uint32_t unsigned_int = ((uint32_t)(value) << 1) ^ ((uint32_t)(value >> 31));
163 pm_buffer_append_varuint(buffer, unsigned_int);
164}
165
169void
170pm_buffer_append_double(pm_buffer_t *buffer, double value) {
171 const void *source = &value;
172 pm_buffer_append(buffer, source, sizeof(double));
173}
174
178bool
179pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
180 if (value <= 0x7F) {
181 pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
182 return true;
183 } else if (value <= 0x7FF) {
184 uint8_t bytes[] = {
185 (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
186 (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
187 };
188
189 pm_buffer_append_bytes(buffer, bytes, 2);
190 return true;
191 } else if (value <= 0xFFFF) {
192 uint8_t bytes[] = {
193 (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
194 (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
195 (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
196 };
197
198 pm_buffer_append_bytes(buffer, bytes, 3);
199 return true;
200 } else if (value <= 0x10FFFF) {
201 uint8_t bytes[] = {
202 (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
203 (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
204 (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
205 (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
206 };
207
208 pm_buffer_append_bytes(buffer, bytes, 4);
209 return true;
210 } else {
211 return false;
212 }
213}
214
218void
219pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
220 for (size_t index = 0; index < length; index++) {
221 const uint8_t byte = source[index];
222
223 if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
224 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
225 pm_buffer_append_format(buffer, "\\x%02X", byte);
226 } else {
227 pm_buffer_append_format(buffer, "\\u%04X", byte);
228 }
229 } else {
230 switch (byte) {
231 case '\a':
232 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
233 pm_buffer_append_string(buffer, "\\a", 2);
234 } else {
235 pm_buffer_append_format(buffer, "\\u%04X", byte);
236 }
237 break;
238 case '\b':
239 pm_buffer_append_string(buffer, "\\b", 2);
240 break;
241 case '\t':
242 pm_buffer_append_string(buffer, "\\t", 2);
243 break;
244 case '\n':
245 pm_buffer_append_string(buffer, "\\n", 2);
246 break;
247 case '\v':
248 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
249 pm_buffer_append_string(buffer, "\\v", 2);
250 } else {
251 pm_buffer_append_format(buffer, "\\u%04X", byte);
252 }
253 break;
254 case '\f':
255 pm_buffer_append_string(buffer, "\\f", 2);
256 break;
257 case '\r':
258 pm_buffer_append_string(buffer, "\\r", 2);
259 break;
260 case '"':
261 pm_buffer_append_string(buffer, "\\\"", 2);
262 break;
263 case '#': {
264 if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
265 const uint8_t next_byte = source[index + 1];
266 if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
267 pm_buffer_append_byte(buffer, '\\');
268 }
269 }
270
271 pm_buffer_append_byte(buffer, '#');
272 break;
273 }
274 case '\\':
275 pm_buffer_append_string(buffer, "\\\\", 2);
276 break;
277 default:
278 pm_buffer_append_byte(buffer, byte);
279 break;
280 }
281 }
282 }
283}
284
288void
289pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
290 size_t cursor = buffer->length;
291 if (pm_buffer_append_length(buffer, length)) {
292 memmove(buffer->value + length, buffer->value, cursor);
293 memcpy(buffer->value, value, length);
294 }
295}
296
300void
301pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
302 if (source->length > 0) {
303 pm_buffer_append(destination, source->value, source->length);
304 }
305}
306
311void
312pm_buffer_clear(pm_buffer_t *buffer) {
313 buffer->length = 0;
314}
315
319void
320pm_buffer_rstrip(pm_buffer_t *buffer) {
321 while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
322 buffer->length--;
323 }
324}
325
329size_t
330pm_buffer_index(const pm_buffer_t *buffer, char value) {
331 const char *first = memchr(buffer->value, value, buffer->length);
332 return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
333}
334
338void
339pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
340 assert(index <= buffer->length);
341
342 if (index == buffer->length) {
343 pm_buffer_append_string(buffer, value, length);
344 } else {
345 pm_buffer_append_zeroes(buffer, length);
346 memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
347 memcpy(buffer->value + index, value, length);
348 }
349}
350
354void
355pm_buffer_free(pm_buffer_t *buffer) {
356 xfree(buffer->value);
357}
xfree
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
xrealloc
#define xrealloc
Old name of ruby_xrealloc.
Definition xmalloc.h:56
xmalloc
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
pm_buffer.h
A wrapper around a contiguous block of allocated memory.
pm_buffer_init_capacity
bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity)
Initialize a pm_buffer_t with the given capacity.
Definition pm_buffer.c:15
pm_buffer_sizeof
PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void)
Return the size of the pm_buffer_t struct.
Definition pm_buffer.c:7
pm_buffer_escaping_t
pm_buffer_escaping_t
The different types of escaping that can be performed by the buffer when appending a slice of Ruby so...
Definition pm_buffer.h:160
pm_buffer_t
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
Definition pm_buffer.h:22
pm_buffer_t::pm_buffer_length
PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
Definition pm_buffer.c:43
pm_buffer_t::capacity
size_t capacity
The capacity of the buffer in bytes that has been allocated.
Definition pm_buffer.h:27
pm_buffer_t::pm_buffer_init
PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
Definition pm_buffer.c:27
pm_buffer_t::length
size_t length
The length of the buffer in bytes.
Definition pm_buffer.h:24
pm_buffer_t::pm_buffer_free
PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
Definition pm_buffer.c:355
pm_buffer_t::pm_buffer_value
PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
Definition pm_buffer.c:35
pm_buffer_t::value
char * value
A pointer to the start of the buffer.
Definition pm_buffer.h:30