comparison dowa/d_memory.c @ 52:636eab07809d

Fixed dowa memory problems. Add few more utility functions.
author June Park <parkjune1995@gmail.com>
date Fri, 19 Dec 2025 13:30:30 -0800
parents 84672efec192
children a30944e5719e
comparison
equal deleted inserted replaced
51:68fa88ac73fe 52:636eab07809d
8 { 8 {
9 perror("malloc"); 9 perror("malloc");
10 return NULL; 10 return NULL;
11 } 11 }
12 p_arena->buffer = malloc(capacity); 12 p_arena->buffer = malloc(capacity);
13 if (p_arena->buffer == NULL)
14 {
15 perror("malloc");
16 Dowa_Free(p_arena);
17 return NULL;
18 }
13 p_arena->offset = 0; 19 p_arena->offset = 0;
14 p_arena->capacity = capacity; 20 p_arena->capacity = capacity;
15 return p_arena; 21 return p_arena;
16 } 22 }
17 23
18 void *Dowa_Arena_Allocate(Dowa_PArena p_arena, size_t size) 24 void *Dowa_Arena_Allocate(Dowa_PArena p_arena, size_t size)
19 { 25 {
26 if (!p_arena || !p_arena->buffer || size == 0)
27 return NULL;
28
20 if (p_arena->offset + size > p_arena->capacity) 29 if (p_arena->offset + size > p_arena->capacity)
21 { 30 {
22 return NULL; 31 return NULL;
23 } 32 }
24 void *currnet_ptr = p_arena->buffer + p_arena->offset; 33 void *currnet_ptr = p_arena->buffer + p_arena->offset;
44 if (!dest) 53 if (!dest)
45 return NULL; 54 return NULL;
46 55
47 memcpy(dest, src, size); 56 memcpy(dest, src, size);
48 return dest; 57 return dest;
58 }
59
60 void Dowa_Arena_Reset(Dowa_PArena p_arena)
61 {
62 if (!p_arena) return;
63 p_arena->offset = 0;
64 }
65
66 size_t Dowa_Arena_Get_Used(Dowa_PArena p_arena)
67 {
68 if (!p_arena) return 0;
69 return p_arena->offset;
70 }
71
72 size_t Dowa_Arena_Get_Remaining(Dowa_PArena p_arena)
73 {
74 if (!p_arena) return 0;
75 return p_arena->capacity - p_arena->offset;
49 } 76 }
50 77
51 // --- HashMap --- // 78 // --- HashMap --- //
52 Dowa_PHashMap Dowa_HashMap_Create(size_t capacity) 79 Dowa_PHashMap Dowa_HashMap_Create(size_t capacity)
53 { 80 {
82 if (p_hash_map == NULL) 109 if (p_hash_map == NULL)
83 { 110 {
84 return NULL; 111 return NULL;
85 } 112 }
86 p_hash_map->entries = Dowa_Arena_Allocate(p_arena, sizeof(*p_hash_map->entries) * capacity); 113 p_hash_map->entries = Dowa_Arena_Allocate(p_arena, sizeof(*p_hash_map->entries) * capacity);
114 if (p_hash_map->entries == NULL)
115 {
116 return NULL;
117 }
87 memset(p_hash_map->entries, 0, capacity * sizeof *p_hash_map->entries); 118 memset(p_hash_map->entries, 0, capacity * sizeof *p_hash_map->entries);
88 if (p_hash_map->entries == NULL)
89 {
90 Dowa_Free(p_hash_map);
91 return NULL;
92 }
93 p_hash_map->capacity = capacity; 119 p_hash_map->capacity = capacity;
94 p_hash_map->current_capacity = 0; 120 p_hash_map->current_capacity = 0;
95 p_hash_map->p_arena = p_arena; 121 p_hash_map->p_arena = p_arena;
96 return p_hash_map; 122 return p_hash_map;
97 } 123 }
107 return; 133 return;
108 } 134 }
109 else 135 else
110 { 136 {
111 Dowa_PHashEntry entry; 137 Dowa_PHashEntry entry;
138 Dowa_PHashEntry next;
112 if (p_hash_map->entries) 139 if (p_hash_map->entries)
113 { 140 {
114 for (int idx=0; idx<p_hash_map->capacity; idx++) 141 for (int idx=0; idx<p_hash_map->capacity; idx++)
115 { 142 {
116 entry = p_hash_map->entries[idx]; 143 entry = p_hash_map->entries[idx];
117 if (entry) 144 while (entry)
118 { 145 {
146 next = entry->next;
119 Dowa_Free(entry->key); 147 Dowa_Free(entry->key);
120 Dowa_Free(entry->buffer); 148 Dowa_Free(entry->buffer);
121 Dowa_Free(entry); 149 Dowa_Free(entry);
150 entry = next;
122 } 151 }
123 } 152 }
124 } 153 }
125 Dowa_Free(p_hash_map->entries); 154 Dowa_Free(p_hash_map->entries);
126 } 155 }
127 Dowa_Free(p_hash_map); 156 Dowa_Free(p_hash_map);
128 } 157 }
129 158
130 int32 Dowa_HashMap_Get_Position(Dowa_PHashMap p_hash_map, const char *key) 159 int32 Dowa_HashMap_Get_Position(Dowa_PHashMap p_hash_map, const char *key)
131 { 160 {
161 if (!p_hash_map || !key)
162 return -1;
163
132 int32 hash_val = HASH_KEY_NUMBER; 164 int32 hash_val = HASH_KEY_NUMBER;
133 int32 c; 165 int32 c;
134 while ((c = *key++)) 166 while ((c = *key++))
135 { 167 {
136 hash_val = (hash_val << 5) + hash_val + c; 168 hash_val = (hash_val << 5) + hash_val + c;
138 return hash_val % p_hash_map->capacity; 170 return hash_val % p_hash_map->capacity;
139 } 171 }
140 172
141 void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, const char *key) 173 void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, const char *key)
142 { 174 {
175 if (!p_hash_map || !key)
176 return NULL;
177
143 int idx = Dowa_HashMap_Get_Position(p_hash_map, key); 178 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
144 Dowa_PHashEntry entry = p_hash_map->entries[idx]; 179 Dowa_PHashEntry entry = p_hash_map->entries[idx];
145 180
146 while (entry) 181 while (entry)
147 { 182 {
154 189
155 return NULL; 190 return NULL;
156 } 191 }
157 192
158 193
159 int32 Dowa_HashMap_Push_Value_With_Type_NoCopy(Dowa_PHashMap p_hash_map, const char *key, 194 int32 Dowa_HashMap_Push_Value_With_Type_NoCopy(Dowa_PHashMap p_hash_map, const char *key,
160 void *value, size_t value_size, 195 void *value, size_t value_size,
161 Dowa_HashMap_ValueType type) 196 Dowa_HashMap_ValueType type)
162 { 197 {
198 if (!p_hash_map || !key || !value)
199 return -1;
200
163 int idx = Dowa_HashMap_Get_Position(p_hash_map, key); 201 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
164 Dowa_PHashEntry entry = p_hash_map->entries[idx]; 202 Dowa_PHashEntry entry = p_hash_map->entries[idx];
165 Dowa_PHashEntry prev = NULL; 203 Dowa_PHashEntry prev = NULL;
166 204
167 // Old key 205 // Old key
168 while (entry) 206 while (entry)
169 { 207 {
170 if (strcmp(entry->key, key) == 0) 208 if (strcmp(entry->key, key) == 0)
171 { 209 {
172 // Fails if it the key exists... 210 // Fails if it the key exists...
173 return -1; 211 return -1;
174 } 212 }
213 prev = entry;
214 entry = entry->next;
175 } 215 }
176 216
177 // Overriding doesn't really make sense? when copying over 217 // Overriding doesn't really make sense? when copying over
178 // as we need to free it. 218 // as we need to free it.
179 // 219 //
184 // if (!p_hash_map->p_arena && entry->buffer) 224 // if (!p_hash_map->p_arena && entry->buffer)
185 // Dowa_Free(entry->buffer); 225 // Dowa_Free(entry->buffer);
186 // entry->buffer = value; 226 // entry->buffer = value;
187 // entry->capacity = value_size; 227 // entry->capacity = value_size;
188 // entry->type = type; 228 // entry->type = type;
189 // return 0; 229 // return 0;
190 // } 230 // }
191 // prev = entry; 231 // prev = entry;
192 // entry = entry->next; 232 // entry = entry->next;
193 //} 233 //}
194
195 // New Key
196 entry = p_hash_map->p_arena ?
197 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) :
198 malloc(sizeof(Dowa_HashEntry));
199 if (!entry) { perror("malloc or arena alloc"); return -1; }
200
201 entry->key = p_hash_map->p_arena ?
202 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) :
203 strdup(key);
204 entry->buffer = value;
205 entry->capacity = value_size;
206 entry->type = type;
207 entry->next = NULL;
208
209 if (prev)
210 prev->next = entry;
211 else
212 p_hash_map->entries[idx] = entry;
213
214 p_hash_map->current_capacity++;
215 return 0;
216 }
217
218 int32 Dowa_HashMap_Push_Value_With_Type(Dowa_PHashMap p_hash_map, const char *key,
219 void *value, size_t value_size,
220 Dowa_HashMap_ValueType type)
221 {
222 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
223 Dowa_PHashEntry entry = p_hash_map->entries[idx];
224 Dowa_PHashEntry prev = NULL;
225
226 // Check for existing key
227 while (entry)
228 {
229 if (strcmp(entry->key, key) == 0)
230 {
231 if (!p_hash_map->p_arena && entry->buffer)
232 Dowa_Free(entry->buffer);
233
234 entry->buffer = p_hash_map->p_arena ?
235 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) :
236 malloc(value_size);
237 if (!entry->buffer) { perror("malloc or arena alloc"); return -1; }
238
239 memcpy(entry->buffer, value, value_size);
240 entry->capacity = value_size;
241 entry->type = type;
242 return 0;
243 }
244 prev = entry;
245 entry = entry->next;
246 }
247 234
248 // New Key 235 // New Key
249 entry = p_hash_map->p_arena ? 236 entry = p_hash_map->p_arena ?
250 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : 237 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) :
251 malloc(sizeof(Dowa_HashEntry)); 238 malloc(sizeof(Dowa_HashEntry));
252 if (!entry) { perror("malloc or arena alloc"); return -1; } 239 if (!entry) { perror("malloc or arena alloc"); return -1; }
253 240
254 entry->key = p_hash_map->p_arena ? 241 entry->key = p_hash_map->p_arena ?
255 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : 242 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) :
256 strdup(key); 243 strdup(key);
244 if (!entry->key)
245 {
246 perror("strdup or arena copy");
247 if (!p_hash_map->p_arena) Dowa_Free(entry);
248 return -1;
249 }
250 entry->buffer = value;
251 entry->capacity = value_size;
252 entry->type = type;
253 entry->next = NULL;
254
255 if (prev)
256 prev->next = entry;
257 else
258 p_hash_map->entries[idx] = entry;
259
260 p_hash_map->current_capacity++;
261 return 0;
262 }
263
264 int32 Dowa_HashMap_Push_Value_With_Type(Dowa_PHashMap p_hash_map, const char *key,
265 void *value, size_t value_size,
266 Dowa_HashMap_ValueType type)
267 {
268 if (!p_hash_map || !key || !value)
269 return -1;
270
271 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
272 Dowa_PHashEntry entry = p_hash_map->entries[idx];
273 Dowa_PHashEntry prev = NULL;
274
275 // Check for existing key
276 while (entry)
277 {
278 if (strcmp(entry->key, key) == 0)
279 {
280 if (!p_hash_map->p_arena && entry->buffer)
281 Dowa_Free(entry->buffer);
282
283 entry->buffer = p_hash_map->p_arena ?
284 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) :
285 malloc(value_size);
286 if (!entry->buffer) { perror("malloc or arena alloc"); return -1; }
287
288 memcpy(entry->buffer, value, value_size);
289 entry->capacity = value_size;
290 entry->type = type;
291 return 0;
292 }
293 prev = entry;
294 entry = entry->next;
295 }
296
297 // New Key
298 entry = p_hash_map->p_arena ?
299 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) :
300 malloc(sizeof(Dowa_HashEntry));
301 if (!entry) { perror("malloc or arena alloc"); return -1; }
302
303 entry->key = p_hash_map->p_arena ?
304 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) :
305 strdup(key);
257 if (!entry->key) { perror("strdup"); return -1; } 306 if (!entry->key) { perror("strdup"); return -1; }
258 307
259 entry->buffer = p_hash_map->p_arena ? 308 entry->buffer = p_hash_map->p_arena ?
260 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : 309 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) :
261 malloc(value_size); 310 malloc(value_size);
280 Dowa_HashMap_Push_Value_With_Type(p_hash_map, key, value, value_size, DOWA_HASH_MAP_TYPE_BUFFER); 329 Dowa_HashMap_Push_Value_With_Type(p_hash_map, key, value, value_size, DOWA_HASH_MAP_TYPE_BUFFER);
281 } 330 }
282 331
283 void Dowa_HashMap_Pop_Key(Dowa_PHashMap p_hash_map, const char *key) 332 void Dowa_HashMap_Pop_Key(Dowa_PHashMap p_hash_map, const char *key)
284 { 333 {
334 if (!p_hash_map || !key)
335 return;
336
285 int idx = Dowa_HashMap_Get_Position(p_hash_map, key); 337 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
286 Dowa_PHashEntry entry = p_hash_map->entries[idx]; 338 Dowa_PHashEntry entry = p_hash_map->entries[idx];
287 if (entry && !(p_hash_map->p_arena)) 339 Dowa_PHashEntry prev = NULL;
288 { 340
289 Dowa_Free(entry->key); 341 while (entry)
290 Dowa_Free(entry->buffer); 342 {
291 Dowa_Free(entry); 343 if (strcmp(entry->key, key) == 0)
292 } 344 {
293 p_hash_map->entries[idx] = NULL; 345 if (prev)
294 if (p_hash_map->current_capacity > 0) 346 prev->next = entry->next;
295 { 347 else
296 p_hash_map->current_capacity--; 348 p_hash_map->entries[idx] = entry->next;
297 } 349
350 if (!(p_hash_map->p_arena))
351 {
352 Dowa_Free(entry->key);
353 Dowa_Free(entry->buffer);
354 Dowa_Free(entry);
355 }
356
357 if (p_hash_map->current_capacity > 0)
358 p_hash_map->current_capacity--;
359 return;
360 }
361 prev = entry;
362 entry = entry->next;
363 }
364 }
365
366 boolean Dowa_HashMap_Has_Key(Dowa_PHashMap p_hash_map, const char *key)
367 {
368 if (!p_hash_map || !key)
369 return FALSE;
370
371 int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
372 Dowa_PHashEntry entry = p_hash_map->entries[idx];
373
374 while (entry)
375 {
376 if (strcmp(entry->key, key) == 0)
377 return TRUE;
378 entry = entry->next;
379 }
380
381 return FALSE;
382 }
383
384 void Dowa_HashMap_Clear(Dowa_PHashMap p_hash_map)
385 {
386 if (!p_hash_map) return;
387
388 if (p_hash_map->p_arena)
389 {
390 for (int idx=0; idx<p_hash_map->capacity; idx++)
391 p_hash_map->entries[idx] = NULL;
392 }
393 else
394 {
395 Dowa_PHashEntry entry;
396 Dowa_PHashEntry next;
397 if (p_hash_map->entries)
398 {
399 for (int idx=0; idx<p_hash_map->capacity; idx++)
400 {
401 entry = p_hash_map->entries[idx];
402 while (entry)
403 {
404 next = entry->next;
405 Dowa_Free(entry->key);
406 Dowa_Free(entry->buffer);
407 Dowa_Free(entry);
408 entry = next;
409 }
410 p_hash_map->entries[idx] = NULL;
411 }
412 }
413 }
414 p_hash_map->current_capacity = 0;
415 }
416
417 uint32 Dowa_HashMap_Get_Count(Dowa_PHashMap p_hash_map)
418 {
419 if (!p_hash_map) return 0;
420 return p_hash_map->current_capacity;
298 } 421 }
299 422
300 void Dowa_HashMap_Print(Dowa_PHashMap map) 423 void Dowa_HashMap_Print(Dowa_PHashMap map)
301 { 424 {
425 if (!map)
426 {
427 printf("HashMap is NULL\n");
428 return;
429 }
430
302 printf("\n-----------\n\n"); 431 printf("\n-----------\n\n");
303 for (size_t i = 0; i < map->capacity; ++i) 432 for (size_t i = 0; i < map->capacity; ++i)
304 { 433 {
305 Dowa_PHashEntry e = map->entries[i]; 434 Dowa_PHashEntry e = map->entries[i];
306 while (e) 435 while (e)
345 printf("-----------\n"); 474 printf("-----------\n");
346 } 475 }
347 476
348 int Dowa_HashMap_Cache_Folder(Dowa_PHashMap p_hash_map, const char *folder_path) 477 int Dowa_HashMap_Cache_Folder(Dowa_PHashMap p_hash_map, const char *folder_path)
349 { 478 {
479 if (!p_hash_map || !folder_path)
480 return -1;
481
350 DIR *dir = opendir(folder_path); 482 DIR *dir = opendir(folder_path);
351 if (!dir) { perror("opendir"); return -1; } 483 if (!dir) { perror("opendir"); return -1; }
352 484
353 struct dirent *entry; 485 struct dirent *entry;
354 while ((entry = readdir(dir))) 486 while ((entry = readdir(dir)))
369 { 501 {
370 size_t size = (size_t)st.st_size; 502 size_t size = (size_t)st.st_size;
371 FILE *f = fopen(fullpath, "rb"); 503 FILE *f = fopen(fullpath, "rb");
372 if (!f) { perror("fopen"); continue; } 504 if (!f) { perror("fopen"); continue; }
373 505
374 void *buf = p_hash_map->p_arena ? 506 void *buf = p_hash_map->p_arena ?
375 Dowa_Arena_Allocate(p_hash_map->p_arena, size) : 507 Dowa_Arena_Allocate(p_hash_map->p_arena, size + 1) :
376 malloc(size); 508 malloc(size + 1);
377 if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; } 509 if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; }
378 510
379 511
380 if (fread(buf, 1, size, f) != size) 512 if (fread(buf, 1, size, f) != size)
381 { 513 {
384 fclose(f); 516 fclose(f);
385 continue; 517 continue;
386 } 518 }
387 fclose(f); 519 fclose(f);
388 520
389 Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size, DOWA_HASH_MAP_TYPE_STRING); 521 ((char *)buf)[size] = '\0';
390 Dowa_Free(buf); // Dowa_HashMap_PushValue made its own copy 522 Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size + 1, DOWA_HASH_MAP_TYPE_STRING);
523 if (!p_hash_map->p_arena)
524 Dowa_Free(buf); // Dowa_HashMap_PushValue made its own copy
391 } 525 }
392 else if (S_ISDIR(st.st_mode)) 526 else if (S_ISDIR(st.st_mode))
393 { 527 {
394 // TODO: Adjust the sizes of the recursive map? 528 // TODO: Adjust the sizes of the recursive map?
395 Dowa_PHashMap p_child_map = Dowa_HashMap_Create_With_Arena(100, p_hash_map->p_arena); 529 Dowa_PHashMap p_child_map = Dowa_HashMap_Create_With_Arena(100, p_hash_map->p_arena);