xref: /plan9/sys/src/cmd/aquarela/smbidmap.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 
3 #define INITIALCHUNKSIZE 10
4 
5 typedef struct Entry {
6 	void *p;
7 	long freechain;
8 } Entry;
9 
10 struct SmbIdMap {
11 	Entry *array;
12 	ulong entries;
13 	long freeindex;
14 };
15 
16 SmbIdMap *
smbidmapnew(void)17 smbidmapnew(void)
18 {
19 	SmbIdMap *m;
20 	m = smbemallocz(sizeof(SmbIdMap), 1);
21 	m->freeindex = -1;
22 	return m;
23 }
24 
25 void
smbidmapremovebyid(SmbIdMap * m,long id)26 smbidmapremovebyid(SmbIdMap *m, long id)
27 {
28 	if (m == nil)
29 		return;
30 	assert(id > 0);
31 	id--;
32 	assert(id >= 0 && id < m->entries);
33 	assert(m->array[id].freechain == -2);
34 	m->array[id].freechain = m->freeindex;
35 	m->freeindex = id;
36 }
37 
38 void
smbidmapremove(SmbIdMap * m,void * thing)39 smbidmapremove(SmbIdMap *m, void *thing)
40 {
41 	long id;
42 	if (m == nil)
43 		return;
44 	id = *(long *)thing;
45 	smbidmapremovebyid(m, id);
46 }
47 
48 void
smbidmapremoveif(SmbIdMap * m,int (* f)(void * p,void * arg),void * arg)49 smbidmapremoveif(SmbIdMap *m, int (*f)(void *p, void *arg), void *arg)
50 {
51 	int i;
52 	if (m == nil)
53 		return;
54 	for (i = 0; i < m->entries; i++)
55 		if (m->array[i].freechain == -2 && (*f)(m->array[i].p, arg))
56 			smbidmapremovebyid(m, i + 1);
57 }
58 
59 static void
grow(SmbIdMap * m)60 grow(SmbIdMap *m)
61 {
62 	long x;
63 	long oldentries = m->entries;
64 	if (m->entries == 0)
65 		m->entries = INITIALCHUNKSIZE;
66 	else
67 		m->entries *= 2;
68 	smberealloc(&m->array, sizeof(Entry) * m->entries);
69 	for (x = m->entries - 1; x >= oldentries; x--) {
70 		m->array[x].freechain = m->freeindex;
71 		m->freeindex = x;
72 	}
73 }
74 
75 long
smbidmapadd(SmbIdMap * m,void * p)76 smbidmapadd(SmbIdMap *m, void *p)
77 {
78 	long i;
79 	if (m->freeindex < 0)
80 		grow(m);
81 	i = m->freeindex;
82 	m->freeindex = m->array[i].freechain;
83 	m->array[i].freechain = -2;
84 	m->array[i].p = p;
85 	*(long *)p = i + 1;
86 	return i + 1;
87 }
88 
89 void *
smbidmapfind(SmbIdMap * m,long id)90 smbidmapfind(SmbIdMap *m, long id)
91 {
92 	if (m == nil)
93 		return nil;
94 	if (id <= 0)
95 		return nil;
96 	id--;
97 	if (id < 0 || id > m->entries || m->array[id].freechain != -2)
98 		return nil;
99 	return m->array[id].p;
100 }
101 
102 void
smbidmapfree(SmbIdMap ** mp,SMBIDMAPAPPLYFN * freefn,void * magic)103 smbidmapfree(SmbIdMap **mp, SMBIDMAPAPPLYFN *freefn, void *magic)
104 {
105 	SmbIdMap *m = *mp;
106 	if (m) {
107 		long i;
108 		if (freefn) {
109 			for (i = 0; i < m->entries; i++)
110 				if (m->array[i].freechain == -2)
111 					(*freefn)(magic, m->array[i].p);
112 		}
113 		free(m->array);
114 		free(m);
115 		*mp = nil;
116 	}
117 }
118 
119 void
smbidmapapply(SmbIdMap * m,SMBIDMAPAPPLYFN * applyfn,void * magic)120 smbidmapapply(SmbIdMap *m, SMBIDMAPAPPLYFN *applyfn, void *magic)
121 {
122 	if (m) {
123 		long i;
124 		for (i = 0; i < m->entries; i++)
125 			if (m->array[i].freechain == -2)
126 				(*applyfn)(magic, m->array[i].p);
127 	}
128 }
129