Ruby: prism/util/pm_buffer.c Source File

Ruby 3.4.1p0 (2024-12-25 revision 48d4efcb85000e1ebae42004e963b5d0cedddcf2)

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
178void
179pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
180 for (size_t index = 0; index < length; index++) {
181 const uint8_t byte = source[index];
182
183 if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
184 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
185 pm_buffer_append_format(buffer, "\\x%02X", byte);
186 } else {
187 pm_buffer_append_format(buffer, "\\u%04X", byte);
188 }
189 } else {
190 switch (byte) {
191 case '\a':
192 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
193 pm_buffer_append_string(buffer, "\\a", 2);
194 } else {
195 pm_buffer_append_format(buffer, "\\u%04X", byte);
196 }
197 break;
198 case '\b':
199 pm_buffer_append_string(buffer, "\\b", 2);
200 break;
201 case '\t':
202 pm_buffer_append_string(buffer, "\\t", 2);
203 break;
204 case '\n':
205 pm_buffer_append_string(buffer, "\\n", 2);
206 break;
207 case '\v':
208 if (escaping == PM_BUFFER_ESCAPING_RUBY) {
209 pm_buffer_append_string(buffer, "\\v", 2);
210 } else {
211 pm_buffer_append_format(buffer, "\\u%04X", byte);
212 }
213 break;
214 case '\f':
215 pm_buffer_append_string(buffer, "\\f", 2);
216 break;
217 case '\r':
218 pm_buffer_append_string(buffer, "\\r", 2);
219 break;
220 case '"':
221 pm_buffer_append_string(buffer, "\\\"", 2);
222 break;
223 case '#': {
224 if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
225 const uint8_t next_byte = source[index + 1];
226 if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
227 pm_buffer_append_byte(buffer, '\\');
228 }
229 }
230
231 pm_buffer_append_byte(buffer, '#');
232 break;
233 }
234 case '\\':
235 pm_buffer_append_string(buffer, "\\\\", 2);
236 break;
237 default:
238 pm_buffer_append_byte(buffer, byte);
239 break;
240 }
241 }
242 }
243}
244
248void
249pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
250 size_t cursor = buffer->length;
251 if (pm_buffer_append_length(buffer, length)) {
252 memmove(buffer->value + length, buffer->value, cursor);
253 memcpy(buffer->value, value, length);
254 }
255}
256
260void
261pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
262 if (source->length > 0) {
263 pm_buffer_append(destination, source->value, source->length);
264 }
265}
266
271void
272pm_buffer_clear(pm_buffer_t *buffer) {
273 buffer->length = 0;
274}
275
279void
280pm_buffer_rstrip(pm_buffer_t *buffer) {
281 while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
282 buffer->length--;
283 }
284}
285
289size_t
290pm_buffer_index(const pm_buffer_t *buffer, char value) {
291 const char *first = memchr(buffer->value, value, buffer->length);
292 return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
293}
294
298void
299pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
300 assert(index <= buffer->length);
301
302 if (index == buffer->length) {
303 pm_buffer_append_string(buffer, value, length);
304 } else {
305 pm_buffer_append_zeroes(buffer, length);
306 memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
307 memcpy(buffer->value + index, value, length);
308 }
309}
310
314void
315pm_buffer_free(pm_buffer_t *buffer) {
316 xfree(buffer->value);
317}
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_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:144
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::capacity
size_t capacity
The capacity of the buffer in bytes that has been allocated.
Definition pm_buffer.h:27
pm_buffer_t::length
size_t length
The length of the buffer in bytes.
Definition pm_buffer.h:24
pm_buffer_t::value
char * value
A pointer to the start of the buffer.
Definition pm_buffer.h:30