Mercurial
view dowa/d_memory.c @ 22:947b81010aba
[Dowa & Seobeo] Updated so that Dowa hashmaps can use arena and not be broken. Split up web so taht it can handle different paths. Also fixes issues with hash collisions which was pain in the ass.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 07 Oct 2025 07:11:02 -0700 |
| parents | 09def63429b9 |
| children | 08a465eec50b |
line wrap: on
line source
#include "dowa.h" // --- Arena --- // Dowa_PArena Dowa_Arena_Create(size_t capacity) { Dowa_PArena p_arena = malloc(sizeof(Dowa_Arena)); if (p_arena == NULL) { perror("malloc"); return NULL; } p_arena->buffer = malloc(capacity); p_arena->offset = 0; p_arena->capacity = capacity; return p_arena; } void *Dowa_Arena_Allocate(Dowa_PArena p_arena, size_t size) { if (p_arena->offset + size > p_arena->capacity) { return NULL; } void *currnet_ptr = p_arena->buffer + p_arena->offset; p_arena->offset += size; return currnet_ptr; } void Dowa_Arena_Destroy(Dowa_PArena p_arena) { if (!p_arena) return; if (p_arena->buffer) free(p_arena->buffer); free(p_arena); } void *Dowa_Arena_Copy(Dowa_PArena p_arena, const void *src, size_t size) { if (p_arena == NULL || src == NULL || size == 0) return NULL; void *dest = Dowa_Arena_Allocate(p_arena, size); if (!dest) return NULL; memcpy(dest, src, size); return dest; } // --- HashMap --- // Dowa_PHashMap Dowa_HashMap_Create(size_t capacity) { Dowa_PHashMap p_hash_map; p_hash_map = malloc(sizeof(Dowa_HashMap)); if (p_hash_map == NULL) { return NULL; } p_hash_map->entries = calloc(capacity, sizeof(*p_hash_map->entries)); if (p_hash_map->entries == NULL) { free(p_hash_map); return NULL; } p_hash_map->capacity = capacity; p_hash_map->current_capacity = 0; p_hash_map->p_arena = NULL; return p_hash_map; } Dowa_PHashMap Dowa_HashMap_Create_With_Arena(size_t capacity, Dowa_PArena p_arena) { if (p_arena == NULL) { printf("Arena is NULL\n"); return Dowa_HashMap_Create(capacity); } Dowa_PHashMap p_hash_map; p_hash_map = Dowa_Arena_Allocate(p_arena, sizeof(Dowa_HashMap)); if (p_hash_map == NULL) { return NULL; } p_hash_map->entries = Dowa_Arena_Allocate(p_arena, sizeof(*p_hash_map->entries) * capacity); memset(p_hash_map->entries, 0, capacity * sizeof *p_hash_map->entries); if (p_hash_map->entries == NULL) { free(p_hash_map); return NULL; } p_hash_map->capacity = capacity; p_hash_map->current_capacity = 0; p_hash_map->p_arena = p_arena; return p_hash_map; } void Dowa_HashMap_Destroy(Dowa_PHashMap p_hash_map) { if (!p_hash_map) return; if (p_hash_map->p_arena) { // Free arena instead of the map... // Dowa_Arena_Destroy(p_hash_map->p_arena); return; } else { Dowa_PHashEntry entry; if (p_hash_map->entries) { for (int idx=0; idx<p_hash_map->capacity; idx++) { entry = p_hash_map->entries[idx]; if (entry) { free(entry->key); free(entry->buffer); free(entry); } } } free(p_hash_map->entries); } free(p_hash_map); } int32 Dowa_HashMap_Get_Position(Dowa_PHashMap p_hash_map, const char *key) { int32 hash_val = HASH_KEY_NUMBER; int32 c; while ((c = *key++)) { hash_val = (hash_val << 5) + hash_val + c; } return hash_val % p_hash_map->capacity; } void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, const char *key) { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; while (entry) { if (strcmp(entry->key, key) == 0) { return entry->buffer; } entry = entry->next; } return NULL; } int32 Dowa_HashMap_Push_Value_With_Type_NoCopy(Dowa_PHashMap p_hash_map, const char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type) { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; Dowa_PHashEntry prev = NULL; // Old key while (entry) { if (strcmp(entry->key, key) == 0) { if (!p_hash_map->p_arena && entry->buffer) free(entry->buffer); entry->buffer = value; entry->capacity = value_size; entry->type = type; return 0; } prev = entry; entry = entry->next; } // New Key entry = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : malloc(sizeof(Dowa_HashEntry)); if (!entry) { perror("malloc or arena alloc"); return -1; } entry->key = p_hash_map->p_arena ? Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : strdup(key); entry->buffer = value; entry->capacity = value_size; entry->type = type; entry->next = NULL; if (prev) prev->next = entry; else p_hash_map->entries[idx] = entry; p_hash_map->current_capacity++; return 0; } int32 Dowa_HashMap_Push_Value_With_Type(Dowa_PHashMap p_hash_map, const char *key, void *value, size_t value_size, Dowa_HashMap_ValueType type) { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; Dowa_PHashEntry prev = NULL; // Check for existing key while (entry) { if (strcmp(entry->key, key) == 0) { if (!p_hash_map->p_arena && entry->buffer) free(entry->buffer); entry->buffer = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : malloc(value_size); if (!entry->buffer) { perror("malloc or arena alloc"); return -1; } memcpy(entry->buffer, value, value_size); entry->capacity = value_size; entry->type = type; return 0; } prev = entry; entry = entry->next; } // New Key entry = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, sizeof(Dowa_HashEntry)) : malloc(sizeof(Dowa_HashEntry)); if (!entry) { perror("malloc or arena alloc"); return -1; } entry->key = p_hash_map->p_arena ? Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) : strdup(key); if (!entry->key) { perror("strdup"); return -1; } entry->buffer = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, value_size) : malloc(value_size); if (!entry->buffer) { perror("malloc or arena alloc"); return -1; } memcpy(entry->buffer, value, value_size); entry->capacity = value_size; entry->type = type; entry->next = NULL; if (prev) prev->next = entry; else p_hash_map->entries[idx] = entry; p_hash_map->current_capacity++; return 0; } void Dowa_HashMap_Push_Value(Dowa_PHashMap p_hash_map, const char *key, void *value, size_t value_size) { Dowa_HashMap_Push_Value_With_Type(p_hash_map, key, value, value_size, DOWA_HASH_MAP_TYPE_BUFFER); } void Dowa_HashMap_Pop_Key(Dowa_PHashMap p_hash_map, const char *key) { int idx = Dowa_HashMap_Get_Position(p_hash_map, key); Dowa_PHashEntry entry = p_hash_map->entries[idx]; if (entry && !(p_hash_map->p_arena)) { free(entry->key); free(entry->buffer); free(entry); } p_hash_map->entries[idx] = NULL; if (p_hash_map->current_capacity > 0) { p_hash_map->current_capacity--; } } void Dowa_HashMap_Print(Dowa_PHashMap map) { printf("\n-----------\n\n"); for (size_t i = 0; i < map->capacity; ++i) { Dowa_PHashEntry e = map->entries[i]; while (e) { if (!e) break; printf("%s: ", e->key); switch (e->type) { case DOWA_HASH_MAP_TYPE_BUFFER: { unsigned char *p = e->buffer; for (size_t j = 0; j < e->capacity; ++j) { printf("%02x", p[j]); } printf("\n"); } break; case DOWA_HASH_MAP_TYPE_STRING: { printf("%s\n", (char*)e->buffer); } break; case DOWA_HASH_MAP_TYPE_HASHMAP: { printf("This is a hashmap with size of %zu, and pointer %p\n", e->capacity, (void *)e); } break; case DOWA_HASH_MAP_TYPE_INT: { printf("%d\n", *(int32*)e->buffer); } break; default: { printf("<unknown type>\n"); } } e = e->next; } } printf("-----------\n"); } int Dowa_HashMap_Cache_Folder(Dowa_PHashMap p_hash_map, const char *folder_path) { DIR *dir = opendir(folder_path); if (!dir) { perror("opendir"); return -1; } struct dirent *entry; while ((entry = readdir(dir))) { // skip "." and ".." if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) continue; char fullpath[PATH_MAX]; snprintf(fullpath, sizeof fullpath, "%s/%s", folder_path, entry->d_name); struct stat st; if (stat(fullpath, &st) < 0) { perror("stat"); continue; } if (S_ISREG(st.st_mode)) { size_t size = (size_t)st.st_size; FILE *f = fopen(fullpath, "rb"); if (!f) { perror("fopen"); continue; } void *buf = p_hash_map->p_arena ? Dowa_Arena_Allocate(p_hash_map->p_arena, size+1) : malloc(size+1); if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; } if (fread(buf, 1, size, f) != size) { perror("fread"); if (!p_hash_map->p_arena) free(buf); fclose(f); continue; } fclose(f); // null-terminate since the files don't do this and we need this for print. ((unsigned char*)buf)[size] = '\0'; Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size + 1, DOWA_HASH_MAP_TYPE_STRING); free(buf); // Dowa_HashMap_PushValue made its own copy } else if (S_ISDIR(st.st_mode)) { // TODO: Adjust the sizes of the recursive map? Dowa_PHashMap p_child_map = Dowa_HashMap_Create_With_Arena(100, p_hash_map->p_arena); if (!p_child_map) { perror("Dowa_HashMap_Create"); return -1; } if (Dowa_HashMap_Cache_Folder(p_child_map, fullpath) == -1) { perror("Dowa_HashMap_Cache_Folder"); return -1; } // Should not copy as we malloced already. if (Dowa_HashMap_Push_Value_With_Type_NoCopy(p_hash_map, entry->d_name, p_child_map, sizeof(p_child_map), DOWA_HASH_MAP_TYPE_HASHMAP) == -1) { Dowa_HashMap_Destroy(p_child_map); return -1; } } } closedir(dir); return 0; }