]> git.mdlowis.com Git - projs/libcds.git/commitdiff
Added reference counting to list implementation
authorMichael D. Lowis <mike@mdlowis.com>
Sat, 19 Jul 2014 04:08:30 +0000 (00:08 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Sat, 19 Jul 2014 04:08:30 +0000 (00:08 -0400)
premake4.lua
source/list/list.c
source/list/list.h
source/mem/mem.c [new file with mode: 0644]
source/mem/mem.h [new file with mode: 0644]
source/vector/vec.c

index 36e5da4ad0de5af251195ff6181178b7809c4f60..8560e0257d1c3260426c0dde28c4f902cd8b84a6 100644 (file)
@@ -13,29 +13,30 @@ project "cds"
     language "C"
     location "build"
     files { "source/**.*" }
+    includedirs { "source/**" }
 
-project "tests"
-    kind "ConsoleApp"
-    language "C++"
-    location "build"
-    links { "UnitTest++", "cds" }
-    includedirs { "source/*", "tools/UnitTest++/**" }
-    files { "tests/**.c*" }
-    postbuildcommands { "./tests.exe" }
+--project "tests"
+--    kind "ConsoleApp"
+--    language "C++"
+--    location "build"
+--    links { "UnitTest++", "cds" }
+--    includedirs { "source/*", "tools/UnitTest++/**" }
+--    files { "tests/**.c*" }
+--    postbuildcommands { "./tests.exe" }
 
 -------------------------------------------------------------------------------
 -- UnitTest++ - A C++ unit testing library
 -------------------------------------------------------------------------------
-project "UnitTest++"
-    kind "SharedLib"
-    language "C++"
-    location "build"
-    files {
-        "tools/UnitTest++/src/*.*",
-    }
-    if os.is "windows" then
-        files { "tools/UnitTest++/src/Win32/**.*" }
-    else
-        files { "tools/UnitTest++/src/Posix/**.*" }
-    end
+--project "UnitTest++"
+--    kind "SharedLib"
+--    language "C++"
+--    location "build"
+--    files {
+--        "tools/UnitTest++/src/*.*",
+--    }
+--    if os.is "windows" then
+--        files { "tools/UnitTest++/src/Win32/**.*" }
+--    else
+--        files { "tools/UnitTest++/src/Posix/**.*" }
+--    end
 
index 67f3100972ac7ca6a7816d1d7fed2870a3c60b77..764236285a1cc5d81c7ac3f9c43c82956f8df61f 100644 (file)
@@ -1,9 +1,14 @@
 #include <stdlib.h>
 #include "list.h"
+#include "mem.h"
+
+static void list_free(void* p_list);
+
+static void list_node_free(void* p_node);
 
 list_t* list_new(void)
 {
-    list_t* list = (list_t*)malloc( sizeof( list_t ) );
+    list_t* list = (list_t*)mem_allocate(sizeof(list_t), NULL);
     list->head = NULL;
     list->tail = NULL;
     return list;
@@ -11,33 +16,12 @@ list_t* list_new(void)
 
 list_node_t* list_new_node(void* contents)
 {
-    list_node_t* node = (list_node_t*)malloc( sizeof( list_node_t ) );
+    list_node_t* node = (list_node_t*)mem_allocate(sizeof(list_node_t), NULL);
     node->contents = contents;
     node->next = NULL;
     return node;
 }
 
-void list_free(list_t* list, bool free_contents)
-{
-    list_node_t* node = list->head;
-    while( NULL != node )
-    {
-        list_node_t* next = node->next;
-        list_free_node( node, free_contents );
-        node = next;
-    }
-    free( list );
-}
-
-void list_free_node(list_node_t* node, bool free_contents)
-{
-    if( free_contents )
-    {
-        free( node->contents );
-    }
-    free( node );
-}
-
 list_node_t* list_front( list_t* list )
 {
     return list->head;
@@ -65,7 +49,6 @@ bool list_empty(list_t* list)
     return ((NULL == list->head) && (NULL == list->tail));
 }
 
-
 list_node_t* list_at(list_t* list, size_t index)
 {
     list_node_t* node = NULL;
@@ -176,7 +159,7 @@ list_node_t* list_insert( list_t* list, size_t index, void* contents)
     return new_node;
 }
 
-list_node_t* list_delete( list_t* list, size_t index, bool free_contents)
+list_node_t* list_delete( list_t* list, size_t index)
 {
     list_node_t* node = NULL;
 
@@ -185,7 +168,8 @@ list_node_t* list_delete( list_t* list, size_t index, bool free_contents)
         node = list_pop_front(list);
         if (NULL != node)
         {
-            list_free_node(node,free_contents);
+            node->next = NULL;
+            mem_release(node);
             node = list_front(list);
         }
     }
@@ -200,7 +184,8 @@ list_node_t* list_delete( list_t* list, size_t index, bool free_contents)
             {
                 list->tail = prev;
             }
-            list_free_node(node,free_contents);
+            node->next = NULL;
+            mem_release(node);
             node = prev->next;
         }
     }
