@herb-tools/node 0.7.4 → 0.8.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/binding.gyp +8 -5
- package/dist/herb-node.esm.js +6 -6
- package/dist/herb-node.esm.js.map +1 -1
- package/extension/error_helpers.cpp +67 -9
- package/extension/error_helpers.h +4 -2
- package/extension/extension_helpers.cpp +20 -31
- package/extension/extension_helpers.h +7 -5
- package/extension/herb.cpp +10 -42
- package/extension/libherb/analyze.c +461 -249
- package/extension/libherb/analyze.h +10 -2
- package/extension/libherb/analyze_helpers.c +5 -0
- package/extension/libherb/analyze_helpers.h +3 -0
- package/extension/libherb/analyze_missing_end.c +147 -0
- package/extension/libherb/analyze_transform.c +196 -0
- package/extension/libherb/analyzed_ruby.c +23 -2
- package/extension/libherb/analyzed_ruby.h +4 -2
- package/extension/libherb/ast_node.c +14 -17
- package/extension/libherb/ast_node.h +4 -4
- package/extension/libherb/ast_nodes.c +180 -182
- package/extension/libherb/ast_nodes.h +69 -68
- package/extension/libherb/ast_pretty_print.c +233 -233
- package/extension/libherb/ast_pretty_print.h +3 -3
- package/extension/libherb/element_source.c +7 -6
- package/extension/libherb/element_source.h +3 -1
- package/extension/libherb/errors.c +273 -153
- package/extension/libherb/errors.h +43 -27
- package/extension/libherb/extract.c +92 -34
- package/extension/libherb/extract.h +4 -4
- package/extension/libherb/herb.c +37 -49
- package/extension/libherb/herb.h +6 -7
- package/extension/libherb/html_util.c +34 -96
- package/extension/libherb/html_util.h +4 -5
- package/extension/libherb/include/analyze.h +10 -2
- package/extension/libherb/include/analyze_helpers.h +3 -0
- package/extension/libherb/include/analyzed_ruby.h +4 -2
- package/extension/libherb/include/ast_node.h +4 -4
- package/extension/libherb/include/ast_nodes.h +69 -68
- package/extension/libherb/include/ast_pretty_print.h +3 -3
- package/extension/libherb/include/element_source.h +3 -1
- package/extension/libherb/include/errors.h +43 -27
- package/extension/libherb/include/extract.h +4 -4
- package/extension/libherb/include/herb.h +6 -7
- package/extension/libherb/include/html_util.h +4 -5
- package/extension/libherb/include/lexer.h +1 -3
- package/extension/libherb/include/lexer_peek_helpers.h +21 -19
- package/extension/libherb/include/lexer_struct.h +12 -10
- package/extension/libherb/include/location.h +10 -13
- package/extension/libherb/include/macros.h +4 -0
- package/extension/libherb/include/parser.h +12 -6
- package/extension/libherb/include/parser_helpers.h +26 -16
- package/extension/libherb/include/position.h +3 -14
- package/extension/libherb/include/pretty_print.h +38 -28
- package/extension/libherb/include/prism_helpers.h +1 -1
- package/extension/libherb/include/range.h +4 -13
- package/extension/libherb/include/token.h +5 -11
- package/extension/libherb/include/token_struct.h +2 -2
- package/extension/libherb/include/utf8.h +3 -2
- package/extension/libherb/include/util/hb_arena.h +31 -0
- package/extension/libherb/include/util/hb_arena_debug.h +8 -0
- package/extension/libherb/include/util/hb_array.h +33 -0
- package/extension/libherb/include/util/hb_buffer.h +34 -0
- package/extension/libherb/include/util/hb_string.h +29 -0
- package/extension/libherb/include/util/hb_system.h +9 -0
- package/extension/libherb/include/util.h +3 -14
- package/extension/libherb/include/version.h +1 -1
- package/extension/libherb/include/visitor.h +1 -1
- package/extension/libherb/io.c +7 -4
- package/extension/libherb/lexer.c +62 -88
- package/extension/libherb/lexer.h +1 -3
- package/extension/libherb/lexer_peek_helpers.c +42 -38
- package/extension/libherb/lexer_peek_helpers.h +21 -19
- package/extension/libherb/lexer_struct.h +12 -10
- package/extension/libherb/location.c +9 -37
- package/extension/libherb/location.h +10 -13
- package/extension/libherb/macros.h +4 -0
- package/extension/libherb/main.c +19 -23
- package/extension/libherb/parser.c +373 -313
- package/extension/libherb/parser.h +12 -6
- package/extension/libherb/parser_helpers.c +60 -54
- package/extension/libherb/parser_helpers.h +26 -16
- package/extension/libherb/parser_match_tags.c +316 -0
- package/extension/libherb/position.h +3 -14
- package/extension/libherb/pretty_print.c +88 -117
- package/extension/libherb/pretty_print.h +38 -28
- package/extension/libherb/prism_helpers.c +7 -7
- package/extension/libherb/prism_helpers.h +1 -1
- package/extension/libherb/range.c +2 -35
- package/extension/libherb/range.h +4 -13
- package/extension/libherb/token.c +36 -87
- package/extension/libherb/token.h +5 -11
- package/extension/libherb/token_struct.h +2 -2
- package/extension/libherb/utf8.c +4 -4
- package/extension/libherb/utf8.h +3 -2
- package/extension/libherb/util/hb_arena.c +179 -0
- package/extension/libherb/util/hb_arena.h +31 -0
- package/extension/libherb/util/hb_arena_debug.c +237 -0
- package/extension/libherb/util/hb_arena_debug.h +8 -0
- package/extension/libherb/{array.c → util/hb_array.c} +26 -27
- package/extension/libherb/util/hb_array.h +33 -0
- package/extension/libherb/util/hb_buffer.c +203 -0
- package/extension/libherb/util/hb_buffer.h +34 -0
- package/extension/libherb/util/hb_string.c +85 -0
- package/extension/libherb/util/hb_string.h +29 -0
- package/extension/libherb/util/hb_system.c +30 -0
- package/extension/libherb/util/hb_system.h +9 -0
- package/extension/libherb/util.c +29 -99
- package/extension/libherb/util.h +3 -14
- package/extension/libherb/version.h +1 -1
- package/extension/libherb/visitor.c +55 -55
- package/extension/libherb/visitor.h +1 -1
- package/extension/nodes.cpp +40 -40
- package/extension/nodes.h +2 -2
- package/extension/prism/include/prism/ast.h +31 -1
- package/extension/prism/include/prism/diagnostic.h +1 -0
- package/extension/prism/include/prism/version.h +3 -3
- package/extension/prism/src/diagnostic.c +3 -1
- package/extension/prism/src/prism.c +130 -71
- package/extension/prism/src/util/pm_string.c +6 -8
- package/package.json +3 -3
- package/extension/libherb/array.h +0 -33
- package/extension/libherb/buffer.c +0 -232
- package/extension/libherb/buffer.h +0 -39
- package/extension/libherb/include/array.h +0 -33
- package/extension/libherb/include/buffer.h +0 -39
- package/extension/libherb/include/json.h +0 -28
- package/extension/libherb/include/memory.h +0 -12
- package/extension/libherb/json.c +0 -205
- package/extension/libherb/json.h +0 -28
- package/extension/libherb/memory.c +0 -53
- package/extension/libherb/memory.h +0 -12
- package/extension/libherb/position.c +0 -33
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#include <stdarg.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
|
|
5
|
+
#include "../include/util/hb_arena.h"
|
|
6
|
+
|
|
7
|
+
#define ANSI_COLOR_GREEN "\033[32m"
|
|
8
|
+
#define ANSI_COLOR_YELLOW "\033[33m"
|
|
9
|
+
#define ANSI_COLOR_RED "\033[31m"
|
|
10
|
+
#define ANSI_COLOR_RESET "\033[0m"
|
|
11
|
+
|
|
12
|
+
#define UTF8_BULLET_OVERHEAD 2
|
|
13
|
+
#define BOX_WIDTH 100
|
|
14
|
+
|
|
15
|
+
static const char* get_usage_color(double percentage) {
|
|
16
|
+
if (percentage >= 90.0) {
|
|
17
|
+
return ANSI_COLOR_RED;
|
|
18
|
+
} else if (percentage >= 70.0) {
|
|
19
|
+
return ANSI_COLOR_YELLOW;
|
|
20
|
+
} else {
|
|
21
|
+
return ANSI_COLOR_GREEN;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static void format_bytes(size_t bytes, char* buffer, size_t buffer_size) {
|
|
26
|
+
if (bytes >= 1024 * 1024) {
|
|
27
|
+
snprintf(buffer, buffer_size, "%.2f MB", bytes / (1024.0 * 1024.0));
|
|
28
|
+
} else if (bytes >= 1024) {
|
|
29
|
+
snprintf(buffer, buffer_size, "%zu KB", bytes / 1024);
|
|
30
|
+
} else {
|
|
31
|
+
snprintf(buffer, buffer_size, "%zu B", bytes);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static void print_progress_bar(size_t used, size_t capacity, int width, const char* color) {
|
|
36
|
+
int filled = (int) ((double) used / (double) capacity * width);
|
|
37
|
+
|
|
38
|
+
printf("%s[", color);
|
|
39
|
+
|
|
40
|
+
for (int i = 0; i < width; i++) {
|
|
41
|
+
if (i < filled) {
|
|
42
|
+
printf("█");
|
|
43
|
+
} else {
|
|
44
|
+
printf("░");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
printf("]%s", ANSI_COLOR_RESET);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void print_box_top(void) {
|
|
52
|
+
printf("╔");
|
|
53
|
+
for (int i = 0; i < BOX_WIDTH; i++) {
|
|
54
|
+
printf("═");
|
|
55
|
+
}
|
|
56
|
+
printf("╗\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static void print_box_separator(void) {
|
|
60
|
+
printf("╠");
|
|
61
|
+
for (int i = 0; i < BOX_WIDTH; i++) {
|
|
62
|
+
printf("═");
|
|
63
|
+
}
|
|
64
|
+
printf("╣\n");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static void print_box_bottom(void) {
|
|
68
|
+
printf("╚");
|
|
69
|
+
for (int i = 0; i < BOX_WIDTH; i++) {
|
|
70
|
+
printf("═");
|
|
71
|
+
}
|
|
72
|
+
printf("╝\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static void print_box_line(const char* format, ...) {
|
|
76
|
+
char line[256];
|
|
77
|
+
va_list args;
|
|
78
|
+
va_start(args, format);
|
|
79
|
+
int length = vsnprintf(line, sizeof(line), format, args);
|
|
80
|
+
va_end(args);
|
|
81
|
+
|
|
82
|
+
printf("║%s%*s║\n", line, BOX_WIDTH - length, "");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static void print_box_line_centered(const char* format, ...) {
|
|
86
|
+
char line[256];
|
|
87
|
+
va_list args;
|
|
88
|
+
va_start(args, format);
|
|
89
|
+
int length = vsnprintf(line, sizeof(line), format, args);
|
|
90
|
+
va_end(args);
|
|
91
|
+
|
|
92
|
+
int total_padding = BOX_WIDTH - length;
|
|
93
|
+
int left_padding = total_padding / 2;
|
|
94
|
+
int right_padding = total_padding - left_padding;
|
|
95
|
+
|
|
96
|
+
printf("║%*s%s%*s║\n", left_padding, "", line, right_padding, "");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static void print_box_line_with_bullet(const char* format, ...) {
|
|
100
|
+
char line[256];
|
|
101
|
+
va_list args;
|
|
102
|
+
va_start(args, format);
|
|
103
|
+
int length = vsnprintf(line, sizeof(line), format, args);
|
|
104
|
+
va_end(args);
|
|
105
|
+
|
|
106
|
+
printf("║%s%*s║\n", line, BOX_WIDTH - (length - UTF8_BULLET_OVERHEAD), "");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void print_box_line_with_bullet_and_color(const char* color, const char* format, ...) {
|
|
110
|
+
char line[256];
|
|
111
|
+
va_list args;
|
|
112
|
+
va_start(args, format);
|
|
113
|
+
int length = vsnprintf(line, sizeof(line), format, args);
|
|
114
|
+
va_end(args);
|
|
115
|
+
|
|
116
|
+
int visual_length = length - UTF8_BULLET_OVERHEAD - (int) strlen(color) - (int) strlen(ANSI_COLOR_RESET);
|
|
117
|
+
printf("║%s%*s║\n", line, BOX_WIDTH - visual_length, "");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void hb_arena_print_stats(const hb_arena_T* allocator) {
|
|
121
|
+
if (allocator->head == NULL) {
|
|
122
|
+
print_box_top();
|
|
123
|
+
print_box_line_centered("ARENA MEMORY LAYOUT");
|
|
124
|
+
print_box_separator();
|
|
125
|
+
print_box_line(" Arena is empty (not initialized)");
|
|
126
|
+
print_box_bottom();
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
size_t num_pages = 0;
|
|
132
|
+
size_t total_capacity = 0;
|
|
133
|
+
size_t total_used = 0;
|
|
134
|
+
size_t fragmentation = 0;
|
|
135
|
+
|
|
136
|
+
for (const hb_arena_page_T* page = allocator->head; page != NULL; page = page->next) {
|
|
137
|
+
num_pages++;
|
|
138
|
+
total_capacity += page->capacity;
|
|
139
|
+
total_used += page->position;
|
|
140
|
+
|
|
141
|
+
if (page != allocator->tail && page->position < page->capacity) {
|
|
142
|
+
fragmentation += (page->capacity - page->position);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
size_t total_available = total_capacity - total_used;
|
|
147
|
+
double usage_percentage = (double) total_used / (double) total_capacity * 100.0;
|
|
148
|
+
double fragmentation_percentage = (double) fragmentation / (double) total_capacity * 100.0;
|
|
149
|
+
const char* overall_color = get_usage_color(usage_percentage);
|
|
150
|
+
|
|
151
|
+
char capacity_string[32], used_string[32], available_string[32], fragmentation_string[32], default_size_string[32];
|
|
152
|
+
format_bytes(total_capacity, capacity_string, sizeof(capacity_string));
|
|
153
|
+
format_bytes(total_used, used_string, sizeof(used_string));
|
|
154
|
+
format_bytes(total_available, available_string, sizeof(available_string));
|
|
155
|
+
format_bytes(fragmentation, fragmentation_string, sizeof(fragmentation_string));
|
|
156
|
+
format_bytes(allocator->default_page_size, default_size_string, sizeof(default_size_string));
|
|
157
|
+
|
|
158
|
+
print_box_top();
|
|
159
|
+
print_box_line_centered("ARENA MEMORY LAYOUT");
|
|
160
|
+
print_box_separator();
|
|
161
|
+
print_box_line(" Statistics:");
|
|
162
|
+
|
|
163
|
+
print_box_line_with_bullet(" • Pages: %zu", num_pages);
|
|
164
|
+
print_box_line_with_bullet(" • Default Page Size: %s", default_size_string);
|
|
165
|
+
print_box_line_with_bullet(" • Total Capacity: %s", capacity_string);
|
|
166
|
+
print_box_line_with_bullet_and_color(
|
|
167
|
+
overall_color,
|
|
168
|
+
" • Total Used: %s%s%s",
|
|
169
|
+
overall_color,
|
|
170
|
+
used_string,
|
|
171
|
+
ANSI_COLOR_RESET
|
|
172
|
+
);
|
|
173
|
+
print_box_line_with_bullet(" • Total Available: %s", available_string);
|
|
174
|
+
print_box_line_with_bullet_and_color(
|
|
175
|
+
overall_color,
|
|
176
|
+
" • Usage: %s%.1f%%%s",
|
|
177
|
+
overall_color,
|
|
178
|
+
usage_percentage,
|
|
179
|
+
ANSI_COLOR_RESET
|
|
180
|
+
);
|
|
181
|
+
print_box_line_with_bullet(" • Allocations: %zu", allocator->allocation_count);
|
|
182
|
+
print_box_line_with_bullet(" • Fragmentation: %s", fragmentation_string);
|
|
183
|
+
|
|
184
|
+
if (fragmentation > 0) { print_box_line(" (%.1f%% skipped in non-tail pages)", fragmentation_percentage); }
|
|
185
|
+
|
|
186
|
+
print_box_separator();
|
|
187
|
+
|
|
188
|
+
size_t page_number = 0;
|
|
189
|
+
|
|
190
|
+
for (const hb_arena_page_T* page = allocator->head; page != NULL; page = page->next) {
|
|
191
|
+
double page_usage = (double) page->position / (double) page->capacity * 100.0;
|
|
192
|
+
const char* page_color = get_usage_color(page_usage);
|
|
193
|
+
|
|
194
|
+
char page_capacity_string[32], page_used_string[32];
|
|
195
|
+
format_bytes(page->capacity, page_capacity_string, sizeof(page_capacity_string));
|
|
196
|
+
format_bytes(page->position, page_used_string, sizeof(page_used_string));
|
|
197
|
+
|
|
198
|
+
if (page == allocator->tail) {
|
|
199
|
+
char header_line[256];
|
|
200
|
+
snprintf(header_line, sizeof(header_line), " Page %zu @ %p ← CURRENT", page_number, (void*) page);
|
|
201
|
+
int visual_length = (int) strlen(header_line) - 2;
|
|
202
|
+
printf("║%s%*s║\n", header_line, BOX_WIDTH - visual_length, "");
|
|
203
|
+
} else {
|
|
204
|
+
print_box_line(" Page %zu @ %p", page_number, (void*) page);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
char stats_line[128];
|
|
208
|
+
int stats_length =
|
|
209
|
+
snprintf(stats_line, sizeof(stats_line), "%s / %s (%.0f%%)", page_used_string, page_capacity_string, page_usage);
|
|
210
|
+
|
|
211
|
+
int bar_width = BOX_WIDTH - 4 - 2 - 2 - stats_length - 1;
|
|
212
|
+
int bar_with_brackets = bar_width + 2;
|
|
213
|
+
|
|
214
|
+
printf("║ ");
|
|
215
|
+
print_progress_bar(page->position, page->capacity, bar_width, page_color);
|
|
216
|
+
printf(" %s %*s║\n", stats_line, BOX_WIDTH - 4 - bar_with_brackets - 2 - stats_length - 1, "");
|
|
217
|
+
|
|
218
|
+
size_t unused = page->capacity - page->position;
|
|
219
|
+
|
|
220
|
+
if (unused > 0) {
|
|
221
|
+
char unused_string[32];
|
|
222
|
+
format_bytes(unused, unused_string, sizeof(unused_string));
|
|
223
|
+
|
|
224
|
+
if (page == allocator->tail) {
|
|
225
|
+
print_box_line(" Unused: %s (available for allocations)", unused_string);
|
|
226
|
+
} else {
|
|
227
|
+
print_box_line(" Unused: %s", unused_string);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
printf("║%*s║\n", BOX_WIDTH, "");
|
|
232
|
+
|
|
233
|
+
page_number++;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
print_box_bottom();
|
|
237
|
+
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
#include <stdint.h>
|
|
2
2
|
#include <stdio.h>
|
|
3
3
|
|
|
4
|
-
#include "include/
|
|
5
|
-
#include "include/
|
|
6
|
-
#include "include/memory.h"
|
|
4
|
+
#include "../include/macros.h"
|
|
5
|
+
#include "../include/util/hb_array.h"
|
|
7
6
|
|
|
8
|
-
size_t
|
|
9
|
-
return sizeof(
|
|
7
|
+
size_t hb_array_sizeof(void) {
|
|
8
|
+
return sizeof(hb_array_T);
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
hb_array_T* hb_array_init(const size_t capacity) {
|
|
12
|
+
hb_array_T* array = malloc(hb_array_sizeof());
|
|
14
13
|
|
|
15
14
|
array->size = 0;
|
|
16
15
|
array->capacity = capacity;
|
|
17
|
-
array->items =
|
|
16
|
+
array->items = malloc(capacity * sizeof(void*));
|
|
18
17
|
|
|
19
18
|
if (!array->items) {
|
|
20
19
|
free(array);
|
|
@@ -24,7 +23,7 @@ array_T* array_init(const size_t capacity) {
|
|
|
24
23
|
return array;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
void
|
|
26
|
+
void hb_array_append(hb_array_T* array, void* item) {
|
|
28
27
|
if (array->size >= array->capacity) {
|
|
29
28
|
size_t new_capacity;
|
|
30
29
|
|
|
@@ -45,7 +44,7 @@ void array_append(array_T* array, void* item) {
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
size_t new_size_bytes = new_capacity * sizeof(void*);
|
|
48
|
-
void* new_items =
|
|
47
|
+
void* new_items = realloc(array->items, new_size_bytes);
|
|
49
48
|
|
|
50
49
|
if (unlikely(new_items == NULL)) { return; }
|
|
51
50
|
|
|
@@ -57,29 +56,29 @@ void array_append(array_T* array, void* item) {
|
|
|
57
56
|
array->size++;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
void*
|
|
59
|
+
void* hb_array_get(const hb_array_T* array, const size_t index) {
|
|
61
60
|
if (index >= array->size) { return NULL; }
|
|
62
61
|
|
|
63
62
|
return array->items[index];
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
void*
|
|
65
|
+
void* hb_array_first(hb_array_T* array) {
|
|
67
66
|
if (!array || array->size == 0) { return NULL; }
|
|
68
67
|
return array->items[0];
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
void*
|
|
70
|
+
void* hb_array_last(hb_array_T* array) {
|
|
72
71
|
if (!array || array->size == 0) { return NULL; }
|
|
73
72
|
return array->items[array->size - 1];
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
void
|
|
75
|
+
void hb_array_set(const hb_array_T* array, const size_t index, void* item) {
|
|
77
76
|
if (index >= array->size) { return; }
|
|
78
77
|
|
|
79
78
|
array->items[index] = item;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
void
|
|
81
|
+
void hb_array_remove(hb_array_T* array, const size_t index) {
|
|
83
82
|
if (index >= array->size) { return; }
|
|
84
83
|
|
|
85
84
|
for (size_t i = index; i < array->size - 1; i++) {
|
|
@@ -89,7 +88,7 @@ void array_remove(array_T* array, const size_t index) {
|
|
|
89
88
|
array->size--;
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
size_t
|
|
91
|
+
size_t hb_array_index_of(hb_array_T* array, void* item) {
|
|
93
92
|
for (size_t i = 0; i < array->size; i++) {
|
|
94
93
|
if (array->items[i] == item) { return i; }
|
|
95
94
|
}
|
|
@@ -97,37 +96,37 @@ size_t array_index_of(array_T* array, void* item) {
|
|
|
97
96
|
return SIZE_MAX;
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
void
|
|
101
|
-
size_t index =
|
|
99
|
+
void hb_array_remove_item(hb_array_T* array, void* item) {
|
|
100
|
+
size_t index = hb_array_index_of(array, item);
|
|
102
101
|
|
|
103
|
-
if (index != SIZE_MAX) {
|
|
102
|
+
if (index != SIZE_MAX) { hb_array_remove(array, index); }
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
// Alias for
|
|
107
|
-
void
|
|
108
|
-
|
|
105
|
+
// Alias for hb_array_append
|
|
106
|
+
void hb_array_push(hb_array_T* array, void* item) {
|
|
107
|
+
hb_array_append(array, item);
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
void*
|
|
110
|
+
void* hb_array_pop(hb_array_T* array) {
|
|
112
111
|
if (!array || array->size == 0) { return NULL; }
|
|
113
112
|
|
|
114
|
-
void* last_item =
|
|
113
|
+
void* last_item = hb_array_last(array);
|
|
115
114
|
array->size--;
|
|
116
115
|
|
|
117
116
|
return last_item;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
size_t
|
|
119
|
+
size_t hb_array_size(const hb_array_T* array) {
|
|
121
120
|
if (array == NULL) { return 0; }
|
|
122
121
|
|
|
123
122
|
return array->size;
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
size_t
|
|
125
|
+
size_t hb_array_capacity(const hb_array_T* array) {
|
|
127
126
|
return array->capacity;
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
void
|
|
129
|
+
void hb_array_free(hb_array_T** array) {
|
|
131
130
|
if (!array || !*array) { return; }
|
|
132
131
|
|
|
133
132
|
free((*array)->items);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#ifndef HERB_ARRAY_H
|
|
2
|
+
#define HERB_ARRAY_H
|
|
3
|
+
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
|
|
6
|
+
typedef struct HB_ARRAY_STRUCT {
|
|
7
|
+
void** items;
|
|
8
|
+
size_t size;
|
|
9
|
+
size_t capacity;
|
|
10
|
+
} hb_array_T;
|
|
11
|
+
|
|
12
|
+
hb_array_T* hb_array_init(size_t capacity);
|
|
13
|
+
|
|
14
|
+
void* hb_array_get(const hb_array_T* array, size_t index);
|
|
15
|
+
void* hb_array_first(hb_array_T* array);
|
|
16
|
+
void* hb_array_last(hb_array_T* array);
|
|
17
|
+
|
|
18
|
+
void hb_array_append(hb_array_T* array, void* item);
|
|
19
|
+
void hb_array_set(const hb_array_T* array, size_t index, void* item);
|
|
20
|
+
void hb_array_free(hb_array_T** array);
|
|
21
|
+
void hb_array_remove(hb_array_T* array, size_t index);
|
|
22
|
+
|
|
23
|
+
size_t hb_array_index_of(hb_array_T* array, void* item);
|
|
24
|
+
void hb_array_remove_item(hb_array_T* array, void* item);
|
|
25
|
+
|
|
26
|
+
void hb_array_push(hb_array_T* array, void* item);
|
|
27
|
+
void* hb_array_pop(hb_array_T* array);
|
|
28
|
+
|
|
29
|
+
size_t hb_array_capacity(const hb_array_T* array);
|
|
30
|
+
size_t hb_array_size(const hb_array_T* array);
|
|
31
|
+
size_t hb_array_sizeof(void);
|
|
32
|
+
|
|
33
|
+
#endif
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#include <stdint.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
|
|
5
|
+
#include "../include/macros.h"
|
|
6
|
+
#include "../include/util.h"
|
|
7
|
+
#include "../include/util/hb_buffer.h"
|
|
8
|
+
|
|
9
|
+
static bool hb_buffer_has_capacity(hb_buffer_T* buffer, const size_t required_length) {
|
|
10
|
+
return (buffer->length + required_length <= buffer->capacity);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resizes the capacity of the buffer to the specified new capacity.
|
|
15
|
+
*
|
|
16
|
+
* @param buffer The buffer to resize
|
|
17
|
+
* @param new_capacity The new capacity to resize the buffer to
|
|
18
|
+
* @return true if capacity was resized, false if reallocation failed
|
|
19
|
+
*/
|
|
20
|
+
static bool hb_buffer_resize(hb_buffer_T* buffer, const size_t new_capacity) {
|
|
21
|
+
if (new_capacity + 1 >= SIZE_MAX) {
|
|
22
|
+
fprintf(stderr, "Error: Buffer capacity would overflow system limits.\n");
|
|
23
|
+
exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
char* new_value = realloc(buffer->value, new_capacity + 1);
|
|
27
|
+
|
|
28
|
+
if (unlikely(new_value == NULL)) {
|
|
29
|
+
fprintf(stderr, "Error: Failed to resize buffer to %zu.\n", new_capacity);
|
|
30
|
+
exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
buffer->value = new_value;
|
|
34
|
+
buffer->capacity = new_capacity;
|
|
35
|
+
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Expands the capacity of the buffer if needed to accommodate additional content.
|
|
41
|
+
* This function is a convenience function that calls hb_buffer_has_capacity and
|
|
42
|
+
* hb_buffer_expand_capacity.
|
|
43
|
+
*
|
|
44
|
+
* @param buffer The buffer to expand capacity for
|
|
45
|
+
* @param required_length The additional length needed beyond current buffer capacity
|
|
46
|
+
* @return true if capacity was increased, false if reallocation failed
|
|
47
|
+
*/
|
|
48
|
+
static bool hb_buffer_expand_if_needed(hb_buffer_T* buffer, const size_t required_length) {
|
|
49
|
+
if (hb_buffer_has_capacity(buffer, required_length)) { return true; }
|
|
50
|
+
|
|
51
|
+
bool should_double_capacity = required_length < buffer->capacity;
|
|
52
|
+
size_t new_capacity = 0;
|
|
53
|
+
|
|
54
|
+
if (should_double_capacity) {
|
|
55
|
+
new_capacity = buffer->capacity * 2;
|
|
56
|
+
} else {
|
|
57
|
+
new_capacity = buffer->capacity + (required_length * 2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return hb_buffer_resize(buffer, new_capacity);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
bool hb_buffer_init(hb_buffer_T* buffer, const size_t capacity) {
|
|
64
|
+
buffer->capacity = capacity;
|
|
65
|
+
buffer->length = 0;
|
|
66
|
+
buffer->value = malloc(sizeof(char) * (buffer->capacity + 1));
|
|
67
|
+
|
|
68
|
+
if (!buffer->value) {
|
|
69
|
+
fprintf(stderr, "Error: Failed to initialize buffer with capacity of %zu.\n", buffer->capacity);
|
|
70
|
+
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
buffer->value[0] = '\0';
|
|
75
|
+
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
char* hb_buffer_value(const hb_buffer_T* buffer) {
|
|
80
|
+
return buffer->value;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
size_t hb_buffer_length(const hb_buffer_T* buffer) {
|
|
84
|
+
return buffer->length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
size_t hb_buffer_capacity(const hb_buffer_T* buffer) {
|
|
88
|
+
return buffer->capacity;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
size_t hb_buffer_sizeof(void) {
|
|
92
|
+
return sizeof(hb_buffer_T);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Appends a null-terminated string to the buffer.
|
|
97
|
+
* @note This function requires that 'text' is a properly null-terminated string.
|
|
98
|
+
* When reading data from files or other non-string sources, ensure the data is
|
|
99
|
+
* null-terminated before calling this function, or use hb_buffer_append_with_length instead.
|
|
100
|
+
*
|
|
101
|
+
* @param buffer The buffer to append to
|
|
102
|
+
* @param text A null-terminated string to append
|
|
103
|
+
* @return void
|
|
104
|
+
*/
|
|
105
|
+
void hb_buffer_append(hb_buffer_T* buffer, const char* text) {
|
|
106
|
+
if (!buffer || !text) { return; }
|
|
107
|
+
if (text[0] == '\0') { return; }
|
|
108
|
+
|
|
109
|
+
size_t text_length = strlen(text);
|
|
110
|
+
|
|
111
|
+
if (!hb_buffer_expand_if_needed(buffer, text_length)) { return; }
|
|
112
|
+
|
|
113
|
+
memcpy(buffer->value + buffer->length, text, text_length);
|
|
114
|
+
buffer->length += text_length;
|
|
115
|
+
buffer->value[buffer->length] = '\0';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Appends a string of specified length to the buffer.
|
|
120
|
+
* Unlike hb_buffer_append(), this function does not require the text to be
|
|
121
|
+
* null-terminated as it uses the provided length instead of strlen().
|
|
122
|
+
* This is particularly useful when working with data from files, network
|
|
123
|
+
* buffers, or other non-null-terminated sources.
|
|
124
|
+
*
|
|
125
|
+
* @param buffer The buffer to append to
|
|
126
|
+
* @param text The text to append (doesn't need to be null-terminated)
|
|
127
|
+
* @param length The number of bytes to append from text
|
|
128
|
+
* @return void
|
|
129
|
+
*/
|
|
130
|
+
void hb_buffer_append_with_length(hb_buffer_T* buffer, const char* text, const size_t length) {
|
|
131
|
+
if (!buffer || !text || length == 0) { return; }
|
|
132
|
+
if (!hb_buffer_expand_if_needed(buffer, length)) { return; }
|
|
133
|
+
|
|
134
|
+
memcpy(buffer->value + buffer->length, text, length);
|
|
135
|
+
|
|
136
|
+
buffer->length += length;
|
|
137
|
+
buffer->value[buffer->length] = '\0';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void hb_buffer_append_string(hb_buffer_T* buffer, hb_string_T string) {
|
|
141
|
+
if (!hb_string_is_empty(string)) { hb_buffer_append_with_length(buffer, string.data, string.length); }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
void hb_buffer_append_char(hb_buffer_T* buffer, const char character) {
|
|
145
|
+
char string[2];
|
|
146
|
+
|
|
147
|
+
string[0] = character;
|
|
148
|
+
string[1] = '\0';
|
|
149
|
+
|
|
150
|
+
hb_buffer_append(buffer, string);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static void hb_buffer_append_repeated(hb_buffer_T* buffer, const char character, size_t length) {
|
|
154
|
+
if (!buffer || length == 0) { return; }
|
|
155
|
+
if (!hb_buffer_expand_if_needed(buffer, length)) { return; }
|
|
156
|
+
|
|
157
|
+
memset(buffer->value + buffer->length, character, length);
|
|
158
|
+
|
|
159
|
+
buffer->length += length;
|
|
160
|
+
buffer->value[buffer->length] = '\0';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
void hb_buffer_append_whitespace(hb_buffer_T* buffer, const size_t length) {
|
|
164
|
+
hb_buffer_append_repeated(buffer, ' ', length);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void hb_buffer_prepend(hb_buffer_T* buffer, const char* text) {
|
|
168
|
+
if (!buffer || !text) { return; }
|
|
169
|
+
if (text[0] == '\0') { return; }
|
|
170
|
+
|
|
171
|
+
size_t text_length = strlen(text);
|
|
172
|
+
|
|
173
|
+
if (!hb_buffer_expand_if_needed(buffer, text_length)) { return; }
|
|
174
|
+
|
|
175
|
+
memmove(buffer->value + text_length, buffer->value, buffer->length + 1);
|
|
176
|
+
memcpy(buffer->value, text, text_length);
|
|
177
|
+
|
|
178
|
+
buffer->length += text_length;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
void hb_buffer_concat(hb_buffer_T* destination, hb_buffer_T* source) {
|
|
182
|
+
if (source->length == 0) { return; }
|
|
183
|
+
if (!hb_buffer_expand_if_needed(destination, source->length)) { return; }
|
|
184
|
+
|
|
185
|
+
memcpy(destination->value + destination->length, source->value, source->length);
|
|
186
|
+
|
|
187
|
+
destination->length += source->length;
|
|
188
|
+
destination->value[destination->length] = '\0';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
void hb_buffer_clear(hb_buffer_T* buffer) {
|
|
192
|
+
buffer->length = 0;
|
|
193
|
+
buffer->value[0] = '\0';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
void hb_buffer_free(hb_buffer_T** buffer) {
|
|
197
|
+
if (!buffer || !*buffer) { return; }
|
|
198
|
+
|
|
199
|
+
if ((*buffer)->value != NULL) { free((*buffer)->value); }
|
|
200
|
+
|
|
201
|
+
free(*buffer);
|
|
202
|
+
*buffer = NULL;
|
|
203
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#ifndef HERB_BUFFER_H
|
|
2
|
+
#define HERB_BUFFER_H
|
|
3
|
+
|
|
4
|
+
#include "hb_string.h"
|
|
5
|
+
|
|
6
|
+
#include <stdbool.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
|
|
9
|
+
typedef struct HB_BUFFER_STRUCT {
|
|
10
|
+
char* value;
|
|
11
|
+
size_t length;
|
|
12
|
+
size_t capacity;
|
|
13
|
+
} hb_buffer_T;
|
|
14
|
+
|
|
15
|
+
bool hb_buffer_init(hb_buffer_T* buffer, size_t capacity);
|
|
16
|
+
|
|
17
|
+
void hb_buffer_append(hb_buffer_T* buffer, const char* text);
|
|
18
|
+
void hb_buffer_append_with_length(hb_buffer_T* buffer, const char* text, size_t length);
|
|
19
|
+
void hb_buffer_append_string(hb_buffer_T* buffer, hb_string_T string);
|
|
20
|
+
void hb_buffer_append_char(hb_buffer_T* buffer, char character);
|
|
21
|
+
void hb_buffer_append_whitespace(hb_buffer_T* buffer, size_t length);
|
|
22
|
+
void hb_buffer_prepend(hb_buffer_T* buffer, const char* text);
|
|
23
|
+
void hb_buffer_concat(hb_buffer_T* destination, hb_buffer_T* source);
|
|
24
|
+
|
|
25
|
+
char* hb_buffer_value(const hb_buffer_T* buffer);
|
|
26
|
+
|
|
27
|
+
size_t hb_buffer_length(const hb_buffer_T* buffer);
|
|
28
|
+
size_t hb_buffer_capacity(const hb_buffer_T* buffer);
|
|
29
|
+
size_t hb_buffer_sizeof(void);
|
|
30
|
+
|
|
31
|
+
void hb_buffer_clear(hb_buffer_T* buffer);
|
|
32
|
+
void hb_buffer_free(hb_buffer_T** buffer);
|
|
33
|
+
|
|
34
|
+
#endif
|