@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.
Files changed (131) hide show
  1. package/binding.gyp +8 -5
  2. package/dist/herb-node.esm.js +6 -6
  3. package/dist/herb-node.esm.js.map +1 -1
  4. package/extension/error_helpers.cpp +67 -9
  5. package/extension/error_helpers.h +4 -2
  6. package/extension/extension_helpers.cpp +20 -31
  7. package/extension/extension_helpers.h +7 -5
  8. package/extension/herb.cpp +10 -42
  9. package/extension/libherb/analyze.c +461 -249
  10. package/extension/libherb/analyze.h +10 -2
  11. package/extension/libherb/analyze_helpers.c +5 -0
  12. package/extension/libherb/analyze_helpers.h +3 -0
  13. package/extension/libherb/analyze_missing_end.c +147 -0
  14. package/extension/libherb/analyze_transform.c +196 -0
  15. package/extension/libherb/analyzed_ruby.c +23 -2
  16. package/extension/libherb/analyzed_ruby.h +4 -2
  17. package/extension/libherb/ast_node.c +14 -17
  18. package/extension/libherb/ast_node.h +4 -4
  19. package/extension/libherb/ast_nodes.c +180 -182
  20. package/extension/libherb/ast_nodes.h +69 -68
  21. package/extension/libherb/ast_pretty_print.c +233 -233
  22. package/extension/libherb/ast_pretty_print.h +3 -3
  23. package/extension/libherb/element_source.c +7 -6
  24. package/extension/libherb/element_source.h +3 -1
  25. package/extension/libherb/errors.c +273 -153
  26. package/extension/libherb/errors.h +43 -27
  27. package/extension/libherb/extract.c +92 -34
  28. package/extension/libherb/extract.h +4 -4
  29. package/extension/libherb/herb.c +37 -49
  30. package/extension/libherb/herb.h +6 -7
  31. package/extension/libherb/html_util.c +34 -96
  32. package/extension/libherb/html_util.h +4 -5
  33. package/extension/libherb/include/analyze.h +10 -2
  34. package/extension/libherb/include/analyze_helpers.h +3 -0
  35. package/extension/libherb/include/analyzed_ruby.h +4 -2
  36. package/extension/libherb/include/ast_node.h +4 -4
  37. package/extension/libherb/include/ast_nodes.h +69 -68
  38. package/extension/libherb/include/ast_pretty_print.h +3 -3
  39. package/extension/libherb/include/element_source.h +3 -1
  40. package/extension/libherb/include/errors.h +43 -27
  41. package/extension/libherb/include/extract.h +4 -4
  42. package/extension/libherb/include/herb.h +6 -7
  43. package/extension/libherb/include/html_util.h +4 -5
  44. package/extension/libherb/include/lexer.h +1 -3
  45. package/extension/libherb/include/lexer_peek_helpers.h +21 -19
  46. package/extension/libherb/include/lexer_struct.h +12 -10
  47. package/extension/libherb/include/location.h +10 -13
  48. package/extension/libherb/include/macros.h +4 -0
  49. package/extension/libherb/include/parser.h +12 -6
  50. package/extension/libherb/include/parser_helpers.h +26 -16
  51. package/extension/libherb/include/position.h +3 -14
  52. package/extension/libherb/include/pretty_print.h +38 -28
  53. package/extension/libherb/include/prism_helpers.h +1 -1
  54. package/extension/libherb/include/range.h +4 -13
  55. package/extension/libherb/include/token.h +5 -11
  56. package/extension/libherb/include/token_struct.h +2 -2
  57. package/extension/libherb/include/utf8.h +3 -2
  58. package/extension/libherb/include/util/hb_arena.h +31 -0
  59. package/extension/libherb/include/util/hb_arena_debug.h +8 -0
  60. package/extension/libherb/include/util/hb_array.h +33 -0
  61. package/extension/libherb/include/util/hb_buffer.h +34 -0
  62. package/extension/libherb/include/util/hb_string.h +29 -0
  63. package/extension/libherb/include/util/hb_system.h +9 -0
  64. package/extension/libherb/include/util.h +3 -14
  65. package/extension/libherb/include/version.h +1 -1
  66. package/extension/libherb/include/visitor.h +1 -1
  67. package/extension/libherb/io.c +7 -4
  68. package/extension/libherb/lexer.c +62 -88
  69. package/extension/libherb/lexer.h +1 -3
  70. package/extension/libherb/lexer_peek_helpers.c +42 -38
  71. package/extension/libherb/lexer_peek_helpers.h +21 -19
  72. package/extension/libherb/lexer_struct.h +12 -10
  73. package/extension/libherb/location.c +9 -37
  74. package/extension/libherb/location.h +10 -13
  75. package/extension/libherb/macros.h +4 -0
  76. package/extension/libherb/main.c +19 -23
  77. package/extension/libherb/parser.c +373 -313
  78. package/extension/libherb/parser.h +12 -6
  79. package/extension/libherb/parser_helpers.c +60 -54
  80. package/extension/libherb/parser_helpers.h +26 -16
  81. package/extension/libherb/parser_match_tags.c +316 -0
  82. package/extension/libherb/position.h +3 -14
  83. package/extension/libherb/pretty_print.c +88 -117
  84. package/extension/libherb/pretty_print.h +38 -28
  85. package/extension/libherb/prism_helpers.c +7 -7
  86. package/extension/libherb/prism_helpers.h +1 -1
  87. package/extension/libherb/range.c +2 -35
  88. package/extension/libherb/range.h +4 -13
  89. package/extension/libherb/token.c +36 -87
  90. package/extension/libherb/token.h +5 -11
  91. package/extension/libherb/token_struct.h +2 -2
  92. package/extension/libherb/utf8.c +4 -4
  93. package/extension/libherb/utf8.h +3 -2
  94. package/extension/libherb/util/hb_arena.c +179 -0
  95. package/extension/libherb/util/hb_arena.h +31 -0
  96. package/extension/libherb/util/hb_arena_debug.c +237 -0
  97. package/extension/libherb/util/hb_arena_debug.h +8 -0
  98. package/extension/libherb/{array.c → util/hb_array.c} +26 -27
  99. package/extension/libherb/util/hb_array.h +33 -0
  100. package/extension/libherb/util/hb_buffer.c +203 -0
  101. package/extension/libherb/util/hb_buffer.h +34 -0
  102. package/extension/libherb/util/hb_string.c +85 -0
  103. package/extension/libherb/util/hb_string.h +29 -0
  104. package/extension/libherb/util/hb_system.c +30 -0
  105. package/extension/libherb/util/hb_system.h +9 -0
  106. package/extension/libherb/util.c +29 -99
  107. package/extension/libherb/util.h +3 -14
  108. package/extension/libherb/version.h +1 -1
  109. package/extension/libherb/visitor.c +55 -55
  110. package/extension/libherb/visitor.h +1 -1
  111. package/extension/nodes.cpp +40 -40
  112. package/extension/nodes.h +2 -2
  113. package/extension/prism/include/prism/ast.h +31 -1
  114. package/extension/prism/include/prism/diagnostic.h +1 -0
  115. package/extension/prism/include/prism/version.h +3 -3
  116. package/extension/prism/src/diagnostic.c +3 -1
  117. package/extension/prism/src/prism.c +130 -71
  118. package/extension/prism/src/util/pm_string.c +6 -8
  119. package/package.json +3 -3
  120. package/extension/libherb/array.h +0 -33
  121. package/extension/libherb/buffer.c +0 -232
  122. package/extension/libherb/buffer.h +0 -39
  123. package/extension/libherb/include/array.h +0 -33
  124. package/extension/libherb/include/buffer.h +0 -39
  125. package/extension/libherb/include/json.h +0 -28
  126. package/extension/libherb/include/memory.h +0 -12
  127. package/extension/libherb/json.c +0 -205
  128. package/extension/libherb/json.h +0 -28
  129. package/extension/libherb/memory.c +0 -53
  130. package/extension/libherb/memory.h +0 -12
  131. 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
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef HERB_ARENA_DEBUG_H
2
+ #define HERB_ARENA_DEBUG_H
3
+
4
+ #include "hb_arena.h"
5
+
6
+ void hb_arena_print_stats(const hb_arena_T* allocator);
7
+
8
+ #endif
@@ -1,20 +1,19 @@
1
1
  #include <stdint.h>
