@herb-tools/node 0.8.10 → 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.
- package/CHANGELOG.md +19 -0
- package/binding.gyp +26 -8
- package/dist/herb-node.cjs +41 -12
- package/dist/herb-node.cjs.map +1 -1
- package/dist/herb-node.esm.js +8 -1
- package/dist/herb-node.esm.js.map +1 -1
- package/dist/types/node-backend.d.ts +3 -1
- package/extension/error_helpers.cpp +395 -73
- package/extension/error_helpers.h +13 -3
- package/extension/extension_helpers.cpp +38 -35
- package/extension/extension_helpers.h +2 -2
- package/extension/herb.cpp +183 -64
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +290 -0
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
- package/extension/libherb/analyze/action_view/content_tag.c +70 -0
- package/extension/libherb/analyze/action_view/link_to.c +143 -0
- package/extension/libherb/analyze/action_view/registry.c +60 -0
- package/extension/libherb/analyze/action_view/tag.c +64 -0
- package/extension/libherb/analyze/action_view/tag_helper_handler.h +41 -0
- package/extension/libherb/analyze/action_view/tag_helper_node_builders.c +305 -0
- package/extension/libherb/analyze/action_view/tag_helper_node_builders.h +70 -0
- package/extension/libherb/analyze/action_view/tag_helpers.c +748 -0
- package/extension/libherb/analyze/action_view/tag_helpers.h +38 -0
- package/extension/libherb/analyze/action_view/turbo_frame_tag.c +88 -0
- package/extension/libherb/analyze/analyze.c +882 -0
- package/extension/libherb/{include → analyze}/analyze.h +14 -4
- package/extension/libherb/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
- package/extension/libherb/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- package/extension/libherb/analyze/builders.c +343 -0
- package/extension/libherb/analyze/builders.h +27 -0
- package/extension/libherb/analyze/conditional_elements.c +594 -0
- package/extension/libherb/analyze/conditional_elements.h +9 -0
- package/extension/libherb/analyze/conditional_open_tags.c +640 -0
- package/extension/libherb/analyze/conditional_open_tags.h +9 -0
- package/extension/libherb/analyze/control_type.c +250 -0
- package/extension/libherb/analyze/control_type.h +14 -0
- package/extension/libherb/{analyze_helpers.c → analyze/helpers.c} +48 -23
- package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +4 -2
- package/extension/libherb/analyze/invalid_structures.c +193 -0
- package/extension/libherb/analyze/invalid_structures.h +11 -0
- package/extension/libherb/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
- package/extension/libherb/analyze/parse_errors.c +84 -0
- package/extension/libherb/analyze/prism_annotate.c +397 -0
- package/extension/libherb/analyze/prism_annotate.h +16 -0
- package/extension/libherb/{analyze_transform.c → analyze/transform.c} +17 -3
- package/extension/libherb/ast_node.c +17 -7
- package/extension/libherb/ast_node.h +11 -5
- package/extension/libherb/ast_nodes.c +663 -388
- package/extension/libherb/ast_nodes.h +118 -39
- package/extension/libherb/ast_pretty_print.c +191 -7
- package/extension/libherb/ast_pretty_print.h +6 -1
- package/extension/libherb/element_source.h +3 -8
- package/extension/libherb/errors.c +1077 -521
- package/extension/libherb/errors.h +149 -56
- package/extension/libherb/extract.c +145 -49
- package/extension/libherb/extract.h +21 -5
- package/extension/libherb/herb.c +52 -34
- package/extension/libherb/herb.h +18 -6
- package/extension/libherb/herb_prism_node.h +13 -0
- package/extension/libherb/html_util.c +241 -12
- package/extension/libherb/html_util.h +7 -2
- package/extension/libherb/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
- package/extension/libherb/include/analyze/action_view/tag_helper_handler.h +41 -0
- package/extension/libherb/include/analyze/action_view/tag_helper_node_builders.h +70 -0
- package/extension/libherb/include/analyze/action_view/tag_helpers.h +38 -0
- package/extension/libherb/{analyze.h → include/analyze/analyze.h} +14 -4
- package/extension/libherb/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- package/extension/libherb/include/analyze/builders.h +27 -0
- package/extension/libherb/include/analyze/conditional_elements.h +9 -0
- package/extension/libherb/include/analyze/conditional_open_tags.h +9 -0
- package/extension/libherb/include/analyze/control_type.h +14 -0
- package/extension/libherb/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
- package/extension/libherb/include/analyze/invalid_structures.h +11 -0
- package/extension/libherb/include/analyze/prism_annotate.h +16 -0
- package/extension/libherb/include/ast_node.h +11 -5
- package/extension/libherb/include/ast_nodes.h +118 -39
- package/extension/libherb/include/ast_pretty_print.h +6 -1
- package/extension/libherb/include/element_source.h +3 -8
- package/extension/libherb/include/errors.h +149 -56
- package/extension/libherb/include/extract.h +21 -5
- package/extension/libherb/include/herb.h +18 -6
- package/extension/libherb/include/herb_prism_node.h +13 -0
- package/extension/libherb/include/html_util.h +7 -2
- package/extension/libherb/include/io.h +3 -1
- package/extension/libherb/include/lex_helpers.h +29 -0
- package/extension/libherb/include/lexer.h +1 -1
- package/extension/libherb/include/lexer_peek_helpers.h +87 -13
- package/extension/libherb/include/lexer_struct.h +2 -0
- package/extension/libherb/include/location.h +2 -1
- package/extension/libherb/include/parser.h +27 -2
- package/extension/libherb/include/parser_helpers.h +19 -3
- package/extension/libherb/include/pretty_print.h +10 -5
- package/extension/libherb/include/prism_context.h +45 -0
- package/extension/libherb/include/prism_helpers.h +10 -7
- package/extension/libherb/include/prism_serialized.h +12 -0
- package/extension/libherb/include/token.h +16 -4
- package/extension/libherb/include/token_struct.h +10 -3
- package/extension/libherb/include/utf8.h +2 -1
- package/extension/libherb/include/util/hb_allocator.h +78 -0
- package/extension/libherb/include/util/hb_arena.h +6 -1
- package/extension/libherb/include/util/hb_arena_debug.h +12 -1
- package/extension/libherb/include/util/hb_array.h +7 -3
- package/extension/libherb/include/util/hb_buffer.h +6 -4
- package/extension/libherb/include/util/hb_foreach.h +79 -0
- package/extension/libherb/include/util/hb_narray.h +8 -4
- package/extension/libherb/include/util/hb_string.h +56 -9
- package/extension/libherb/include/util.h +6 -3
- package/extension/libherb/include/version.h +1 -1
- package/extension/libherb/io.c +3 -2
- package/extension/libherb/io.h +3 -1
- package/extension/libherb/lex_helpers.h +29 -0
- package/extension/libherb/lexer.c +42 -30
- package/extension/libherb/lexer.h +1 -1
- package/extension/libherb/lexer_peek_helpers.c +12 -74
- package/extension/libherb/lexer_peek_helpers.h +87 -13
- package/extension/libherb/lexer_struct.h +2 -0
- package/extension/libherb/location.c +2 -2
- package/extension/libherb/location.h +2 -1
- package/extension/libherb/main.c +53 -28
- package/extension/libherb/parser.c +783 -247
- package/extension/libherb/parser.h +27 -2
- package/extension/libherb/parser_helpers.c +110 -23
- package/extension/libherb/parser_helpers.h +19 -3
- package/extension/libherb/parser_match_tags.c +110 -49
- package/extension/libherb/pretty_print.c +29 -24
- package/extension/libherb/pretty_print.h +10 -5
- package/extension/libherb/prism_context.h +45 -0
- package/extension/libherb/prism_helpers.c +30 -27
- package/extension/libherb/prism_helpers.h +10 -7
- package/extension/libherb/prism_serialized.h +12 -0
- package/extension/libherb/ruby_parser.c +2 -0
- package/extension/libherb/token.c +151 -66
- package/extension/libherb/token.h +16 -4
- package/extension/libherb/token_matchers.c +0 -1
- package/extension/libherb/token_struct.h +10 -3
- package/extension/libherb/utf8.c +7 -6
- package/extension/libherb/utf8.h +2 -1
- package/extension/libherb/util/hb_allocator.c +341 -0
- package/extension/libherb/util/hb_allocator.h +78 -0
- package/extension/libherb/util/hb_arena.c +81 -56
- package/extension/libherb/util/hb_arena.h +6 -1
- package/extension/libherb/util/hb_arena_debug.c +32 -17
- package/extension/libherb/util/hb_arena_debug.h +12 -1
- package/extension/libherb/util/hb_array.c +30 -15
- package/extension/libherb/util/hb_array.h +7 -3
- package/extension/libherb/util/hb_buffer.c +17 -21
- package/extension/libherb/util/hb_buffer.h +6 -4
- package/extension/libherb/util/hb_foreach.h +79 -0
- package/extension/libherb/util/hb_narray.c +22 -7
- package/extension/libherb/util/hb_narray.h +8 -4
- package/extension/libherb/util/hb_string.c +49 -35
- package/extension/libherb/util/hb_string.h +56 -9
- package/extension/libherb/util.c +21 -11
- package/extension/libherb/util.h +6 -3
- package/extension/libherb/version.h +1 -1
- package/extension/libherb/visitor.c +48 -1
- package/extension/nodes.cpp +451 -6
- package/extension/nodes.h +8 -1
- package/package.json +12 -8
- package/src/node-backend.ts +11 -1
- package/dist/types/index-cjs.d.cts +0 -1
- package/extension/libherb/analyze.c +0 -1608
- package/extension/libherb/element_source.c +0 -12
- package/extension/libherb/include/util/hb_system.h +0 -9
- package/extension/libherb/util/hb_system.c +0 -30
- package/extension/libherb/util/hb_system.h +0 -9
- package/src/index-cjs.cts +0 -22
- /package/dist/types/{index-esm.d.mts → index.d.ts} +0 -0
- /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
|
-
#
|
|
11
|
-
|
|
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*
|
|
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
|
|
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
|
|
63
|
+
size_t page_size_with_meta_data = page_size + sizeof(hb_arena_page_T);
|
|
52
64
|
|
|
53
|
-
hb_arena_page_T* page =
|
|
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
|
-
|
|
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
|
|
76
|
-
assert(
|
|
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 =
|
|
94
|
+
allocator->default_page_size = default_page_size;
|
|
81
95
|
allocator->allocation_count = 0;
|
|
82
96
|
|
|
83
|
-
return hb_arena_append_page(allocator,
|
|
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
|
|
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
|
|
115
|
+
return hb_arena_page_alloc(allocator->tail, required_size);
|
|
102
116
|
}
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
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
|
-
|
|
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
|
-
|
|
167
|
+
if (current_page == NULL) { return; }
|
|
149
168
|
|
|
150
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
161
|
-
|
|
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
|
-
|
|
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
|
|
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
|