herb 0.8.10-arm-linux-gnu → 0.9.0-arm-linux-gnu
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.
- checksums.yaml +4 -4
- data/Makefile +11 -3
- data/README.md +64 -34
- data/Rakefile +48 -40
- data/config.yml +317 -34
- data/ext/herb/error_helpers.c +367 -140
- data/ext/herb/error_helpers.h +1 -0
- data/ext/herb/extconf.rb +67 -28
- data/ext/herb/extension.c +317 -51
- data/ext/herb/extension.h +1 -0
- data/ext/herb/extension_helpers.c +23 -14
- data/ext/herb/extension_helpers.h +2 -2
- data/ext/herb/nodes.c +537 -270
- data/ext/herb/nodes.h +1 -0
- data/herb.gemspec +3 -2
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/4.0/herb.so +0 -0
- data/lib/herb/ast/helpers.rb +3 -3
- data/lib/herb/ast/node.rb +15 -2
- data/lib/herb/ast/nodes.rb +1132 -157
- data/lib/herb/bootstrap.rb +87 -0
- data/lib/herb/cli.rb +341 -31
- data/lib/herb/configuration.rb +248 -0
- data/lib/herb/defaults.yml +32 -0
- data/lib/herb/engine/compiler.rb +78 -11
- data/lib/herb/engine/debug_visitor.rb +13 -3
- data/lib/herb/engine/error_formatter.rb +13 -9
- data/lib/herb/engine/parser_error_overlay.rb +10 -6
- data/lib/herb/engine/validator.rb +8 -3
- data/lib/herb/engine/validators/nesting_validator.rb +2 -2
- data/lib/herb/engine.rb +82 -35
- data/lib/herb/errors.rb +563 -88
- data/lib/herb/lex_result.rb +1 -0
- data/lib/herb/location.rb +7 -3
- data/lib/herb/parse_result.rb +12 -2
- data/lib/herb/parser_options.rb +57 -0
- data/lib/herb/position.rb +1 -0
- data/lib/herb/prism_inspect.rb +116 -0
- data/lib/herb/project.rb +923 -331
- data/lib/herb/range.rb +1 -0
- data/lib/herb/token.rb +7 -1
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor.rb +37 -2
- data/lib/herb/warnings.rb +6 -1
- data/lib/herb.rb +35 -3
- data/sig/herb/ast/helpers.rbs +2 -2
- data/sig/herb/ast/node.rbs +12 -2
- data/sig/herb/ast/nodes.rbs +641 -128
- data/sig/herb/bootstrap.rbs +31 -0
- data/sig/herb/configuration.rbs +89 -0
- data/sig/herb/engine/compiler.rbs +9 -1
- data/sig/herb/engine/debug_visitor.rbs +2 -0
- data/sig/herb/engine/validator.rbs +5 -1
- data/sig/herb/engine.rbs +17 -3
- data/sig/herb/errors.rbs +258 -63
- data/sig/herb/location.rbs +4 -0
- data/sig/herb/parse_result.rbs +4 -2
- data/sig/herb/parser_options.rbs +42 -0
- data/sig/herb/position.rbs +1 -0
- data/sig/herb/prism_inspect.rbs +28 -0
- data/sig/herb/range.rbs +1 -0
- data/sig/herb/token.rbs +6 -0
- data/sig/herb/visitor.rbs +25 -4
- data/sig/herb/warnings.rbs +6 -1
- data/sig/herb.rbs +14 -0
- data/sig/herb_c_extension.rbs +5 -2
- data/sig/serialized_ast_errors.rbs +54 -6
- data/sig/serialized_ast_nodes.rbs +60 -6
- data/src/analyze/action_view/attribute_extraction_helpers.c +290 -0
- data/src/analyze/action_view/content_tag.c +70 -0
- data/src/analyze/action_view/link_to.c +143 -0
- data/src/analyze/action_view/registry.c +60 -0
- data/src/analyze/action_view/tag.c +64 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
- data/src/analyze/action_view/tag_helpers.c +748 -0
- data/src/analyze/action_view/turbo_frame_tag.c +88 -0
- data/src/analyze/analyze.c +882 -0
- data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
- data/src/analyze/builders.c +343 -0
- data/src/analyze/conditional_elements.c +594 -0
- data/src/analyze/conditional_open_tags.c +640 -0
- data/src/analyze/control_type.c +250 -0
- data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
- data/src/analyze/invalid_structures.c +193 -0
- data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
- data/src/analyze/parse_errors.c +84 -0
- data/src/analyze/prism_annotate.c +397 -0
- data/src/{analyze_transform.c → analyze/transform.c} +17 -3
- data/src/ast_node.c +17 -7
- data/src/ast_nodes.c +662 -387
- data/src/ast_pretty_print.c +190 -6
- data/src/errors.c +1076 -520
- data/src/extract.c +145 -49
- data/src/herb.c +52 -34
- data/src/html_util.c +241 -12
- data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
- data/src/include/analyze/action_view/tag_helper_handler.h +41 -0
- data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
- data/src/include/analyze/action_view/tag_helpers.h +38 -0
- data/src/include/{analyze.h → analyze/analyze.h} +14 -4
- data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- data/src/include/analyze/builders.h +27 -0
- data/src/include/analyze/conditional_elements.h +9 -0
- data/src/include/analyze/conditional_open_tags.h +9 -0
- data/src/include/analyze/control_type.h +14 -0
- data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
- data/src/include/analyze/invalid_structures.h +11 -0
- data/src/include/analyze/prism_annotate.h +16 -0
- data/src/include/ast_node.h +11 -5
- data/src/include/ast_nodes.h +117 -38
- data/src/include/ast_pretty_print.h +5 -0
- data/src/include/element_source.h +3 -8
- data/src/include/errors.h +148 -55
- data/src/include/extract.h +21 -5
- data/src/include/herb.h +18 -6
- data/src/include/herb_prism_node.h +13 -0
- data/src/include/html_util.h +7 -2
- data/src/include/io.h +3 -1
- data/src/include/lex_helpers.h +29 -0
- data/src/include/lexer.h +1 -1
- data/src/include/lexer_peek_helpers.h +87 -13
- data/src/include/lexer_struct.h +2 -0
- data/src/include/location.h +2 -1
- data/src/include/parser.h +27 -2
- data/src/include/parser_helpers.h +19 -3
- data/src/include/pretty_print.h +10 -5
- data/src/include/prism_context.h +45 -0
- data/src/include/prism_helpers.h +10 -7
- data/src/include/prism_serialized.h +12 -0
- data/src/include/token.h +16 -4
- data/src/include/token_struct.h +10 -3
- data/src/include/utf8.h +2 -1
- data/src/include/util/hb_allocator.h +78 -0
- data/src/include/util/hb_arena.h +6 -1
- data/src/include/util/hb_arena_debug.h +12 -1
- data/src/include/util/hb_array.h +7 -3
- data/src/include/util/hb_buffer.h +6 -4
- data/src/include/util/hb_foreach.h +79 -0
- data/src/include/util/hb_narray.h +8 -4
- data/src/include/util/hb_string.h +56 -9
- data/src/include/util.h +6 -3
- data/src/include/version.h +1 -1
- data/src/io.c +3 -2
- data/src/lexer.c +42 -30
- data/src/lexer_peek_helpers.c +12 -74
- data/src/location.c +2 -2
- data/src/main.c +53 -28
- data/src/parser.c +783 -247
- data/src/parser_helpers.c +110 -23
- data/src/parser_match_tags.c +109 -48
- data/src/pretty_print.c +29 -24
- data/src/prism_helpers.c +30 -27
- data/src/ruby_parser.c +2 -0
- data/src/token.c +151 -66
- data/src/token_matchers.c +0 -1
- data/src/utf8.c +7 -6
- data/src/util/hb_allocator.c +341 -0
- data/src/util/hb_arena.c +81 -56
- data/src/util/hb_arena_debug.c +32 -17
- data/src/util/hb_array.c +30 -15
- data/src/util/hb_buffer.c +17 -21
- data/src/util/hb_narray.c +22 -7
- data/src/util/hb_string.c +49 -35
- data/src/util.c +21 -11
- data/src/visitor.c +47 -0
- data/templates/ext/herb/error_helpers.c.erb +24 -11
- data/templates/ext/herb/error_helpers.h.erb +1 -0
- data/templates/ext/herb/nodes.c.erb +50 -16
- data/templates/ext/herb/nodes.h.erb +1 -0
- data/templates/java/error_helpers.c.erb +1 -1
- data/templates/java/nodes.c.erb +30 -8
- data/templates/java/org/herb/ast/Errors.java.erb +24 -1
- data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
- data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
- data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
- data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
- data/templates/lib/herb/ast/nodes.rb.erb +88 -31
- data/templates/lib/herb/errors.rb.erb +15 -3
- data/templates/lib/herb/visitor.rb.erb +2 -2
- data/templates/rust/src/ast/nodes.rs.erb +97 -44
- data/templates/rust/src/errors.rs.erb +2 -1
- data/templates/rust/src/nodes.rs.erb +167 -15
- data/templates/rust/src/union_types.rs.erb +60 -0
- data/templates/rust/src/visitor.rs.erb +81 -0
- data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
- data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
- data/templates/src/ast_nodes.c.erb +34 -26
- data/templates/src/ast_pretty_print.c.erb +24 -5
- data/templates/src/errors.c.erb +60 -54
- data/templates/src/include/ast_nodes.h.erb +6 -2
- data/templates/src/include/ast_pretty_print.h.erb +5 -0
- data/templates/src/include/errors.h.erb +15 -11
- data/templates/src/include/util/hb_foreach.h.erb +20 -0
- data/templates/src/parser_match_tags.c.erb +10 -4
- data/templates/src/visitor.c.erb +2 -2
- data/templates/template.rb +204 -29
- data/templates/wasm/error_helpers.cpp.erb +9 -5
- data/templates/wasm/nodes.cpp.erb +41 -4
- metadata +57 -16
- data/src/analyze.c +0 -1608
- data/src/element_source.c +0 -12
- data/src/include/util/hb_system.h +0 -9
- data/src/util/hb_system.c +0 -30
|
@@ -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
|
+
}
|
data/src/util/hb_arena.c
CHANGED
|
@@ -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;
|
data/src/util/hb_arena_debug.c
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <string.h>
|
|
4
4
|
|
|
5
5
|
#include "../include/util/hb_arena.h"
|
|
6
|
+
#include "../include/util/hb_arena_debug.h"
|
|
6
7
|
|
|
7
8
|
#define ANSI_COLOR_GREEN "\033[32m"
|
|
8
9
|
#define ANSI_COLOR_YELLOW "\033[33m"
|
|
@@ -117,6 +118,29 @@ static void print_box_line_with_bullet_and_color(const char* color, const char*
|
|
|
117
118
|
printf("║%s%*s║\n", line, BOX_WIDTH - visual_length, "");
|
|
118
119
|
}
|
|
119
120
|
|
|
121
|
+
hb_arena_stats_T hb_arena_get_stats(const hb_arena_T* arena) {
|
|
122
|
+
hb_arena_stats_T stats = { 0 };
|
|
123
|
+
|
|
124
|
+
if (arena->head == NULL) { return stats; }
|
|
125
|
+
|
|
126
|
+
stats.default_page_size = arena->default_page_size;
|
|
127
|
+
stats.allocations = arena->allocation_count;
|
|
128
|
+
|
|
129
|
+
hb_arena_for_each_page_const(arena) {
|
|
130
|
+
stats.pages++;
|
|
131
|
+
stats.total_capacity += page->capacity;
|
|
132
|
+
stats.total_used += page->position;
|
|
133
|
+
|
|
134
|
+
if (page != arena->tail && page->position < page->capacity) {
|
|
135
|
+
stats.fragmentation += (page->capacity - page->position);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
stats.total_available = stats.total_capacity - stats.total_used;
|
|
140
|
+
|
|
141
|
+
return stats;
|
|
142
|
+
}
|
|
143
|
+
|
|
120
144
|
void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
121
145
|
if (allocator->head == NULL) {
|
|
122
146
|
print_box_top();
|
|
@@ -128,22 +152,13 @@ void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
|
128
152
|
return;
|
|
129
153
|
}
|
|
130
154
|
|
|
131
|
-
|
|
132
|
-
size_t total_capacity = 0;
|
|
133
|
-
size_t total_used = 0;
|
|
134
|
-
size_t fragmentation = 0;
|
|
155
|
+
hb_arena_stats_T stats = hb_arena_get_stats(allocator);
|
|
135
156
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (page != allocator->tail && page->position < page->capacity) {
|
|
142
|
-
fragmentation += (page->capacity - page->position);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
157
|
+
size_t total_capacity = stats.total_capacity;
|
|
158
|
+
size_t total_used = stats.total_used;
|
|
159
|
+
size_t total_available = stats.total_available;
|
|
160
|
+
size_t fragmentation = stats.fragmentation;
|
|
145
161
|
|
|
146
|
-
size_t total_available = total_capacity - total_used;
|
|
147
162
|
double usage_percentage = (double) total_used / (double) total_capacity * 100.0;
|
|
148
163
|
double fragmentation_percentage = (double) fragmentation / (double) total_capacity * 100.0;
|
|
149
164
|
const char* overall_color = get_usage_color(usage_percentage);
|
|
@@ -160,7 +175,7 @@ void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
|
160
175
|
print_box_separator();
|
|
161
176
|
print_box_line(" Statistics:");
|
|
162
177
|
|
|
163
|
-
print_box_line_with_bullet(" • Pages: %zu",
|
|
178
|
+
print_box_line_with_bullet(" • Pages: %zu", stats.pages);
|
|
164
179
|
print_box_line_with_bullet(" • Default Page Size: %s", default_size_string);
|
|
165
180
|
print_box_line_with_bullet(" • Total Capacity: %s", capacity_string);
|
|
166
181
|
print_box_line_with_bullet_and_color(
|
|
@@ -178,7 +193,7 @@ void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
|
178
193
|
usage_percentage,
|
|
179
194
|
ANSI_COLOR_RESET
|
|
180
195
|
);
|
|
181
|
-
print_box_line_with_bullet(" • Allocations: %zu",
|
|
196
|
+
print_box_line_with_bullet(" • Allocations: %zu", stats.allocations);
|
|
182
197
|
print_box_line_with_bullet(" • Fragmentation: %s", fragmentation_string);
|
|
183
198
|
|
|
184
199
|
if (fragmentation > 0) { print_box_line(" (%.1f%% skipped in non-tail pages)", fragmentation_percentage); }
|
|
@@ -187,7 +202,7 @@ void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
|
187
202
|
|
|
188
203
|
size_t page_number = 0;
|
|
189
204
|
|
|
190
|
-
|
|
205
|
+
hb_arena_for_each_page_const(allocator) {
|
|
191
206
|
double page_usage = (double) page->position / (double) page->capacity * 100.0;
|
|
192
207
|
const char* page_color = get_usage_color(page_usage);
|
|
193
208
|
|