Ruby: prism/util/pm_string.c Source File

Ruby 3.3.4p94 (2024-07-09 revision be1089c8ec5ba40e09b1553e36b3174bf4014d9d)

pm_string.c
1#include "prism/util/pm_string.h"
2
7 PRISM_EXPORTED_FUNCTION size_t
8pm_string_sizeof(void) {
9 return sizeof(pm_string_t);
10}
11
15void
16pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) {
17 assert(start <= end);
18
19 *string = (pm_string_t) {
20 .type = PM_STRING_SHARED,
21 .source = start,
22 .length = (size_t) (end - start)
23 };
24}
25
29void
30pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) {
31 *string = (pm_string_t) {
32 .type = PM_STRING_OWNED,
33 .source = source,
34 .length = length
35 };
36}
37
41void
42pm_string_constant_init(pm_string_t *string, const char *source, size_t length) {
43 *string = (pm_string_t) {
44 .type = PM_STRING_CONSTANT,
45 .source = (const uint8_t *) source,
46 .length = length
47 };
48}
49
61bool
62pm_string_mapped_init(pm_string_t *string, const char *filepath) {
63#ifdef _WIN32
64 // Open the file for reading.
65 HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
66
67 if (file == INVALID_HANDLE_VALUE) {
68 perror("CreateFile failed");
69 return false;
70 }
71
72 // Get the file size.
73 DWORD file_size = GetFileSize(file, NULL);
74 if (file_size == INVALID_FILE_SIZE) {
75 CloseHandle(file);
76 perror("GetFileSize failed");
77 return false;
78 }
79
80 // If the file is empty, then we don't need to do anything else, we'll set
81 // the source to a constant empty string and return.
82 if (file_size == 0) {
83 CloseHandle(file);
84 const uint8_t source[] = "";
85 *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
86 return true;
87 }
88
89 // Create a mapping of the file.
90 HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
91 if (mapping == NULL) {
92 CloseHandle(file);
93 perror("CreateFileMapping failed");
94 return false;
95 }
96
97 // Map the file into memory.
98 uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
99 CloseHandle(mapping);
100 CloseHandle(file);
101
102 if (source == NULL) {
103 perror("MapViewOfFile failed");
104 return false;
105 }
106
107 *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
108 return true;
109#else
110 // Open the file for reading
111 int fd = open(filepath, O_RDONLY);
112 if (fd == -1) {
113 perror("open");
114 return false;
115 }
116
117 // Stat the file to get the file size
118 struct stat sb;
119 if (fstat(fd, &sb) == -1) {
120 close(fd);
121 perror("fstat");
122 return false;
123 }
124
125 // mmap the file descriptor to virtually get the contents
126 size_t size = (size_t) sb.st_size;
127 uint8_t *source = NULL;
128
129 if (size == 0) {
130 close(fd);
131 const uint8_t source[] = "";
132 *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
133 return true;
134 }
135
136 source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
137 if (source == MAP_FAILED) {
138 perror("Map failed");
139 return false;
140 }
141
142 close(fd);
143 *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
144 return true;
145#endif
146}
147
151size_t
152pm_string_memsize(const pm_string_t *string) {
153 size_t size = sizeof(pm_string_t);
154 if (string->type == PM_STRING_OWNED) {
155 size += string->length;
156 }
157 return size;
158}
159
164void
165pm_string_ensure_owned(pm_string_t *string) {
166 if (string->type == PM_STRING_OWNED) return;
167
168 size_t length = pm_string_length(string);
169 const uint8_t *source = pm_string_source(string);
170
171 uint8_t *memory = malloc(length);
172 if (!memory) return;
173
174 pm_string_owned_init(string, memory, length);
175 memcpy((void *) string->source, source, length);
176}
177
181 PRISM_EXPORTED_FUNCTION size_t
182pm_string_length(const pm_string_t *string) {
183 return string->length;
184}
185
189 PRISM_EXPORTED_FUNCTION const uint8_t *
190pm_string_source(const pm_string_t *string) {
191 return string->source;
192}
193
197 PRISM_EXPORTED_FUNCTION void
198pm_string_free(pm_string_t *string) {
199 void *memory = (void *) string->source;
200
201 if (string->type == PM_STRING_OWNED) {
202 free(memory);
203 } else if (string->type == PM_STRING_MAPPED && string->length) {
204#if defined(_WIN32)
205 UnmapViewOfFile(memory);
206#else
207 munmap(memory, string->length);
208#endif
209 }
210}
pm_string.h
A generic string type that can have various ownership semantics.
PRISM_EXPORTED_FUNCTION
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
Definition defines.h:32
pm_string_t
A generic string type that can have various ownership semantics.
Definition pm_string.h:30
pm_string_t::source
const uint8_t * source
A pointer to the start of the string.
Definition pm_string.h:32
pm_string_t::type
enum pm_string_t::@97 type
The type of the string.
pm_string_t::length
size_t length
The length of the string in bytes of memory.
Definition pm_string.h:35