changeset 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 68fa88ac73fe
children 82d1fe4d4ee6 92b097d70af4
files dowa/d_memory.c dowa/dowa.h
diffstat 2 files changed, 169 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/dowa/d_memory.c	Mon Dec 15 19:55:17 2025 -0800
+++ b/dowa/d_memory.c	Fri Dec 19 13:30:30 2025 -0800
@@ -10,6 +10,12 @@
     return NULL;
   }
   p_arena->buffer = malloc(capacity);
+  if (p_arena->buffer == NULL)
+  {
+    perror("malloc");
+    Dowa_Free(p_arena);
+    return NULL;
+  }
   p_arena->offset = 0;
   p_arena->capacity = capacity;
   return p_arena;
@@ -17,6 +23,9 @@
 
 void *Dowa_Arena_Allocate(Dowa_PArena p_arena, size_t size)
 {
+  if (!p_arena || !p_arena->buffer || size == 0)
+    return NULL;
+
   if (p_arena->offset + size > p_arena->capacity)
   {
     return NULL;
@@ -48,6 +57,24 @@
   return dest;
 }
 
+void Dowa_Arena_Reset(Dowa_PArena p_arena)
+{
+  if (!p_arena) return;
+  p_arena->offset = 0;
+}
+
+size_t Dowa_Arena_Get_Used(Dowa_PArena p_arena)
+{
+  if (!p_arena) return 0;
+  return p_arena->offset;
+}
+
+size_t Dowa_Arena_Get_Remaining(Dowa_PArena p_arena)
+{
+  if (!p_arena) return 0;
+  return p_arena->capacity - p_arena->offset;
+}
+
 // --- HashMap --- //
 Dowa_PHashMap Dowa_HashMap_Create(size_t capacity)
 {
@@ -84,12 +111,11 @@
     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)
   {
-    Dowa_Free(p_hash_map);
     return NULL;
   }
+  memset(p_hash_map->entries, 0, capacity * sizeof *p_hash_map->entries);
   p_hash_map->capacity = capacity;
   p_hash_map->current_capacity = 0;
   p_hash_map->p_arena = p_arena;
@@ -109,16 +135,19 @@
   else
   {
     Dowa_PHashEntry entry;
+    Dowa_PHashEntry next;
     if (p_hash_map->entries)
     {
       for (int idx=0; idx<p_hash_map->capacity; idx++)
       {
         entry = p_hash_map->entries[idx];
-        if (entry)
+        while (entry)
         {
+          next = entry->next;
           Dowa_Free(entry->key);
           Dowa_Free(entry->buffer);
           Dowa_Free(entry);
+          entry = next;
         }
       }
     }
@@ -129,6 +158,9 @@
 
 int32 Dowa_HashMap_Get_Position(Dowa_PHashMap p_hash_map, const char *key)
 {
+  if (!p_hash_map || !key)
+    return -1;
+
   int32 hash_val = HASH_KEY_NUMBER;
   int32 c;
   while ((c = *key++))
@@ -140,6 +172,9 @@
 
 void *Dowa_HashMap_Get(Dowa_PHashMap p_hash_map, const char *key)
 {
+  if (!p_hash_map || !key)
+    return NULL;
+
   int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
   Dowa_PHashEntry entry = p_hash_map->entries[idx];
 
@@ -156,22 +191,27 @@
 }
 
 
-int32 Dowa_HashMap_Push_Value_With_Type_NoCopy(Dowa_PHashMap p_hash_map, const char *key, 
+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)
 {
+  if (!p_hash_map || !key || !value)
+    return -1;
+
   int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
   Dowa_PHashEntry entry = p_hash_map->entries[idx];
   Dowa_PHashEntry prev = NULL;
 
-  // Old key 
+  // Old key
   while (entry)
   {
     if (strcmp(entry->key, key) == 0)
     {
       // Fails if it the key exists...
-      return -1; 
+      return -1;
     }
+    prev = entry;
+    entry = entry->next;
   }
 
   // Overriding doesn't really make sense? when copying over
@@ -186,21 +226,27 @@
   //    entry->buffer = value;
   //    entry->capacity = value_size;
   //    entry->type = type;
-  //    return 0; 
+  //    return 0;
   //  }
   //  prev = entry;
   //  entry = entry->next;
   //}
 
-  // New Key 
-  entry = p_hash_map->p_arena ? 
+  // 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 */) : 
+    Dowa_Arena_Copy(p_hash_map->p_arena, key, strlen(key) + 1 /* \0 */) :
     strdup(key);
+  if (!entry->key)
+  {
+    perror("strdup or arena copy");
+    if (!p_hash_map->p_arena) Dowa_Free(entry);
+    return -1;
+  }
   entry->buffer = value;
   entry->capacity = value_size;
   entry->type = type;
@@ -215,10 +261,13 @@
   return 0;
 }
 
-int32 Dowa_HashMap_Push_Value_With_Type(Dowa_PHashMap p_hash_map, const char *key, 
+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)
 {
+  if (!p_hash_map || !key || !value)
+    return -1;
+
   int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
   Dowa_PHashEntry entry = p_hash_map->entries[idx];
   Dowa_PHashEntry prev = NULL;
@@ -282,23 +331,103 @@
 
 void Dowa_HashMap_Pop_Key(Dowa_PHashMap p_hash_map, const char *key)
 {
+  if (!p_hash_map || !key)
+    return;
+
+  int idx = Dowa_HashMap_Get_Position(p_hash_map, key);
+  Dowa_PHashEntry entry = p_hash_map->entries[idx];
+  Dowa_PHashEntry prev = NULL;
+
+  while (entry)
+  {
+    if (strcmp(entry->key, key) == 0)
+    {
+      if (prev)
+        prev->next = entry->next;
+      else
+        p_hash_map->entries[idx] = entry->next;
+
+      if (!(p_hash_map->p_arena))
+      {
+        Dowa_Free(entry->key);
+        Dowa_Free(entry->buffer);
+        Dowa_Free(entry);
+      }
+
+      if (p_hash_map->current_capacity > 0)
+        p_hash_map->current_capacity--;
+      return;
+    }
+    prev = entry;
+    entry = entry->next;
+  }
+}
+
+boolean Dowa_HashMap_Has_Key(Dowa_PHashMap p_hash_map, const char *key)
+{
+  if (!p_hash_map || !key)
+    return FALSE;
+
   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))
+
+  while (entry)
   {
-    Dowa_Free(entry->key);
-    Dowa_Free(entry->buffer);
-    Dowa_Free(entry);
+    if (strcmp(entry->key, key) == 0)
+      return TRUE;
+    entry = entry->next;
+  }
+
+  return FALSE;
+}
+
+void Dowa_HashMap_Clear(Dowa_PHashMap p_hash_map)
+{
+  if (!p_hash_map) return;
+
+  if (p_hash_map->p_arena)
+  {
+    for (int idx=0; idx<p_hash_map->capacity; idx++)
+      p_hash_map->entries[idx] = NULL;
   }
-  p_hash_map->entries[idx] = NULL;
-  if (p_hash_map->current_capacity > 0)
+  else
   {
-    p_hash_map->current_capacity--;
+    Dowa_PHashEntry entry;
+    Dowa_PHashEntry next;
+    if (p_hash_map->entries)
+    {
+      for (int idx=0; idx<p_hash_map->capacity; idx++)
+      {
+        entry = p_hash_map->entries[idx];
+        while (entry)
+        {
+          next = entry->next;
+          Dowa_Free(entry->key);
+          Dowa_Free(entry->buffer);
+          Dowa_Free(entry);
+          entry = next;
+        }
+        p_hash_map->entries[idx] = NULL;
+      }
+    }
   }
+  p_hash_map->current_capacity = 0;
+}
+
+uint32 Dowa_HashMap_Get_Count(Dowa_PHashMap p_hash_map)
+{
+  if (!p_hash_map) return 0;
+  return p_hash_map->current_capacity;
 }
 
 void Dowa_HashMap_Print(Dowa_PHashMap map)
 {
+  if (!map)
+  {
+    printf("HashMap is NULL\n");
+    return;
+  }
+
   printf("\n-----------\n\n");
   for (size_t i = 0; i < map->capacity; ++i)
   {
@@ -347,6 +476,9 @@
 
 int Dowa_HashMap_Cache_Folder(Dowa_PHashMap p_hash_map, const char *folder_path)
 {
+  if (!p_hash_map || !folder_path)
+    return -1;
+
   DIR *dir = opendir(folder_path);
   if (!dir) { perror("opendir"); return -1; }
 
@@ -371,9 +503,9 @@
       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) :
-        malloc(size);
+      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; }
 
 
@@ -386,8 +518,10 @@
       }
       fclose(f);
 
-      Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size, DOWA_HASH_MAP_TYPE_STRING);
-      Dowa_Free(buf);  // Dowa_HashMap_PushValue made its own copy
+      ((char *)buf)[size] = '\0';
+      Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size + 1, DOWA_HASH_MAP_TYPE_STRING);
+      if (!p_hash_map->p_arena)
+        Dowa_Free(buf);  // Dowa_HashMap_PushValue made its own copy
     }
     else if (S_ISDIR(st.st_mode))
     {
--- a/dowa/dowa.h	Mon Dec 15 19:55:17 2025 -0800
+++ b/dowa/dowa.h	Fri Dec 19 13:30:30 2025 -0800
@@ -54,6 +54,12 @@
 extern void  Dowa_Arena_Destroy(Dowa_PArena arena);
 /* Strdup but saves within the arena */
 extern void *Dowa_Arena_Copy(Dowa_PArena p_arena, const void *src, size_t size);
+/* Resets the arena offset to 0, allowing reuse without freeing */
+extern void  Dowa_Arena_Reset(Dowa_PArena p_arena);
+/* Returns the current number of bytes allocated in the arena */
+extern size_t Dowa_Arena_Get_Used(Dowa_PArena p_arena);
+/* Returns the remaining capacity in bytes */
+extern size_t Dowa_Arena_Get_Remaining(Dowa_PArena p_arena);
 
 
 // --- HashMap --- //
@@ -97,6 +103,12 @@
 extern 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);
 /* Removes the entry with the specified key from the hashmap and frees its data if owned. */
 extern void          Dowa_HashMap_Pop_Key(Dowa_PHashMap p_hash_map, const char *key);
+/* Returns TRUE if the key exists in the hashmap, FALSE otherwise. */
+extern boolean       Dowa_HashMap_Has_Key(Dowa_PHashMap p_hash_map, const char *key);
+/* Removes all entries from the hashmap without destroying it. */
+extern void          Dowa_HashMap_Clear(Dowa_PHashMap p_hash_map);
+/* Returns the number of entries currently in the hashmap. */
+extern uint32        Dowa_HashMap_Get_Count(Dowa_PHashMap p_hash_map);
 
 // --- Utility Functions --- //
 /* Prints all entries in the hashmap to stdout for debugging purposes. */