moev pool here
[vg.git] / vg_mem_pool.h
1 #ifndef VG_MEM_POOL_H
2 #define VG_MEM_POOL_H
3
4 /* pool for loaded addons */
5 #define VG_POOL_NIL 0xffff
6
7 typedef struct vg_pool vg_pool;
8 typedef struct vg_pool_node vg_pool_node;
9
10 /* this goes in your structures */
11 struct vg_pool_node {
12 u16 l, r, ref_count;
13 };
14
15 struct vg_pool {
16 void *buffer; /* array which holds the real data */
17 u16 count, head, tail;
18 size_t stride, offset;
19 };
20
21 static vg_pool_node *vg_pool_nodeptr ( vg_pool *pool, void *item );
22 static void *vg_pool_item ( vg_pool *pool, u16 index );
23 static void vg_pool_init ( vg_pool *pool );
24 static u16 addon_item_index ( vg_pool *pool, void *item );
25 static void *vg_pool_lru ( vg_pool *pool );
26 static void vg_pool_watch ( vg_pool *pool, void *item );
27 static void vg_pool_unwatch ( vg_pool *pool, void *item );
28
29 /* implementation
30 * -------------------------------------------------------------------------- */
31
32 static vg_pool_node *vg_pool_nodeptr( vg_pool *pool, void *item ){
33 if( !item ) return NULL;
34 else return item + pool->offset;
35 }
36
37 static void *vg_pool_item( vg_pool *pool, u16 index ){
38 if( index == VG_POOL_NIL ) return NULL;
39 else return pool->buffer + pool->stride*(size_t)index;
40 }
41
42 static void vg_pool_init( vg_pool *pool ){
43 pool->head = 0;
44 pool->tail = pool->count -1;
45 for( i32 ib=0; ib < pool->count; ib++ ){
46 void *vb = vg_pool_item( pool, ib );
47 vg_pool_node *nb = vg_pool_nodeptr( pool, vb );
48
49 i32 ia = ib-1, ic = ib+1;
50 nb->l = ia>=0? ia: VG_POOL_NIL,
51 nb->r = ic<pool->count? ic: VG_POOL_NIL;
52 nb->ref_count = 0;
53 }
54 }
55
56 static u16 addon_item_index( vg_pool *pool, void *item ){
57 return (item - pool->buffer) / pool->stride;
58 }
59
60 static void *vg_pool_lru( vg_pool *pool ){
61 u16 head = pool->head;
62 if( head == VG_POOL_NIL ) return NULL;
63
64 void *item = vg_pool_item( pool, head );
65 vg_pool_node *node = vg_pool_nodeptr( pool, item );
66
67 if( pool->head == pool->tail ) pool->tail = VG_POOL_NIL;
68 pool->head = node->r;
69
70 node->l = VG_POOL_NIL;
71 node->r = VG_POOL_NIL;
72 return item;
73 }
74
75 static void vg_pool_watch( vg_pool *pool, void *item ){
76 vg_pool_node *node = vg_pool_nodeptr( pool, item );
77
78 if( node->ref_count >= 128 )
79 vg_fatal_error( "pool watch missmatch (limit is 128)\n" );
80
81 node->ref_count ++;
82 }
83
84 /* if after this no more watches, places back into the volatile list */
85 static void vg_pool_unwatch( vg_pool *pool, void *item ){
86 vg_pool_node *node = vg_pool_nodeptr( pool, item );
87
88 if( node->ref_count == 0 )
89 vg_fatal_error( "pool unwatch missmatch (no watchers)\n" );
90
91 node->ref_count --;
92 if( !node->ref_count ){
93 void *item_head = vg_pool_item( pool, pool->head ),
94 *item_tail = vg_pool_item( pool, pool->tail );
95 vg_pool_node *head = vg_pool_nodeptr( pool, item_head ),
96 *tail = vg_pool_nodeptr( pool, item_tail );
97
98 u16 index = addon_item_index( pool, item );
99 if( tail ) tail->r = index;
100 node->l = pool->tail;
101 pool->tail = index;
102 if( !head ) pool->head = index;
103 }
104 }
105
106 #endif /* VG_MEM_POOL_H */