Mercurial
comparison dowa/d_memory.c @ 71:75de5903355c
Giagantic changes that update Dowa library to be more align with stb style array and hashmap. Updated Seobeo to be caching on server side instead of file level caching. Deleted bunch of things I don't really use.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sun, 28 Dec 2025 20:34:22 -0800 |
| parents | ecb6ee6a22c3 |
| children | 4532ce6d9eb8 |
comparison
equal
deleted
inserted
replaced
| 70:4bc56e88e1f3 | 71:75de5903355c |
|---|---|
| 21 return p_arena; | 21 return p_arena; |
| 22 } | 22 } |
| 23 | 23 |
| 24 void *Dowa_Arena_Allocate(Dowa_Arena *p_arena, size_t size) | 24 void *Dowa_Arena_Allocate(Dowa_Arena *p_arena, size_t size) |
| 25 { | 25 { |
| 26 if (!p_arena || !p_arena->buffer || size == 0) | 26 return Dowa_Arena_Allocate_Aligned(p_arena, size, sizeof(void*) * 2); |
| 27 return NULL; | |
| 28 | |
| 29 if (p_arena->offset + size > p_arena->capacity) | |
| 30 { | |
| 31 return NULL; | |
| 32 } | |
| 33 void *currnet_ptr = p_arena->buffer + p_arena->offset; | |
| 34 p_arena->offset += size; | |
| 35 return currnet_ptr; | |
| 36 } | 27 } |
| 37 | 28 |
| 38 void Dowa_Arena_Destroy(Dowa_Arena *p_arena) | 29 void Dowa_Arena_Destroy(Dowa_Arena *p_arena) |
| 39 { | 30 { |
| 40 if (!p_arena) return; | 31 if (!p_arena) return; |
| 73 { | 64 { |
| 74 if (!p_arena) return 0; | 65 if (!p_arena) return 0; |
| 75 return p_arena->capacity - p_arena->offset; | 66 return p_arena->capacity - p_arena->offset; |
| 76 } | 67 } |
| 77 | 68 |
| 78 // --- HashMap --- // | 69 void *Dowa_Arena_Allocate_Aligned(Dowa_Arena *p_arena, size_t size, size_t alignment) |
| 70 { | |
| 71 if (!p_arena || !p_arena->buffer || size == 0 || alignment == 0) | |
| 72 return NULL; | |
| 73 | |
| 74 size_t current_address = (size_t)(p_arena->buffer + p_arena->offset); | |
| 75 size_t aligned_address = (current_address + alignment - 1) & ~(alignment - 1); | |
| 76 size_t padding = aligned_address - current_address; | |
| 77 | |
| 78 if (p_arena->offset + padding + size > p_arena->capacity) | |
| 79 return NULL; | |
| 80 | |
| 81 p_arena->offset += padding; | |
| 82 void *p_result = p_arena->buffer + p_arena->offset; | |
| 83 p_arena->offset += size; | |
| 84 return p_result; | |
| 85 } | |
| 86 | |
| 87 // --- NEW stb_ds-style Array Implementation --- // | |
| 88 | |
| 89 void* dowa__array_grow(void* p_array, size_t element_size, size_t minimum_capacity, Dowa_Arena* p_arena) | |
| 90 { | |
| 91 Dowa_Array_Header* p_header; | |
| 92 size_t new_capacity; | |
| 93 size_t current_capacity; | |
| 94 | |
| 95 if (p_array) | |
| 96 { | |
| 97 p_header = dowa__header(p_array); | |
| 98 current_capacity = p_header->capacity; | |
| 99 | |
| 100 if (p_header->allocator_type == DOWA_ALLOCATOR_ARENA && p_header->p_arena != p_arena) | |
| 101 { | |
| 102 fprintf(stderr, "Error: Cannot mix arena allocators\n"); | |
| 103 return p_array; | |
| 104 } | |
| 105 } | |
| 106 else | |
| 107 { | |
| 108 current_capacity = 0; | |
| 109 } | |
| 110 | |
| 111 if (current_capacity >= minimum_capacity && p_array != NULL) | |
| 112 return p_array; | |
| 113 | |
| 114 new_capacity = current_capacity * 2; | |
| 115 if (new_capacity < 4) | |
| 116 new_capacity = 4; | |
| 117 if (new_capacity < minimum_capacity) | |
| 118 new_capacity = minimum_capacity; | |
| 119 | |
| 120 size_t total_size = sizeof(Dowa_Array_Header) + (element_size * new_capacity); | |
| 121 | |
| 122 if (p_arena) | |
| 123 { | |
| 124 // Array header and data must be properly aligned | |
| 125 size_t alignment = element_size >= 16 ? 16 : (element_size >= 8 ? 8 : element_size); | |
| 126 Dowa_Array_Header* p_new_header = (Dowa_Array_Header*)Dowa_Arena_Allocate_Aligned(p_arena, total_size, alignment); | |
| 127 if (!p_new_header) | |
| 128 return p_array; | |
| 129 | |
| 130 void* p_new_array = (char*)p_new_header + sizeof(Dowa_Array_Header); | |
| 131 | |
| 132 if (p_array) | |
| 133 { | |
| 134 memcpy(p_new_array, p_array, element_size * p_header->length); | |
| 135 p_new_header->length = p_header->length; | |
| 136 } | |
| 137 else | |
| 138 { | |
| 139 p_new_header->length = 0; | |
| 140 } | |
| 141 | |
| 142 p_new_header->capacity = new_capacity; | |
| 143 p_new_header->allocator_type = DOWA_ALLOCATOR_ARENA; | |
| 144 p_new_header->p_arena = p_arena; | |
| 145 p_new_header->p_hash = p_array ? p_header->p_hash : NULL; | |
| 146 | |
| 147 return p_new_array; | |
| 148 } | |
| 149 else | |
| 150 { | |
| 151 Dowa_Array_Header* p_new_header; | |
| 152 | |
| 153 if (p_array) | |
| 154 { | |
| 155 p_header = dowa__header(p_array); | |
| 156 p_new_header = (Dowa_Array_Header*)realloc(p_header, total_size); | |
| 157 } | |
| 158 else | |
| 159 { | |
| 160 p_new_header = (Dowa_Array_Header*)malloc(total_size); | |
| 161 if (p_new_header) | |
| 162 p_new_header->length = 0; | |
| 163 } | |
| 164 | |
| 165 if (!p_new_header) | |
| 166 return p_array; | |
| 167 | |
| 168 p_new_header->capacity = new_capacity; | |
| 169 p_new_header->allocator_type = DOWA_ALLOCATOR_MALLOC; | |
| 170 p_new_header->p_arena = NULL; | |
| 171 p_new_header->p_hash = NULL; | |
| 172 | |
| 173 return (char*)p_new_header + sizeof(Dowa_Array_Header); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void dowa__array_free(void* p_array) | |
| 178 { | |
| 179 if (!p_array) | |
| 180 return; | |
| 181 | |
| 182 Dowa_Array_Header* p_header = dowa__header(p_array); | |
| 183 | |
| 184 if (p_header->allocator_type == DOWA_ALLOCATOR_MALLOC) | |
| 185 free(p_header); | |
| 186 } | |
| 187 | |
| 188 // --- NEW stb_ds-style HashMap Implementation --- // | |
| 189 | |
| 190 #define DOWA_HASH_EMPTY 0xFFFFFFFF | |
| 191 #define DOWA_HASH_TOMBSTONE 0xFFFFFFFE | |
| 192 | |
| 193 uint32 dowa__hash_bytes(void* p_key, size_t key_size) | |
| 194 { | |
| 195 uint32 hash = HASH_KEY_NUMBER; | |
| 196 uint8* p_bytes = (uint8*)p_key; | |
| 197 | |
| 198 for (size_t i = 0; i < key_size; i++) | |
| 199 hash = ((hash << 5) + hash) + p_bytes[i]; | |
| 200 | |
| 201 if (hash == DOWA_HASH_EMPTY || hash == DOWA_HASH_TOMBSTONE) | |
| 202 hash = HASH_KEY_NUMBER; | |
| 203 | |
| 204 return hash; | |
| 205 } | |
| 206 | |
| 207 static Dowa_Hash_Index* dowa__hashmap_get_index(void* p_map) | |
| 208 { | |
| 209 if (!p_map) | |
| 210 return NULL; | |
| 211 | |
| 212 Dowa_Array_Header* p_header = dowa__header(p_map); | |
| 213 return (Dowa_Hash_Index*)p_header->p_hash; | |
| 214 } | |
| 215 | |
| 216 static void* dowa__hashmap_find_slot(void* p_map, size_t element_size, void* p_key, size_t key_size, uint32 hash, boolean* p_found) | |
| 217 { | |
| 218 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 219 if (!p_index || !p_index->p_buckets) | |
| 220 { | |
| 221 *p_found = FALSE; | |
| 222 return NULL; | |
| 223 } | |
| 224 | |
| 225 size_t bucket_mask = p_index->bucket_count - 1; | |
| 226 size_t bucket_index = hash & bucket_mask; | |
| 227 size_t probe_step = 0; | |
| 228 | |
| 229 while (1) | |
| 230 { | |
| 231 Dowa_Hash_Bucket* p_bucket = &p_index->p_buckets[bucket_index]; | |
| 232 | |
| 233 for (size_t i = 0; i < DOWA_HASH_BUCKET_SIZE; i++) | |
| 234 { | |
| 235 if (p_bucket->hash[i] == DOWA_HASH_EMPTY) | |
| 236 { | |
| 237 *p_found = FALSE; | |
| 238 return NULL; | |
| 239 } | |
| 240 | |
| 241 if (p_bucket->hash[i] == hash && p_bucket->index[i] != DOWA_HASH_TOMBSTONE) | |
| 242 { | |
| 243 uint32 array_index = p_bucket->index[i]; | |
| 244 char* p_element = (char*)p_map + (array_index * element_size); | |
| 245 | |
| 246 char** p_stored_key_ptr = (char**)p_element; | |
| 247 char* p_stored_key = *p_stored_key_ptr; | |
| 248 char* p_search_key = (char*)p_key; | |
| 249 | |
| 250 if (memcmp(p_stored_key, p_search_key, key_size) == 0) | |
| 251 { | |
| 252 *p_found = TRUE; | |
| 253 return p_element; | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 probe_step++; | |
| 259 bucket_index = (hash + (probe_step * probe_step)) & bucket_mask; | |
| 260 | |
| 261 if (probe_step > p_index->bucket_count) | |
| 262 break; | |
| 263 } | |
| 264 | |
| 265 *p_found = FALSE; | |
| 266 return NULL; | |
| 267 } | |
| 268 | |
| 269 void* dowa__hashmap_get_ptr(void* p_map, size_t element_size, void* p_key, size_t key_size) | |
| 270 { | |
| 271 if (!p_map) | |
| 272 return NULL; | |
| 273 | |
| 274 uint32 hash = dowa__hash_bytes(p_key, key_size); | |
| 275 boolean found = FALSE; | |
| 276 void* p_result = dowa__hashmap_find_slot(p_map, element_size, p_key, key_size, hash, &found); | |
| 277 | |
| 278 return found ? p_result : NULL; | |
| 279 } | |
| 280 | |
| 281 void* dowa__hashmap_get(void* p_map, size_t element_size, void* p_key, size_t key_size) | |
| 282 { | |
| 283 void* p_kv = dowa__hashmap_get_ptr(p_map, element_size, p_key, key_size); | |
| 284 if (!p_kv) | |
| 285 return NULL; | |
| 286 | |
| 287 return (char*)p_kv + key_size; | |
| 288 } | |
| 289 | |
| 290 boolean dowa__hashmap_has_key(void* p_map, size_t element_size, void* p_key, size_t key_size) | |
| 291 { | |
| 292 return dowa__hashmap_get_ptr(p_map, element_size, p_key, key_size) != NULL; | |
| 293 } | |
| 294 | |
| 295 static void* dowa__hashmap_rehash(void* p_map, size_t element_size, size_t new_bucket_count, Dowa_Arena* p_arena) | |
| 296 { | |
| 297 Dowa_Hash_Index* p_old_index = dowa__hashmap_get_index(p_map); | |
| 298 if (!p_old_index) | |
| 299 return p_map; | |
| 300 | |
| 301 size_t bucket_alloc_size = sizeof(Dowa_Hash_Bucket) * new_bucket_count; | |
| 302 Dowa_Hash_Bucket* p_new_buckets; | |
| 303 | |
| 304 if (p_arena) | |
| 305 { | |
| 306 p_new_buckets = (Dowa_Hash_Bucket*)Dowa_Arena_Allocate_Aligned(p_arena, bucket_alloc_size, DOWA_HASH_CACHE_LINE_SIZE); | |
| 307 } | |
| 308 else | |
| 309 { | |
| 310 if (posix_memalign((void**)&p_new_buckets, DOWA_HASH_CACHE_LINE_SIZE, bucket_alloc_size) != 0) | |
| 311 p_new_buckets = NULL; | |
| 312 } | |
| 313 | |
| 314 if (!p_new_buckets) | |
| 315 return p_map; | |
| 316 | |
| 317 for (size_t i = 0; i < new_bucket_count; i++) | |
| 318 { | |
| 319 for (size_t j = 0; j < DOWA_HASH_BUCKET_SIZE; j++) | |
| 320 { | |
| 321 p_new_buckets[i].hash[j] = DOWA_HASH_EMPTY; | |
| 322 p_new_buckets[i].index[j] = DOWA_HASH_EMPTY; | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 Dowa_Hash_Index* p_new_index; | |
| 327 if (p_arena) | |
| 328 p_new_index = (Dowa_Hash_Index*)Dowa_Arena_Allocate_Aligned(p_arena, sizeof(Dowa_Hash_Index), 16); | |
| 329 else | |
| 330 p_new_index = (Dowa_Hash_Index*)malloc(sizeof(Dowa_Hash_Index)); | |
| 331 | |
| 332 if (!p_new_index) | |
| 333 { | |
| 334 if (!p_arena) | |
| 335 free(p_new_buckets); | |
| 336 return p_map; | |
| 337 } | |
| 338 | |
| 339 p_new_index->bucket_count = new_bucket_count; | |
| 340 p_new_index->item_count = 0; | |
| 341 p_new_index->tombstone_count = 0; | |
| 342 p_new_index->allocator_type = p_arena ? DOWA_ALLOCATOR_ARENA : DOWA_ALLOCATOR_MALLOC; | |
| 343 p_new_index->p_arena = p_arena; | |
| 344 p_new_index->p_buckets = p_new_buckets; | |
| 345 | |
| 346 size_t map_length = Dowa_Array_Length(p_map); | |
| 347 for (size_t i = 0; i < map_length; i++) | |
| 348 { | |
| 349 char* p_element = (char*)p_map + (i * element_size); | |
| 350 char** p_key_ptr = (char**)p_element; | |
| 351 char* p_key_data = *p_key_ptr; | |
| 352 uint32 hash = dowa__hash_bytes(p_key_data, strlen(p_key_data) + 1); | |
| 353 | |
| 354 size_t bucket_mask = new_bucket_count - 1; | |
| 355 size_t bucket_index = hash & bucket_mask; | |
| 356 size_t probe_step = 0; | |
| 357 boolean inserted = FALSE; | |
| 358 | |
| 359 while (!inserted && probe_step <= new_bucket_count) | |
| 360 { | |
| 361 Dowa_Hash_Bucket* p_bucket = &p_new_buckets[bucket_index]; | |
| 362 | |
| 363 for (size_t j = 0; j < DOWA_HASH_BUCKET_SIZE; j++) | |
| 364 { | |
| 365 if (p_bucket->hash[j] == DOWA_HASH_EMPTY) | |
| 366 { | |
| 367 p_bucket->hash[j] = hash; | |
| 368 p_bucket->index[j] = (uint32)i; | |
| 369 p_new_index->item_count++; | |
| 370 inserted = TRUE; | |
| 371 break; | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 if (!inserted) | |
| 376 { | |
| 377 probe_step++; | |
| 378 bucket_index = (hash + (probe_step * probe_step)) & bucket_mask; | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 if (p_old_index->allocator_type == DOWA_ALLOCATOR_MALLOC) | |
| 384 { | |
| 385 if (p_old_index->p_buckets) | |
| 386 free(p_old_index->p_buckets); | |
| 387 free(p_old_index); | |
| 388 } | |
| 389 | |
| 390 dowa__header(p_map)->p_hash = p_new_index; | |
| 391 return p_map; | |
| 392 } | |
| 393 | |
| 394 void* dowa__hashmap_push(void* p_map, size_t element_size, void* p_key, size_t key_size, Dowa_Arena* p_arena) | |
| 395 { | |
| 396 uint32 hash = dowa__hash_bytes(p_key, key_size); | |
| 397 | |
| 398 if (p_map) | |
| 399 { | |
| 400 boolean found = FALSE; | |
| 401 dowa__hashmap_find_slot(p_map, element_size, p_key, key_size, hash, &found); | |
| 402 if (found) | |
| 403 return p_map; | |
| 404 } | |
| 405 | |
| 406 p_map = dowa__array_grow(p_map, element_size, 0, p_arena); | |
| 407 | |
| 408 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 409 if (!p_index) | |
| 410 { | |
| 411 size_t initial_bucket_count = 4; | |
| 412 size_t bucket_alloc_size = sizeof(Dowa_Hash_Bucket) * initial_bucket_count; | |
| 413 Dowa_Hash_Bucket* p_buckets; | |
| 414 | |
| 415 if (p_arena) | |
| 416 { | |
| 417 p_buckets = (Dowa_Hash_Bucket*)Dowa_Arena_Allocate_Aligned(p_arena, bucket_alloc_size, DOWA_HASH_CACHE_LINE_SIZE); | |
| 418 } | |
| 419 else | |
| 420 { | |
| 421 if (posix_memalign((void**)&p_buckets, DOWA_HASH_CACHE_LINE_SIZE, bucket_alloc_size) != 0) | |
| 422 p_buckets = NULL; | |
| 423 } | |
| 424 | |
| 425 if (!p_buckets) | |
| 426 return p_map; | |
| 427 | |
| 428 for (size_t i = 0; i < initial_bucket_count; i++) | |
| 429 { | |
| 430 for (size_t j = 0; j < DOWA_HASH_BUCKET_SIZE; j++) | |
| 431 { | |
| 432 p_buckets[i].hash[j] = DOWA_HASH_EMPTY; | |
| 433 p_buckets[i].index[j] = DOWA_HASH_EMPTY; | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 if (p_arena) | |
| 438 p_index = (Dowa_Hash_Index*)Dowa_Arena_Allocate_Aligned(p_arena, sizeof(Dowa_Hash_Index), 16); | |
| 439 else | |
| 440 p_index = (Dowa_Hash_Index*)malloc(sizeof(Dowa_Hash_Index)); | |
| 441 | |
| 442 if (!p_index) | |
| 443 { | |
| 444 if (!p_arena) | |
| 445 free(p_buckets); | |
| 446 return p_map; | |
| 447 } | |
| 448 | |
| 449 p_index->bucket_count = initial_bucket_count; | |
| 450 p_index->item_count = 0; | |
| 451 p_index->tombstone_count = 0; | |
| 452 p_index->allocator_type = p_arena ? DOWA_ALLOCATOR_ARENA : DOWA_ALLOCATOR_MALLOC; | |
| 453 p_index->p_arena = p_arena; | |
| 454 p_index->p_buckets = p_buckets; | |
| 455 | |
| 456 dowa__header(p_map)->p_hash = p_index; | |
| 457 } | |
| 458 | |
| 459 // Rehash when load factor exceeds ~50% (bucket_count * BUCKET_SIZE * 0.5) | |
| 460 // This ensures we rehash before probe chains get too long | |
| 461 if (p_index->item_count + p_index->tombstone_count >= p_index->bucket_count * 4) | |
| 462 p_map = dowa__hashmap_rehash(p_map, element_size, p_index->bucket_count * 2, p_arena); | |
| 463 | |
| 464 p_index = dowa__hashmap_get_index(p_map); | |
| 465 | |
| 466 Dowa_Array_Header* p_header = dowa__header(p_map); | |
| 467 uint32 new_index = (uint32)p_header->length; | |
| 468 char* p_new_element = (char*)p_map + (new_index * element_size); | |
| 469 | |
| 470 char* p_key_copy; | |
| 471 if (p_arena) | |
| 472 p_key_copy = (char*)Dowa_Arena_Allocate(p_arena, key_size); | |
| 473 else | |
| 474 p_key_copy = (char*)malloc(key_size); | |
| 475 | |
| 476 if (!p_key_copy) | |
| 477 return p_map; | |
| 478 | |
| 479 memcpy(p_key_copy, p_key, key_size); | |
| 480 | |
| 481 memcpy(p_new_element, &p_key_copy, sizeof(char*)); | |
| 482 p_header->length++; | |
| 483 | |
| 484 // Try to insert into hash table - if it fails, rehash and retry | |
| 485 boolean inserted = FALSE; | |
| 486 for (int attempt = 0; attempt < 2 && !inserted; attempt++) | |
| 487 { | |
| 488 if (attempt == 1) | |
| 489 { | |
| 490 // First attempt failed - rehash to make more room | |
| 491 p_header->length--; // Undo the array length increment temporarily | |
| 492 p_map = dowa__hashmap_rehash(p_map, element_size, p_index->bucket_count * 2, p_arena); | |
| 493 p_index = dowa__hashmap_get_index(p_map); | |
| 494 p_header = dowa__header(p_map); | |
| 495 | |
| 496 // Restore array state | |
| 497 new_index = (uint32)p_header->length; | |
| 498 p_new_element = (char*)p_map + (new_index * element_size); | |
| 499 memcpy(p_new_element, &p_key_copy, sizeof(char*)); | |
| 500 p_header->length++; | |
| 501 } | |
| 502 | |
| 503 size_t bucket_mask = p_index->bucket_count - 1; | |
| 504 size_t bucket_index = hash & bucket_mask; | |
| 505 size_t probe_step = 0; | |
| 506 | |
| 507 while (!inserted && probe_step <= p_index->bucket_count) | |
| 508 { | |
| 509 Dowa_Hash_Bucket* p_bucket = &p_index->p_buckets[bucket_index]; | |
| 510 | |
| 511 for (size_t i = 0; i < DOWA_HASH_BUCKET_SIZE; i++) | |
| 512 { | |
| 513 if (p_bucket->hash[i] == DOWA_HASH_EMPTY || p_bucket->hash[i] == DOWA_HASH_TOMBSTONE) | |
| 514 { | |
| 515 if (p_bucket->hash[i] == DOWA_HASH_TOMBSTONE) | |
| 516 p_index->tombstone_count--; | |
| 517 | |
| 518 p_bucket->hash[i] = hash; | |
| 519 p_bucket->index[i] = new_index; | |
| 520 p_index->item_count++; | |
| 521 inserted = TRUE; | |
| 522 break; | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 if (!inserted) | |
| 527 { | |
| 528 probe_step++; | |
| 529 bucket_index = (hash + (probe_step * probe_step)) & bucket_mask; | |
| 530 } | |
| 531 } | |
| 532 } | |
| 533 | |
| 534 return p_map; | |
| 535 } | |
| 536 | |
| 537 void dowa__hashmap_delete(void* p_map, size_t element_size, void* p_key, size_t key_size) | |
| 538 { | |
| 539 if (!p_map) | |
| 540 return; | |
| 541 | |
| 542 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 543 if (!p_index || !p_index->p_buckets) | |
| 544 return; | |
| 545 | |
| 546 uint32 hash = dowa__hash_bytes(p_key, key_size); | |
| 547 size_t bucket_mask = p_index->bucket_count - 1; | |
| 548 size_t bucket_index = hash & bucket_mask; | |
| 549 size_t probe_step = 0; | |
| 550 | |
| 551 while (probe_step <= p_index->bucket_count) | |
| 552 { | |
| 553 Dowa_Hash_Bucket* p_bucket = &p_index->p_buckets[bucket_index]; | |
| 554 | |
| 555 for (size_t i = 0; i < DOWA_HASH_BUCKET_SIZE; i++) | |
| 556 { | |
| 557 if (p_bucket->hash[i] == DOWA_HASH_EMPTY) | |
| 558 return; | |
| 559 | |
| 560 if (p_bucket->hash[i] == hash && p_bucket->index[i] != DOWA_HASH_TOMBSTONE) | |
| 561 { | |
| 562 uint32 array_index = p_bucket->index[i]; | |
| 563 char* p_element = (char*)p_map + (array_index * element_size); | |
| 564 | |
| 565 char** p_stored_key_ptr = (char**)p_element; | |
| 566 char* p_stored_key = *p_stored_key_ptr; | |
| 567 char* p_search_key = (char*)p_key; | |
| 568 | |
| 569 if (memcmp(p_stored_key, p_search_key, key_size) == 0) | |
| 570 { | |
| 571 if (dowa__header(p_map)->allocator_type == DOWA_ALLOCATOR_MALLOC) | |
| 572 free(p_stored_key); | |
| 573 | |
| 574 p_bucket->hash[i] = DOWA_HASH_TOMBSTONE; | |
| 575 p_bucket->index[i] = DOWA_HASH_TOMBSTONE; | |
| 576 p_index->item_count--; | |
| 577 p_index->tombstone_count++; | |
| 578 return; | |
| 579 } | |
| 580 } | |
| 581 } | |
| 582 | |
| 583 probe_step++; | |
| 584 bucket_index = (hash + (probe_step * probe_step)) & bucket_mask; | |
| 585 } | |
| 586 } | |
| 587 | |
| 588 void dowa__hashmap_clear(void* p_map, size_t element_size) | |
| 589 { | |
| 590 if (!p_map) | |
| 591 return; | |
| 592 | |
| 593 Dowa_Array_Header* p_header = dowa__header(p_map); | |
| 594 p_header->length = 0; | |
| 595 | |
| 596 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 597 if (p_index && p_index->p_buckets) | |
| 598 { | |
| 599 for (size_t i = 0; i < p_index->bucket_count; i++) | |
| 600 { | |
| 601 for (size_t j = 0; j < DOWA_HASH_BUCKET_SIZE; j++) | |
| 602 { | |
| 603 p_index->p_buckets[i].hash[j] = DOWA_HASH_EMPTY; | |
| 604 p_index->p_buckets[i].index[j] = DOWA_HASH_EMPTY; | |
| 605 } | |
| 606 } | |
| 607 p_index->item_count = 0; | |
| 608 p_index->tombstone_count = 0; | |
| 609 } | |
| 610 } | |
| 611 | |
| 612 void dowa__hashmap_free(void* p_map) | |
| 613 { | |
| 614 if (!p_map) | |
| 615 return; | |
| 616 | |
| 617 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 618 if (p_index && p_index->allocator_type == DOWA_ALLOCATOR_MALLOC) | |
| 619 { | |
| 620 if (p_index->p_buckets) | |
| 621 free(p_index->p_buckets); | |
| 622 free(p_index); | |
| 623 } | |
| 624 | |
| 625 dowa__array_free(p_map); | |
| 626 } | |
| 627 | |
| 628 size_t dowa__hashmap_count(void* p_map) | |
| 629 { | |
| 630 if (!p_map) | |
| 631 return 0; | |
| 632 | |
| 633 Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map); | |
| 634 return p_index ? p_index->item_count : 0; | |
| 635 } | |
| 636 | |
| 637 /* | |
| 638 // --- OLD HashMap Implementation (Commented out for migration) --- // | |
| 79 Dowa_HashMap *Dowa_HashMap_Create(size_t capacity) | 639 Dowa_HashMap *Dowa_HashMap_Create(size_t capacity) |
| 80 { | 640 { |
| 81 Dowa_HashMap *p_hash_map; | 641 Dowa_HashMap *p_hash_map; |
| 82 p_hash_map = malloc(sizeof(Dowa_HashMap)); | 642 p_hash_map = malloc(sizeof(Dowa_HashMap)); |
| 83 if (p_hash_map == NULL) | 643 if (p_hash_map == NULL) |
| 212 } | 772 } |
| 213 prev = entry; | 773 prev = entry; |
| 214 entry = entry->next; | 774 entry = entry->next; |
| 215 } | 775 } |
| 216 | 776 |
| 217 // Overriding doesn't really make sense? when copying over | |
| 218 // as we need to free it. | |
| 219 // | |
| 220 //while (entry) | |
| 221 //{ | |
| 222 // if (strcmp(entry->key, key) == 0) | |
| 223 // { | |
| 224 // if (!p_hash_map->p_arena && entry->buffer) | |
| 225 // Dowa_Free(entry->buffer); | |
| 226 // entry->buffer = value; | |
| 227 // entry->capacity = value_size; | |
| 228 // entry->type = type; | |
| 229 // return 0; | |
| 230 // } | |
| 231 // prev = entry; | |
| 232 // entry = entry->next; | |
| 233 //} | |
| 234 | |
| 235 // New Key | 777 // New Key |
| 236 entry = p_hash_map->p_arena ? | 778 entry = p_hash_map->p_arena ? |
| 237 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : | 779 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : |
| 238 malloc(sizeof(Dowa_HashEntry)); | 780 malloc(sizeof(Dowa_HashEntry)); |
| 239 if (!entry) { perror("malloc or arena alloc"); return -1; } | 781 if (!entry) { perror("malloc or arena alloc"); return -1; } |
| 240 | 782 |
| 241 entry->key = p_hash_map->p_arena ? | 783 entry->key = p_hash_map->p_arena ? |
| 242 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : | 784 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1) : |
| 243 strdup(key); | 785 strdup(key); |
| 244 if (!entry->key) | 786 if (!entry->key) |
| 245 { | 787 { |
| 246 perror("strdup or arena copy"); | 788 perror("strdup or arena copy"); |
| 247 if (!p_hash_map->p_arena) Dowa_Free(entry); | 789 if (!p_hash_map->p_arena) Dowa_Free(entry); |
| 299 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : | 841 Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : |
| 300 malloc(sizeof(Dowa_HashEntry)); | 842 malloc(sizeof(Dowa_HashEntry)); |
| 301 if (!entry) { perror("malloc or arena alloc"); return -1; } | 843 if (!entry) { perror("malloc or arena alloc"); return -1; } |
| 302 | 844 |
| 303 entry->key = p_hash_map->p_arena ? | 845 entry->key = p_hash_map->p_arena ? |
| 304 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : | 846 Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1) : |
| 305 strdup(key); | 847 strdup(key); |
| 306 if (!entry->key) { perror("strdup"); return -1; } | 848 if (!entry->key) { perror("strdup"); return -1; } |
| 307 | 849 |
| 308 entry->buffer = p_hash_map->p_arena ? | 850 entry->buffer = p_hash_map->p_arena ? |
| 309 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : | 851 Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : |
| 472 } | 1014 } |
| 473 } | 1015 } |
| 474 printf("-----------\n"); | 1016 printf("-----------\n"); |
| 475 } | 1017 } |
| 476 | 1018 |
| 1019 // -- Array --// | |
| 1020 Dowa_Array *Dowa_Array_Init() | |
| 1021 { | |
| 1022 Dowa_Array *dowa_array = malloc(sizeof(Dowa_Array)); | |
| 1023 if (dowa_array == NULL) | |
| 1024 { | |
| 1025 return NULL; | |
| 1026 } | |
| 1027 | |
| 1028 dowa_array->capacity = DOWA_ARRAY_DEFAULT_CAPACITY; | |
| 1029 dowa_array->items = (Dowa_Array_Item *)malloc(sizeof(Dowa_Array_Item) * DOWA_ARRAY_DEFAULT_CAPACITY); | |
| 1030 if (dowa_array->items == NULL) | |
| 1031 { | |
| 1032 return NULL; | |
| 1033 } | |
| 1034 | |
| 1035 dowa_array->current_length = 0; | |
| 1036 return dowa_array; | |
| 1037 } | |
| 1038 | |
| 1039 // void Dowa_Array_Push_Value(Dowa_Array *dowa_array, void *buffer, uint32 length) | |
| 1040 // { | |
| 1041 // if (dowa_array->current_length == dowa_array->capacity) | |
| 1042 // { | |
| 1043 // dowa_array->items = realloc(dowa_array->items, sizeof(Dowa_Array_Item) * dowa_array->capacity * 2); | |
| 1044 // dowa_array->capacity = dowa_array->capacity * 2; | |
| 1045 // } | |
| 1046 // Dowa_Array_Item *item = &(dowa_array->items[dowa_array->current_length]); | |
| 1047 // item->value = malloc(length); | |
| 1048 // if (item->value == NULL) | |
| 1049 // { | |
| 1050 // // didn't alloc should raise an error. | |
| 1051 // return; | |
| 1052 // } | |
| 1053 // memcpy(item->value, buffer, length); | |
| 1054 // item->length = length; | |
| 1055 // dowa_array->current_length += 1; | |
| 1056 // } | |
| 1057 | |
| 1058 | |
| 477 #ifdef DIRECTORY | 1059 #ifdef DIRECTORY |
| 478 int Dowa_HashMap_Cache_Folder(Dowa_HashMap *p_hash_map, const char *folder_path) | 1060 int Dowa_HashMap_Cache_Folder(Dowa_HashMap *p_hash_map, const char *folder_path) |
| 479 { | 1061 { |
| 480 if (!p_hash_map || !folder_path) | 1062 if (!p_hash_map || !folder_path) |
| 481 return -1; | 1063 return -1; |
| 550 } | 1132 } |
| 551 closedir(dir); | 1133 closedir(dir); |
| 552 return 0; | 1134 return 0; |
| 553 } | 1135 } |
| 554 #endif | 1136 #endif |
| 1137 */ |