@herb-tools/node 0.8.9 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/binding.gyp +26 -8
  3. package/dist/herb-node.cjs +41 -12
  4. package/dist/herb-node.cjs.map +1 -1
  5. package/dist/herb-node.esm.js +8 -1
  6. package/dist/herb-node.esm.js.map +1 -1
  7. package/dist/types/node-backend.d.ts +3 -1
  8. package/extension/error_helpers.cpp +419 -71
  9. package/extension/error_helpers.h +14 -3
  10. package/extension/extension_helpers.cpp +38 -35
  11. package/extension/extension_helpers.h +2 -2
  12. package/extension/herb.cpp +183 -64
  13. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +290 -0
  14. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
  15. package/extension/libherb/analyze/action_view/content_tag.c +70 -0
  16. package/extension/libherb/analyze/action_view/link_to.c +143 -0
  17. package/extension/libherb/analyze/action_view/registry.c +60 -0
  18. package/extension/libherb/analyze/action_view/tag.c +64 -0
  19. package/extension/libherb/analyze/action_view/tag_helper_handler.h +41 -0
  20. package/extension/libherb/analyze/action_view/tag_helper_node_builders.c +305 -0
  21. package/extension/libherb/analyze/action_view/tag_helper_node_builders.h +70 -0
  22. package/extension/libherb/analyze/action_view/tag_helpers.c +748 -0
  23. package/extension/libherb/analyze/action_view/tag_helpers.h +38 -0
  24. package/extension/libherb/analyze/action_view/turbo_frame_tag.c +88 -0
  25. package/extension/libherb/analyze/analyze.c +882 -0
  26. package/extension/libherb/{include → analyze}/analyze.h +14 -4
  27. package/extension/libherb/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  28. package/extension/libherb/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  29. package/extension/libherb/analyze/builders.c +343 -0
  30. package/extension/libherb/analyze/builders.h +27 -0
  31. package/extension/libherb/analyze/conditional_elements.c +594 -0
  32. package/extension/libherb/analyze/conditional_elements.h +9 -0
  33. package/extension/libherb/analyze/conditional_open_tags.c +640 -0
  34. package/extension/libherb/analyze/conditional_open_tags.h +9 -0
  35. package/extension/libherb/analyze/control_type.c +250 -0
  36. package/extension/libherb/analyze/control_type.h +14 -0
  37. package/extension/libherb/{analyze_helpers.c → analyze/helpers.c} +79 -31
  38. package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +22 -17
  39. package/extension/libherb/analyze/invalid_structures.c +193 -0
  40. package/extension/libherb/analyze/invalid_structures.h +11 -0
  41. package/extension/libherb/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  42. package/extension/libherb/analyze/parse_errors.c +84 -0
  43. package/extension/libherb/analyze/prism_annotate.c +397 -0
  44. package/extension/libherb/analyze/prism_annotate.h +16 -0
  45. package/extension/libherb/{analyze_transform.c → analyze/transform.c} +17 -3
  46. package/extension/libherb/ast_node.c +17 -7
  47. package/extension/libherb/ast_node.h +11 -5
  48. package/extension/libherb/ast_nodes.c +663 -388
  49. package/extension/libherb/ast_nodes.h +118 -39
  50. package/extension/libherb/ast_pretty_print.c +191 -7
  51. package/extension/libherb/ast_pretty_print.h +6 -1
  52. package/extension/libherb/element_source.h +3 -8
  53. package/extension/libherb/errors.c +1100 -507
  54. package/extension/libherb/errors.h +155 -54
  55. package/extension/libherb/extract.c +148 -49
  56. package/extension/libherb/extract.h +21 -5
  57. package/extension/libherb/herb.c +52 -34
  58. package/extension/libherb/herb.h +18 -6
  59. package/extension/libherb/herb_prism_node.h +13 -0
  60. package/extension/libherb/html_util.c +241 -12
  61. package/extension/libherb/html_util.h +7 -2
  62. package/extension/libherb/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  63. package/extension/libherb/include/analyze/action_view/tag_helper_handler.h +41 -0
  64. package/extension/libherb/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  65. package/extension/libherb/include/analyze/action_view/tag_helpers.h +38 -0
  66. package/extension/libherb/{analyze.h → include/analyze/analyze.h} +14 -4
  67. package/extension/libherb/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  68. package/extension/libherb/include/analyze/builders.h +27 -0
  69. package/extension/libherb/include/analyze/conditional_elements.h +9 -0
  70. package/extension/libherb/include/analyze/conditional_open_tags.h +9 -0
  71. package/extension/libherb/include/analyze/control_type.h +14 -0
  72. package/extension/libherb/include/{analyze_helpers.h → analyze/helpers.h} +22 -17
  73. package/extension/libherb/include/analyze/invalid_structures.h +11 -0
  74. package/extension/libherb/include/analyze/prism_annotate.h +16 -0
  75. package/extension/libherb/include/ast_node.h +11 -5
  76. package/extension/libherb/include/ast_nodes.h +118 -39
  77. package/extension/libherb/include/ast_pretty_print.h +6 -1
  78. package/extension/libherb/include/element_source.h +3 -8
  79. package/extension/libherb/include/errors.h +155 -54
  80. package/extension/libherb/include/extract.h +21 -5
  81. package/extension/libherb/include/herb.h +18 -6
  82. package/extension/libherb/include/herb_prism_node.h +13 -0
  83. package/extension/libherb/include/html_util.h +7 -2
  84. package/extension/libherb/include/io.h +3 -1
  85. package/extension/libherb/include/lex_helpers.h +29 -0
  86. package/extension/libherb/include/lexer.h +1 -1
  87. package/extension/libherb/include/lexer_peek_helpers.h +87 -13
  88. package/extension/libherb/include/lexer_struct.h +2 -0
  89. package/extension/libherb/include/location.h +2 -1
  90. package/extension/libherb/include/parser.h +27 -2
  91. package/extension/libherb/include/parser_helpers.h +19 -3
  92. package/extension/libherb/include/pretty_print.h +10 -5
  93. package/extension/libherb/include/prism_context.h +45 -0
  94. package/extension/libherb/include/prism_helpers.h +10 -7
  95. package/extension/libherb/include/prism_serialized.h +12 -0
  96. package/extension/libherb/include/token.h +16 -4
  97. package/extension/libherb/include/token_struct.h +10 -3
  98. package/extension/libherb/include/utf8.h +2 -1
  99. package/extension/libherb/include/util/hb_allocator.h +78 -0
  100. package/extension/libherb/include/util/hb_arena.h +6 -1
  101. package/extension/libherb/include/util/hb_arena_debug.h +12 -1
  102. package/extension/libherb/include/util/hb_array.h +7 -3
  103. package/extension/libherb/include/util/hb_buffer.h +6 -4
  104. package/extension/libherb/include/util/hb_foreach.h +79 -0
  105. package/extension/libherb/include/util/hb_narray.h +8 -4
  106. package/extension/libherb/include/util/hb_string.h +56 -9
  107. package/extension/libherb/include/util/string.h +11 -0
  108. package/extension/libherb/include/util.h +6 -3
  109. package/extension/libherb/include/version.h +1 -1
  110. package/extension/libherb/io.c +3 -2
  111. package/extension/libherb/io.h +3 -1
  112. package/extension/libherb/lex_helpers.h +29 -0
  113. package/extension/libherb/lexer.c +42 -30
  114. package/extension/libherb/lexer.h +1 -1
  115. package/extension/libherb/lexer_peek_helpers.c +12 -74
  116. package/extension/libherb/lexer_peek_helpers.h +87 -13
  117. package/extension/libherb/lexer_struct.h +2 -0
  118. package/extension/libherb/location.c +2 -2
  119. package/extension/libherb/location.h +2 -1
  120. package/extension/libherb/main.c +79 -66
  121. package/extension/libherb/parser.c +784 -247
  122. package/extension/libherb/parser.h +27 -2
  123. package/extension/libherb/parser_helpers.c +110 -23
  124. package/extension/libherb/parser_helpers.h +19 -3
  125. package/extension/libherb/parser_match_tags.c +110 -49
  126. package/extension/libherb/pretty_print.c +29 -24
  127. package/extension/libherb/pretty_print.h +10 -5
  128. package/extension/libherb/prism_context.h +45 -0
  129. package/extension/libherb/prism_helpers.c +30 -27
  130. package/extension/libherb/prism_helpers.h +10 -7
  131. package/extension/libherb/prism_serialized.h +12 -0
  132. package/extension/libherb/ruby_parser.c +2 -0
  133. package/extension/libherb/token.c +151 -66
  134. package/extension/libherb/token.h +16 -4
  135. package/extension/libherb/token_matchers.c +0 -1
  136. package/extension/libherb/token_struct.h +10 -3
  137. package/extension/libherb/utf8.c +7 -6
  138. package/extension/libherb/utf8.h +2 -1
  139. package/extension/libherb/util/hb_allocator.c +341 -0
  140. package/extension/libherb/util/hb_allocator.h +78 -0
  141. package/extension/libherb/util/hb_arena.c +81 -56
  142. package/extension/libherb/util/hb_arena.h +6 -1
  143. package/extension/libherb/util/hb_arena_debug.c +32 -17
  144. package/extension/libherb/util/hb_arena_debug.h +12 -1
  145. package/extension/libherb/util/hb_array.c +30 -15
  146. package/extension/libherb/util/hb_array.h +7 -3
  147. package/extension/libherb/util/hb_buffer.c +17 -21
  148. package/extension/libherb/util/hb_buffer.h +6 -4
  149. package/extension/libherb/util/hb_foreach.h +79 -0
  150. package/extension/libherb/util/hb_narray.c +22 -7
  151. package/extension/libherb/util/hb_narray.h +8 -4
  152. package/extension/libherb/util/hb_string.c +49 -35
  153. package/extension/libherb/util/hb_string.h +56 -9
  154. package/extension/libherb/util/string.h +11 -0
  155. package/extension/libherb/util.c +21 -11
  156. package/extension/libherb/util.h +6 -3
  157. package/extension/libherb/version.h +1 -1
  158. package/extension/libherb/visitor.c +48 -1
  159. package/extension/nodes.cpp +451 -6
  160. package/extension/nodes.h +8 -1
  161. package/extension/prism/include/prism/ast.h +4 -4
  162. package/extension/prism/include/prism/version.h +2 -2
  163. package/extension/prism/src/prism.c +1 -1
  164. package/package.json +12 -8
  165. package/src/node-backend.ts +11 -1
  166. package/dist/types/index-cjs.d.cts +0 -1
  167. package/extension/libherb/analyze.c +0 -1594
  168. package/extension/libherb/element_source.c +0 -12
  169. package/extension/libherb/include/util/hb_system.h +0 -9
  170. package/extension/libherb/util/hb_system.c +0 -30
  171. package/extension/libherb/util/hb_system.h +0 -9
  172. package/src/index-cjs.cts +0 -22
  173. /package/dist/types/{index-esm.d.mts → index.d.ts} +0 -0
  174. /package/src/{index-esm.mts → index.ts} +0 -0
