build system revision
[vg.git] / vg_mem_pool.c
diff --git a/vg_mem_pool.c b/vg_mem_pool.c
new file mode 100644 (file)
index 0000000..1fe3302
--- /dev/null
@@ -0,0 +1,100 @@
+#include "vg_platform.h"
+#include "vg_mem.h"
+#include "vg_mem_pool.h"
+#include <stddef.h>
+
+/* implementation 
+ * -------------------------------------------------------------------------- */
+
+vg_pool_node *vg_pool_nodeptr( vg_pool *pool, u16 id ){
+   if( !id ) return NULL;
+   else {
+      return pool->buffer + (pool->stride*(id-1)) + pool->offset;
+   }
+}
+
+void *vg_pool_item( vg_pool *pool, u16 id )
+{
+   if( (id == 0) || (id > pool->count) ) 
+      return NULL;
+
+   return pool->buffer + pool->stride*(size_t)(id-1);
+}
+
+void vg_pool_init( vg_pool *pool )
+{
+   pool->head = 1;
+   pool->tail = pool->count;
+   for( u16 ib=1; ib <= pool->count; ib++ ){
+      vg_pool_node *nb = vg_pool_nodeptr( pool, ib );
+
+      u16 ia = ib-1, ic = ib+1;
+      nb->l = ia;
+      nb->r = ic<=pool->count? ic: 0;
+      nb->ref_count = 0;
+   }
+}
+
+u16 vg_pool_id( vg_pool *pool, void *item )
+{
+   return ((item - pool->buffer) / pool->stride) + 1;
+}
+
+static void vg_pool_unlink( vg_pool *pool, u16 id )
+{
+   vg_pool_node *node = vg_pool_nodeptr( pool, id );
+   vg_pool_node *l = vg_pool_nodeptr( pool, node->l ),
+                *r = vg_pool_nodeptr( pool, node->r );
+
+   if( pool->head == id ) pool->head = node->r;
+   if( pool->tail == id ) pool->tail = node->l;
+   
+   if( l ) l->r = node->r;
+   if( r ) r->l = node->l;
+
+   node->r = 0;
+   node->l = 0;
+}
+
+u16 vg_pool_lru( vg_pool *pool )
+{
+   u16 head = pool->head;
+   if( !head ) return 0;
+
+   vg_pool_unlink( pool, head );
+   return head;
+}
+
+void vg_pool_watch( vg_pool *pool, u16 id )
+{
+   vg_pool_node *node = vg_pool_nodeptr( pool, id );
+
+   if( !node->ref_count ){
+      vg_pool_unlink( pool, id );
+   }
+
+   if( node->ref_count == 0xffff )
+      vg_fatal_error( "pool watch missmatch (limit is 128)\n" );
+
+   node->ref_count ++;
+}
+
+/* if after this no more watches, places back into the volatile list */
+void vg_pool_unwatch( vg_pool *pool, u16 id )
+{
+   vg_pool_node *node = vg_pool_nodeptr( pool, id );
+
+   if( node->ref_count == 0 )
+      vg_fatal_error( "pool unwatch missmatch (no watchers)\n" );
+
+   node->ref_count --;
+   if( !node->ref_count ){
+      vg_pool_node *head = vg_pool_nodeptr( pool, pool->head ),
+                   *tail = vg_pool_nodeptr( pool, pool->tail );
+      
+      if( tail ) tail->r = id;
+      node->l = pool->tail;
+      pool->tail = id;
+      if( !head ) pool->head = id;
+   }
+}