@@ -208,17 +193,23 @@ list_node_t* list_delete( list_t* list, size_t index, bool free_contents)
     return node;
 }
 
-list_t* list_clear(list_t* list, bool free_contents)
+void list_clear(list_t* list)
 {
-    list_node_t* node = list->head;
-    while(NULL != node)
-    {
-        list_node_t* next = node->next;
-        list_free_node(node,free_contents);
-        node = next;
-    }
+    mem_release((void*)list->head);
     list->head = NULL;
     list->tail = NULL;
-    return list;
 }
 
+static void list_free(void* p_list)
+{
+    if (NULL != ((list_t*)p_list)->head)
+        mem_release(((list_t*)p_list)->head);
+}
+
+static void list_node_free(void* p_node)
+{
+    if (NULL != ((list_node_t*)p_node)->contents)
+        mem_release(((list_node_t*)p_node)->contents);
+    if (NULL != ((list_node_t*)p_node)->next)
+        mem_release(((list_node_t*)p_node)->next);
+}
index 5a146c2b9a9dce267d713533c0c35b3e6a0bd058..029c4f35c03bf73b9a3e304c527575137c73a54f 100644 (file)
@@ -41,28 +41,6 @@ extern list_t* list_new(void);
  */
 list_node_t* list_new_node(void* contents);
 
-/**
- * @brief Frees all memory used by a linked list.
- *
- * This function loops through the supplied list and frees all nodes.
- * Also frees contents if free_contents is passed a non-zero value.
- *
- * @param list          The list to be freed.
- * @param free_contents Whether or not to also free the contents of each node.
- **/
-void list_free(list_t* list, bool free_contents);
-
-/**
- * @brief Frees all memory used by a node.
- *
- * This function frees all memory allocated to a node. Also frees contents if
- * the free_contents is 1.
- *
- * @param node
- * @param free_contents
- */
-void list_free_node(list_node_t* node, bool free_contents);
-
 /**
  * @brief Returns pointer to first node in the list
  *
@@ -147,7 +125,7 @@ list_node_t* list_push_back( list_t* list, void* contents );
  * This function removes the first node from the list and frees it's associated
  * memory.
  *
- * @param list          The lsit to operate on.
+ * @param list The lsit to operate on.
  *
  * @return Pointer to the newly added node.
  **/
@@ -159,7 +137,7 @@ list_node_t* list_pop_front( list_t* list );
  * This function removes the last node from the list and frees it's associated
  * memory.
  *
- * @param list          The list to operate on.
+ * @param list The list to operate on.
  *
  * @return Pointer to the newly added node.
  **/
@@ -185,26 +163,21 @@ list_node_t* list_insert( list_t* list, size_t index, void* contents);
  *
  * This function traverses the list to the desired index and frees the memory
  * allocated for that node. If the deleted node has a child then the child is
- * reattached to the deleted node's parent. If free_contents is passed a
- * non-zero value then the node's contents pointer is also freed.
+ * reattached to the deleted node's parent.
  *
  * @param list          The list to operate on.
  * @param index         The index of the node to delete.
- * @param free_contents Whether or not to also free the contents of the node.
  *
  * @return Pointer to the node that is now at the supplied index.
  **/
-list_node_t* list_delete( list_t* list, size_t index, bool free_contents);
+list_node_t* list_delete(list_t* list, size_t index);
 
 /**
  * @brief Deletes all elements in the provided list
  *
  * @param list          The list to be cleared
- * @param free_contents Whether or not to also free the contents of every node.
- *
- * @return A pointer to the cleared list.
  */
-list_t* list_clear(list_t* list, bool free_contents);
+void list_clear(list_t* list);
 
 #ifdef __cplusplus
 }