@@ -0,0 +1,341 @@
1
+ #include "../include/util/hb_allocator.h"
2
+ #include "../include/util/hb_arena.h"
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ // --- Malloc backend ---
9
+
10
+ static void* malloc_alloc(hb_allocator_T* _self, size_t size) {
11
+ return calloc(1, size);
12
+ }
13
+
14
+ static void malloc_dealloc(hb_allocator_T* _self, void* pointer) {
15
+ free(pointer);
16
+ }
17
+
18
+ static char* malloc_strdup(hb_allocator_T* _self, const char* string) {
19
+ if (!string) { return NULL; }
20
+
21
+ size_t length = strlen(string);
22
+ char* copy = malloc(length + 1);
23
+ if (!copy) { return NULL; }
24
+
25
+ memcpy(copy, string, length + 1);
26
+
27
+ return copy;
28
+ }
29
+
30
+ static char* malloc_strndup(hb_allocator_T* _self, const char* string, size_t length) {
31
+ if (!string) { return NULL; }
32
+
33
+ char* copy = malloc(length + 1);
34
+ if (!copy) { return NULL; }
35
+
36
+ memcpy(copy, string, length);
37
+ copy[length] = '\0';
38
+
39
+ return copy;
40
+ }
41
+
42
+ static void* malloc_realloc(hb_allocator_T* _self, void* pointer, size_t _old_size, size_t new_size) {
43
+ return realloc(pointer, new_size);
44
+ }
45
+
46
+ static void malloc_destroy(hb_allocator_T* _self) {
47
+ }
48
+
49
+ hb_allocator_T hb_allocator_with_malloc(void) {
50
+ return (hb_allocator_T) {
51
+ .alloc = malloc_alloc,
52
+ .realloc = malloc_realloc,
53
+ .dealloc = malloc_dealloc,
54
+ .strdup = malloc_strdup,
55
+ .strndup = malloc_strndup,
56
+ .destroy = malloc_destroy,
57
+ .context = NULL,
58
+ };
59
+ }
60
+
61
+ // --- Arena backend ---
62
+
63
+ static void* arena_alloc(hb_allocator_T* self, size_t size) {
64
+ return hb_arena_alloc((hb_arena_T*) self->context, size);
65
+ }
66
+
67
+ static void* arena_realloc(hb_allocator_T* self, void* pointer, size_t old_size, size_t new_size) {
68
+ if (!pointer) { return arena_alloc(self, new_size); }
69
+
70
+ void* new_pointer = hb_arena_alloc((hb_arena_T*) self->context, new_size);
71
+ if (!new_pointer) { return NULL; }
72
+
73
+ size_t copy_size = old_size < new_size ? old_size : new_size;
74
+ memcpy(new_pointer, pointer, copy_size);
75
+
76
+ return new_pointer;
77
+ }
78
+
79
+ static void arena_dealloc(hb_allocator_T* _self, void* _pointer) {
80
+ }
81
+
82
+ static char* arena_strdup(hb_allocator_T* self, const char* string) {
83
+ if (!string) { return NULL; }
84
+
85
+ size_t length = strlen(string);
86
+ char* copy = hb_arena_alloc((hb_arena_T*) self->context, length + 1);
87
+ if (!copy) { return NULL; }
88
+
89
+ memcpy(copy, string, length + 1);
90
+
91
+ return copy;
92
+ }
93
+
94
+ static char* arena_strndup(hb_allocator_T* self, const char* string, size_t length) {
95
+ if (!string) { return NULL; }
96
+
97
+ char* copy = hb_arena_alloc((hb_arena_T*) self->context, length + 1);
98
+ if (!copy) { return NULL; }
99
+
100
+ memcpy(copy, string, length);
101
+ copy[length] = '\0';
102
+
103
+ return copy;
104
+ }
105
+
106
+ static void arena_destroy(hb_allocator_T* self) {
107
+ hb_arena_T* arena = (hb_arena_T*) self->context;
108
+ hb_arena_free(arena);
109
+ free(arena);
110
+ self->context = NULL;
111
+ }
112
+
113
+ hb_allocator_T hb_allocator_with_arena(hb_arena_T* arena) {
114
+ return (hb_allocator_T) {
115
+ .alloc = arena_alloc,
116
+ .realloc = arena_realloc,
117
+ .dealloc = arena_dealloc,
118
+ .strdup = arena_strdup,
119
+ .strndup = arena_strndup,
120
+ .destroy = arena_destroy,
121
+ .context = arena,
122
+ };
123
+ }
124
+
125
+ // --- Tracking backend ---
126
+
127
+ #define TRACKING_INITIAL_CAPACITY 128
128
+ #define TRACKING_TOMBSTONE ((void*) 1)
129
+
130
+ static size_t tracking_probe(hb_allocator_tracking_stats_T* stats, void* pointer) {
131
+ size_t mask = stats->buckets_capacity - 1;
132
+ size_t index = ((size_t) pointer >> 4) & mask;
133
+
134
+ while (true) {
135
+ void* key = stats->buckets[index].pointer;
136
+ if (key == NULL || key == TRACKING_TOMBSTONE || key == pointer) { return index; }
137
+ index = (index + 1) & mask;
138
+ }
139
+ }
140
+
141
+ static void tracking_grow(hb_allocator_tracking_stats_T* stats) {
142
+ size_t old_capacity = stats->buckets_capacity;
143
+ hb_allocator_tracking_entry_T* old_buckets = stats->buckets;
144
+
145
+ size_t new_capacity = old_capacity ? old_capacity * 2 : TRACKING_INITIAL_CAPACITY;
146
+ stats->buckets = calloc(new_capacity, sizeof(hb_allocator_tracking_entry_T));
147
+ stats->buckets_capacity = new_capacity;
148
+ stats->buckets_used = 0;
149
+
150
+ for (size_t i = 0; i < old_capacity; i++) {
151
+ if (old_buckets[i].pointer != NULL && old_buckets[i].pointer != TRACKING_TOMBSTONE) {
152
+ size_t index = tracking_probe(stats, old_buckets[i].pointer);
153
+ stats->buckets[index] = old_buckets[i];
154
+ stats->buckets_used++;
155
+ }
156
+ }
157
+
158
+ free(old_buckets);
159
+ }
160
+
161
+ static void tracking_record(hb_allocator_tracking_stats_T* stats, void* pointer, size_t size) {
162
+ if (stats->buckets_used * 2 >= stats->buckets_capacity) { tracking_grow(stats); }
163
+
164
+ size_t index = tracking_probe(stats, pointer);
165
+ stats->buckets[index] = (hb_allocator_tracking_entry_T) { .pointer = pointer, .size = size };
166
+ stats->buckets_used++;
167
+ stats->allocation_count++;
168
+ stats->bytes_allocated += size;
169
+ }
170
+
171
+ static void tracking_record_untracked(hb_allocator_tracking_stats_T* stats, void* pointer) {
172
+ stats->untracked_deallocation_count++;
173
+
174
+ if (stats->untracked_pointers_size >= stats->untracked_pointers_capacity) {
175
+ size_t new_capacity = stats->untracked_pointers_capacity ? stats->untracked_pointers_capacity * 2 : 16;
176
+ void** new_pointers = realloc(stats->untracked_pointers, new_capacity * sizeof(void*));
177
+
178
+ if (!new_pointers) { return; }
179
+
180
+ stats->untracked_pointers = new_pointers;
181
+ stats->untracked_pointers_capacity = new_capacity;
182
+ }
183
+
184
+ stats->untracked_pointers[stats->untracked_pointers_size++] = pointer;
185
+ }
186
+
187
+ static void tracking_unrecord(hb_allocator_tracking_stats_T* stats, void* pointer) {
188
+ if (!stats->buckets_capacity) {
189
+ tracking_record_untracked(stats, pointer);
190
+
191
+ return;
192
+ }
193
+
194
+ size_t mask = stats->buckets_capacity - 1;
195
+ size_t index = ((size_t) pointer >> 4) & mask;
196
+
197
+ while (true) {
198
+ void* key = stats->buckets[index].pointer;
199
+
200
+ if (key == NULL) {
201
+ tracking_record_untracked(stats, pointer);
202
+
203
+ return;
204
+ }
205
+
206
+ if (key == pointer) {
207
+ stats->deallocation_count++;
208
+ stats->bytes_deallocated += stats->buckets[index].size;
209
+ stats->buckets[index].pointer = TRACKING_TOMBSTONE;
210
+ stats->buckets[index].size = 0;
211
+
212
+ return;
213
+ }
214
+
215
+ index = (index + 1) & mask;
216
+ }
217
+ }
218
+
219
+ static void* tracking_alloc(hb_allocator_T* self, size_t size) {
220
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
221
+ void* pointer = calloc(1, size);
222
+
223
+ if (pointer) { tracking_record(stats, pointer, size); }
224
+
225
+ return pointer;
226
+ }
227
+
228
+ static void* tracking_realloc(hb_allocator_T* self, void* pointer, size_t _old_size, size_t new_size) {
229
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
230
+
231
+ if (pointer) { tracking_unrecord(stats, pointer); }
232
+
233
+ void* new_pointer = realloc(pointer, new_size);
234
+
235
+ if (new_pointer) { tracking_record(stats, new_pointer, new_size); }
236
+
237
+ return new_pointer;
238
+ }
239
+
240
+ static void tracking_dealloc(hb_allocator_T* self, void* pointer) {
241
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
242
+ tracking_unrecord(stats, pointer);
243
+ free(pointer);
244
+ }
245
+
246
+ static char* tracking_strdup(hb_allocator_T* self, const char* string) {
247
+ if (!string) { return NULL; }
248
+
249
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
250
+ size_t length = strlen(string);
251
+ char* copy = malloc(length + 1);
252
+ if (!copy) { return NULL; }
253
+
254
+ memcpy(copy, string, length + 1);
255
+ tracking_record(stats, copy, length + 1);
256
+
257
+ return copy;
258
+ }
259
+
260
+ static char* tracking_strndup(hb_allocator_T* self, const char* string, size_t length) {
261
+ if (!string) { return NULL; }
262
+
263
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
264
+ char* copy = malloc(length + 1);
265
+ if (!copy) { return NULL; }
266
+
267
+ memcpy(copy, string, length);
268
+ copy[length] = '\0';
269
+ tracking_record(stats, copy, length + 1);
270
+
271
+ return copy;
272
+ }
273
+
274
+ static void tracking_destroy(hb_allocator_T* self) {
275
+ hb_allocator_tracking_stats_T* stats = (hb_allocator_tracking_stats_T*) self->context;
276
+
277
+ free(stats->buckets);
278
+ free(stats->untracked_pointers);
279
+ free(stats);
280
+
281
+ self->context = NULL;
282
+ }
283
+
284
+ hb_allocator_T hb_allocator_with_tracking(void) {
285
+ hb_allocator_tracking_stats_T* stats = calloc(1, sizeof(hb_allocator_tracking_stats_T));
286
+
287
+ return (hb_allocator_T) {
288
+ .alloc = tracking_alloc,
289
+ .realloc = tracking_realloc,
290
+ .dealloc = tracking_dealloc,
291
+ .strdup = tracking_strdup,
292
+ .strndup = tracking_strndup,
293
+ .destroy = tracking_destroy,
294
+ .context = stats,
295
+ };
296
+ }
297
+
298
+ hb_allocator_tracking_stats_T* hb_allocator_tracking_stats(hb_allocator_T* allocator) {
299
+ return (hb_allocator_tracking_stats_T*) allocator->context;
300
+ }
301
+
302
+ // --- High-level API ---
303
+
304
+ bool hb_allocator_init(hb_allocator_T* allocator, hb_allocator_type_T type) {
305
+ return hb_allocator_init_with_size(allocator, type, 0);
306
+ }
307
+
308
+ bool hb_allocator_init_with_size(hb_allocator_T* allocator, hb_allocator_type_T type, size_t initial_size) {
309
+ switch (type) {
310
+ case HB_ALLOCATOR_MALLOC: {
311
+ *allocator = hb_allocator_with_malloc();
312
+ return true;
313
+ }
314
+
315
+ case HB_ALLOCATOR_ARENA: {
316
+ if (initial_size == 0) { initial_size = HB_ALLOCATOR_DEFAULT_ARENA_SIZE; }
317
+
318
+ hb_arena_T* arena = malloc(sizeof(hb_arena_T));
319
+ if (!arena) { return false; }
320
+
321
+ if (!hb_arena_init(arena, initial_size)) {
322
+ free(arena);
323
+ return false;
324
+ }
325
+
326
+ *allocator = hb_allocator_with_arena(arena);
327
+ return true;
328
+ }
329
+
330
+ case HB_ALLOCATOR_TRACKING: {
331
+ *allocator = hb_allocator_with_tracking();
332
+ return true;
333
+ }
334
+
335
+ default: return false;
336
+ }
337
+ }
338
+
339
+ void hb_allocator_destroy(hb_allocator_T* allocator) {
340
+ allocator->destroy(allocator);
341
+ }
@@ -0,0 +1,78 @@
1
+ #ifndef HERB_ALLOCATOR_H
2
+ #define HERB_ALLOCATOR_H
3
+
4
+ #include <stdbool.h>
5
+ #include <stddef.h>
6
+
7
+ #include "hb_arena.h"
8
+
9
+ #ifndef HB_ALLOCATOR_DEFAULT_ARENA_SIZE
10
+ # define HB_ALLOCATOR_DEFAULT_ARENA_SIZE (1024 * 16)
11
+ #endif
12
+
13
+ typedef enum {
14
+ HB_ALLOCATOR_MALLOC,
15
+ HB_ALLOCATOR_ARENA,
16
+ HB_ALLOCATOR_TRACKING,
17
+ } hb_allocator_type_T;
18
+
19
+ typedef struct {
20
+ void* pointer;
21
+ size_t size;
22
+ } hb_allocator_tracking_entry_T;
23
+
24
+ typedef struct {
25
+ size_t allocation_count;
26
+ size_t deallocation_count;
27
+ size_t untracked_deallocation_count;
28
+ size_t bytes_allocated;
29
+ size_t bytes_deallocated;
30
+ hb_allocator_tracking_entry_T* buckets;
31
+ size_t buckets_capacity;
32
+ size_t buckets_used;
33
+ void** untracked_pointers;
34
+ size_t untracked_pointers_size;
35
+ size_t untracked_pointers_capacity;
36
+ } hb_allocator_tracking_stats_T;
37
+
38
+ typedef struct hb_allocator {
39
+ void* (*alloc)(struct hb_allocator* self, size_t size);
40
+ void* (*realloc)(struct hb_allocator* self, void* pointer, size_t old_size, size_t new_size);
41
+ void (*dealloc)(struct hb_allocator* self, void* pointer);
42
+ char* (*strdup)(struct hb_allocator* self, const char* string);
43
+ char* (*strndup)(struct hb_allocator* self, const char* string, size_t length);
44
+ void (*destroy)(struct hb_allocator* self);
45
+ void* context;
46
+ } hb_allocator_T;
47
+
48
+ bool hb_allocator_init(hb_allocator_T* allocator, hb_allocator_type_T type);
49
+ bool hb_allocator_init_with_size(hb_allocator_T* allocator, hb_allocator_type_T type, size_t initial_size);
50
+ void hb_allocator_destroy(hb_allocator_T* allocator);
51
+
52
+ hb_allocator_T hb_allocator_with_malloc(void);
53
+ hb_allocator_T hb_allocator_with_arena(hb_arena_T* arena);
54
+ hb_allocator_T hb_allocator_with_tracking(void);
55
+
56
+ hb_allocator_tracking_stats_T* hb_allocator_tracking_stats(hb_allocator_T* allocator);
57
+
58
+ static inline void* hb_allocator_alloc(hb_allocator_T* allocator, size_t size) {
59
+ return allocator->alloc(allocator, size);
60
+ }
61
+
62
+ static inline void* hb_allocator_realloc(hb_allocator_T* allocator, void* pointer, size_t old_size, size_t new_size) {
63
+ return allocator->realloc(allocator, pointer, old_size, new_size);
64
+ }
65
+
66
+ static inline void hb_allocator_dealloc(hb_allocator_T* allocator, void* pointer) {
67
+ allocator->dealloc(allocator, pointer);
68
+ }
69
+
70
+ static inline char* hb_allocator_strdup(hb_allocator_T* allocator, const char* string) {
71
+ return allocator->strdup(allocator, string);
72
+ }
73
+
74
+ static inline char* hb_allocator_strndup(hb_allocator_T* allocator, const char* string, size_t length) {
75
+ return allocator->strndup(allocator, string, length);
76
+ }
77
+
78
+ #endif
@@ -1,14 +1,38 @@
1
1
  #include "../include/util/hb_arena.h"