2
2
  #include <stdio.h>
3
3
 
4
- #include "include/array.h"
5
- #include "include/macros.h"
6
- #include "include/memory.h"
4
+ #include "../include/macros.h"
5
+ #include "../include/util/hb_array.h"
7
6
 
8
- size_t array_sizeof(void) {
9
- return sizeof(array_T);
7
+ size_t hb_array_sizeof(void) {
8
+ return sizeof(hb_array_T);
10
9
  }
11
10
 
12
- array_T* array_init(const size_t capacity) {
13
- array_T* array = safe_malloc(array_sizeof());
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 = nullable_safe_malloc(sizeof(void*) * capacity);
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 array_append(array_T* array, void* item) {
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 = safe_realloc(array->items, new_size_bytes);
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* array_get(const array_T* array, const size_t index) {
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* array_first(array_T* array) {
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* array_last(array_T* array) {
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 array_set(const array_T* array, const size_t index, void* item) {
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 array_remove(array_T* array, const size_t index) {
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 array_index_of(array_T* array, void* item) {
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 array_remove_item(array_T* array, void* item) {
101
- size_t index = array_index_of(array, item);
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) { array_remove(array, index); }
102
+ if (index != SIZE_MAX) { hb_array_remove(array, index); }
104
103
  }
105
104
 
106
- // Alias for array_append
107
- void array_push(array_T* array, void* item) {
108
- array_append(array, item);
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* array_pop(array_T* array) {
110
+ void* hb_array_pop(hb_array_T* array) {
112
111
  if (!array || array->size == 0) { return NULL; }
113
112
 
114
- void* last_item = array_last(array);
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 array_size(const array_T* array) {
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 array_capacity(const array_T* array) {
125
+ size_t hb_array_capacity(const hb_array_T* array) {
127
126
  return array->capacity;
128
127
  }
129
128
 
130
- void array_free(array_T** array) {
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