diff --git a/source/mem/mem.c b/source/mem/mem.c
new file mode 100644 (file)
index 0000000..f1b2d86
--- /dev/null
@@ -0,0 +1,60 @@
+#include "mem.h"
+#include <stdlib.h>
+
+typedef struct {
+    int refcount;
+    destructor_t p_finalize;
+} obj_t;
+
+typedef struct {
+    intptr_t val;
+} box_t;
+
+void* mem_allocate(size_t size, destructor_t p_destruct_fn)
+{
+    obj_t* p_obj = (obj_t*)malloc(sizeof(obj_t) + size);
+    p_obj->refcount = 1;
+    p_obj->p_finalize = p_destruct_fn;
+    return (void*)(p_obj+1);
+}
+
+void mem_retain(void* p_obj)
+{
+    obj_t* p_hdr = (((obj_t*)p_obj)-1);
+    p_hdr->refcount += 1;
+}
+
+void mem_release(void* p_obj)
+{
+    obj_t* p_hdr = (((obj_t*)p_obj)-1);
+    p_hdr->refcount -= 1;
+    if(p_hdr->refcount < 1)
+    {
+        if(p_hdr->p_finalize)
+        {
+            p_hdr->p_finalize(p_obj);
+        }
+        free(p_hdr);
+    }
+}
+
+void mem_autorelease(void* p_obj)
+{
+}
+
+void mem_releaseall(void)
+{
+}
+
+void* mem_box(intptr_t val)
+{
+    box_t* p_box = (box_t*)mem_allocate(sizeof(box_t), NULL);
+    p_box->val = val;
+    return (void*)p_box;
+}
+
+intptr_t mem_unbox(void* p_box)
+{
+    return ((box_t*)p_box)->val;
+}
+
diff --git a/source/mem/mem.h b/source/mem/mem.h
new file mode 100644 (file)
index 0000000..3d99bb7
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+  @file mem.h
+  @brief TODO: Describe this file
+  $Revision$
+  $HeadURL$
+  */
+#ifndef MEM_H
+#define MEM_H
+
+#include <stdint.h>
+#include <string.h>
+
+/** A function pointer for object destructors */
+typedef void (*destructor_t)(void* p_val);
+
+/**
+ * @brief Allocates a new reference counted object of the given size which will
+ *        be destructed with the given function before it's memory is reclaimed.
+ *
+ * @param size The number of bytes to allocate for this object.
+ * @param p_destruct_fn The function to call when reclaiming this object.
+ *
+ * @return Pointer to the newly allocated object
+ */
+void* mem_allocate(size_t size, destructor_t p_destruct_fn);
+
+/**
+ * @brief Increments the reference count for the given object.
+ *
+ * @param p_obj The object to be retained.
+ */
+void mem_retain(void* p_obj);
+
+/**
+ * @brief Decrements the reference count for a given object.
+ *
+ * @param p_obj The object to be released.
+ */
+void mem_release(void* p_obj);
+
+/**
+ * @brief Schedules an object to be released at a later time when more convenient.
+ *
+ * @param p_obj The object to be released.
+ */
+void mem_autorelease(void* p_obj);
+
+/**
+ * @brief Release all objects scheduled to be released reclaiming their memory
+ *        if necessary.
+ */
+void mem_releaseall(void);
+
+/**
+ * @brief Create a reference counted box holding the given value so that it can
+ *        be placed in a container.
+ *
+ * @param val The value to be boxed.
+ *
+ * @return The pointer to the newly allocated box.
+ */
+void* mem_box(intptr_t val);
+
+/**
+ * @brief Release a reference counted box and return it's contained value.
+ *
+ * @return The boxed value.
+ */
+intptr_t mem_unbox(void* p_box);
+
+#endif /* MEM_H */
index 298f6850ddfc24893d3971c4e018a5b472ff8e27..591d134d1d07ebb6e3dfd8932c72c4dbf885b5e8 100644 (file)
@@ -71,7 +71,7 @@ void vec_resize(vec_t* p_vec, size_t size, void* data)
     if (size > p_vec->size)
     {
         vec_reserve(p_vec,vec_next_capacity(size));
-        for (p_vec->size; p_vec->size < size; p_vec->size++)
+        for (; p_vec->size < size; p_vec->size++)
         {
             p_vec->p_buffer[ p_vec->size ] = data;
         }
@@ -155,7 +155,7 @@ bool vec_insert(vec_t* p_vec, size_t index, size_t num_elements, ...)
         /* insert the new items */
         va_start(elements, num_elements);
         new_size = index + num_elements;
-        for (index; index < new_size; index++)
+        for (; index < new_size; index++)
         {
             p_vec->p_buffer[index] = va_arg(elements,void*);
         }