2
2
  #include "../include/macros.h"
3
- #include "../include/util/hb_system.h"
4
3
 
5
4
  #include <assert.h>
6
5
  #include <stdbool.h>
7
6
  #include <stdint.h>
8
7
  #include <string.h>
9
8
 
10
- #define hb_arena_for_each_page(allocator, page) \
11
- for (hb_arena_page_T* page = (allocator)->head; page != NULL; page = page->next)
9
+ #ifdef HERB_USE_MALLOC
10
+ # include <stdlib.h>
11
+ #else
12
+ # ifdef __linux__
13
+ # define _GNU_SOURCE
14
+ # endif
15
+ # include <sys/mman.h>
16
+ #endif
17
+
18
+ static void* hb_arena_allocate_page(size_t size) {
19
+ #ifdef HERB_USE_MALLOC
20
+ return malloc(size);
21
+ #else
22
+ void* memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
23
+ if (memory == MAP_FAILED) { return NULL; }
24
+
25
+ return memory;
26
+ #endif
27
+ }
28
+
29
+ static void hb_arena_free_page(void* pointer, size_t size) {
30
+ #ifdef HERB_USE_MALLOC
31
+ free(pointer);
32
+ #else
33
+ munmap(pointer, size);
34
+ #endif
35
+ }
12
36
 
13
37
  static inline size_t hb_arena_align_size(size_t size, size_t alignment) {
14
38
  assert(size <= SIZE_MAX - (alignment - 1));
@@ -22,7 +46,7 @@ static inline bool hb_arena_page_has_capacity(hb_arena_page_T* page, size_t requ
22
46
  return page->position + required_size <= page->capacity;
23
47
  }
24
48
 
25
- static inline void* hb_arena_page_alloc_from(hb_arena_page_T* page, size_t size) {
49
+ static inline void* hb_arena_page_alloc(hb_arena_page_T* page, size_t size) {
26
50
  assert(size > 0);
27
51
  assert(page->position + size <= page->capacity);
28
52
 
@@ -32,28 +56,18 @@ static inline void* hb_arena_page_alloc_from(hb_arena_page_T* page, size_t size)
32
56
  return result;
33
57
  }
34
58
 
35
- static inline void hb_arena_page_reset(hb_arena_page_T* page) {
36
- page->position = 0;
37
- }
38
-
39
- static inline void hb_arena_reset_pages_after(hb_arena_page_T* start_page) {
40
- for (hb_arena_page_T* page = start_page; page != NULL; page = page->next) {
41
- hb_arena_page_reset(page);
42
- }
43
- }
44
-
45
- static bool hb_arena_append_page(hb_arena_T* allocator, size_t minimum_size) {
46
- assert(minimum_size > 0);
47
-
48
- size_t page_size = MAX(allocator->default_page_size, minimum_size);
59
+ static size_t hb_arena_page_free(hb_arena_page_T* starting_page);
49
60
 
61
+ static bool hb_arena_append_page(hb_arena_T* allocator, size_t page_size) {
50
62
  assert(page_size <= SIZE_MAX - sizeof(hb_arena_page_T));
51
- size_t total_size = page_size + sizeof(hb_arena_page_T);
63
+ size_t page_size_with_meta_data = page_size + sizeof(hb_arena_page_T);
52
64
 
53
- hb_arena_page_T* page = hb_system_allocate_memory(total_size);
65
+ hb_arena_page_T* page = hb_arena_allocate_page(page_size_with_meta_data);
54
66
  if (page == NULL) { return false; }
55
67
 
56
- *page = (hb_arena_page_T) { .next = NULL, .capacity = page_size, .position = 0 };
68
+ page->next = NULL;
69
+ page->capacity = page_size;
70
+ page->position = 0;
57
71
 
58
72
  if (allocator->head == NULL) {
59
73
  allocator->head = page;
@@ -72,15 +86,15 @@ static bool hb_arena_append_page(hb_arena_T* allocator, size_t minimum_size) {
72
86
  return true;
73
87
  }
74
88
 
75
- bool hb_arena_init(hb_arena_T* allocator, size_t initial_size) {
76
- assert(initial_size > 0);
89
+ bool hb_arena_init(hb_arena_T* allocator, size_t default_page_size) {
90
+ assert(default_page_size > 0);
77
91
 
78
92
  allocator->head = NULL;
79
93
  allocator->tail = NULL;
80
- allocator->default_page_size = initial_size;
94
+ allocator->default_page_size = default_page_size;
81
95
  allocator->allocation_count = 0;
82
96
 
83
- return hb_arena_append_page(allocator, initial_size);
97
+ return hb_arena_append_page(allocator, default_page_size);
84
98
  }
85
99
 
86
100
  void* hb_arena_alloc(hb_arena_T* allocator, size_t size) {
@@ -92,27 +106,28 @@ void* hb_arena_alloc(hb_arena_T* allocator, size_t size) {
92
106
  allocator->allocation_count++;
93
107
 
94
108
  if (hb_arena_page_has_capacity(allocator->tail, required_size)) {
95
- return hb_arena_page_alloc_from(allocator->tail, required_size);
109
+ return hb_arena_page_alloc(allocator->tail, required_size);
96
110
  }
97
111
 
98
112
  for (hb_arena_page_T* page = allocator->tail->next; page != NULL; page = page->next) {
99
113
  if (hb_arena_page_has_capacity(page, required_size)) {
100
114
  allocator->tail = page;
101
- return hb_arena_page_alloc_from(allocator->tail, required_size);
115
+ return hb_arena_page_alloc(allocator->tail, required_size);
102
116
  }
103
117
  }
104
118
 
105
- bool allocated = hb_arena_append_page(allocator, required_size);
119
+ size_t page_size = MAX(allocator->default_page_size, required_size);
120
+ bool allocated = hb_arena_append_page(allocator, page_size);
106
121
 
107
122
  if (!allocated) { return NULL; }
108
123
 
109
- return hb_arena_page_alloc_from(allocator->tail, required_size);
124
+ return hb_arena_page_alloc(allocator->tail, required_size);
110
125
  }
111
126
 
112
127
  size_t hb_arena_position(hb_arena_T* allocator) {
113
128
  size_t total = 0;
114
129
 
115
- hb_arena_for_each_page(allocator, page) {
130
+ hb_arena_for_each_page(allocator) {
116
131
  total += page->position;
117
132
  }
118
133
 
@@ -122,7 +137,7 @@ size_t hb_arena_position(hb_arena_T* allocator) {
122
137
  size_t hb_arena_capacity(hb_arena_T* allocator) {
123
138
  size_t total = 0;
124
139
 
125
- hb_arena_for_each_page(allocator, page) {
140
+ hb_arena_for_each_page(allocator) {
126
141
  total += page->capacity;
127
142
  }
128
143
 
@@ -130,48 +145,58 @@ size_t hb_arena_capacity(hb_arena_T* allocator) {
130
145
  }
131
146
 
132
147
  void hb_arena_reset(hb_arena_T* allocator) {
133
- hb_arena_for_each_page(allocator, page) {
134
- hb_arena_page_reset(page);
135
- }
136
-
137
- allocator->tail = allocator->head;
148
+ hb_arena_reset_to(allocator, 0);
138
149
  allocator->allocation_count = 0;
139
150
  }
140
151
 
141
152
  void hb_arena_reset_to(hb_arena_T* allocator, size_t target_position) {
142
- if (target_position == 0) {
143
- hb_arena_reset(allocator);
153
+ hb_arena_page_T* current_page = allocator->head;
154
+ size_t current_position = 0;
155
+
156
+ while (current_page != NULL) {
157
+ current_position += current_page->position;
144
158
 
145
- return;
159
+ if (current_position >= target_position) {
160
+ current_page->position -= current_position - target_position;
161
+ break;
162
+ }
163
+
164
+ current_page = current_page->next;
146
165
  }
147
166
 
148
- size_t accumulated = 0;
167
+ if (current_page == NULL) { return; }
149
168
 
150
- hb_arena_for_each_page(allocator, page) {
151
- if (accumulated + page->capacity >= target_position) {
152
- page->position = target_position - accumulated;
153
- allocator->tail = page;
169
+ allocator->tail = current_page;
154
170
 
155
- hb_arena_reset_pages_after(page->next);
171
+ if (current_page->next != NULL) {
172
+ size_t freed_size = hb_arena_page_free(current_page->next);
173
+ current_page->next = NULL;
156
174
 
157
- return;
158
- }
175
+ hb_arena_append_page(allocator, freed_size);
176
+ }
177
+ }
178
+
179
+ static size_t hb_arena_page_free(hb_arena_page_T* starting_page) {
180
+ size_t freed_capacity = 0;
159
181
 
160
- accumulated += page->capacity;
161
- page->position = page->capacity;
182
+ for (hb_arena_page_T* current_page = starting_page; current_page != NULL;) {
183
+ hb_arena_page_T* next_page = current_page->next;
184
+
185
+ freed_capacity += current_page->capacity;
186
+
187
+ size_t total_size = sizeof(hb_arena_page_T) + current_page->capacity;
188
+ hb_arena_free_page(current_page, total_size);
189
+
190
+ current_page = next_page;
162
191
  }
192
+
193
+ return freed_capacity;
163
194
  }
164
195
 
165
196
  void hb_arena_free(hb_arena_T* allocator) {
166
197
  if (allocator->head == NULL) { return; }
167
198
 
168
- for (hb_arena_page_T* current = allocator->head; current != NULL;) {
169
- hb_arena_page_T* next = current->next;
170
- size_t total_size = sizeof(hb_arena_page_T) + current->capacity;
171
- hb_system_free_memory(current, total_size);
172
-
173
- current = next;
174
- }
199
+ hb_arena_page_free(allocator->head);
175
200
 
176
201
  allocator->head = NULL;
177
202
  allocator->tail = NULL;
@@ -20,12 +20,17 @@ typedef struct HB_ARENA_STRUCT {
20
20
  size_t allocation_count;
21
21
  } hb_arena_T;
22
22
 
23
+ #define hb_arena_for_each_page(arena) for (hb_arena_page_T* page = (arena)->head; page != NULL; page = page->next)
24
+
25
+ #define hb_arena_for_each_page_const(arena) \
26
+ for (const hb_arena_page_T* page = (arena)->head; page != NULL; page = page->next)
27
+
23
28
  bool hb_arena_init(hb_arena_T* allocator, size_t initial_size);
24
29
  void* hb_arena_alloc(hb_arena_T* allocator, size_t size);
25
30
  size_t hb_arena_position(hb_arena_T* allocator);
26
31
  size_t hb_arena_capacity(hb_arena_T* allocator);
27
32
  void hb_arena_reset(hb_arena_T* allocator);
28
- void hb_arena_reset_to(hb_arena_T* allocator, size_t new_position);
33
+ void hb_arena_reset_to(hb_arena_T* allocator, size_t target_position);
29
34
  void hb_arena_free(hb_arena_T* allocator);
30
35
 
31
36
  #endif