xref: /plan9/sys/src/libbin/bin.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
1 #include <u.h>
2 #include <libc.h>
3 #include <bin.h>
4 
5 enum
6 {
7 	StructAlign = sizeof(union {vlong vl; double d; ulong p; void *v;
8 				struct{vlong v;}vs; struct{double d;}ds; struct{ulong p;}ss; struct{void *v;}xs;})
9 };
10 
11 enum
12 {
13 	BinSize	= 8*1024
14 };
15 
16 struct Bin
17 {
18 	Bin	*next;
19 	ulong	total;			/* total bytes allocated in can->next */
20 	uintptr	pos;
21 	uintptr	end;
22 	uintptr	v;			/* last value allocated */
23 	uchar	body[BinSize];
24 };
25 
26 /*
27  * allocator which allows an entire set to be freed at one time
28  */
29 static Bin*
mkbin(Bin * bin,ulong size)30 mkbin(Bin *bin, ulong size)
31 {
32 	Bin *b;
33 
34 	size = ((size << 1) + (BinSize - 1)) & ~(BinSize - 1);
35 	b = malloc(sizeof(Bin) + size - BinSize);
36 	if(b == nil)
37 		return nil;
38 	b->next = bin;
39 	b->total = 0;
40 	if(bin != nil)
41 		b->total = bin->total + bin->pos - (uintptr)bin->body;
42 	b->pos = (uintptr)b->body;
43 	b->end = b->pos + size;
44 	return b;
45 }
46 
47 void*
binalloc(Bin ** bin,ulong size,int zero)48 binalloc(Bin **bin, ulong size, int zero)
49 {
50 	Bin *b;
51 	uintptr p;
52 
53 	if(size == 0)
54 		size = 1;
55 	b = *bin;
56 	if(b == nil){
57 		b = mkbin(nil, size);
58 		if(b == nil)
59 			return nil;
60 		*bin = b;
61 	}
62 	p = b->pos;
63 	p = (p + (StructAlign - 1)) & ~(StructAlign - 1);
64 	if(p + size > b->end){
65 		b = mkbin(b, size);
66 		if(b == nil)
67 			return nil;
68 		*bin = b;
69 		p = b->pos;
70 	}
71 	b->pos = p + size;
72 	b->v = p;
73 	if(zero)
74 		memset((void*)p, 0, size);
75 	return (void*)p;
76 }
77 
78 void*
bingrow(Bin ** bin,void * op,ulong osize,ulong size,int zero)79 bingrow(Bin **bin, void *op, ulong osize, ulong size, int zero)
80 {
81 	Bin *b;
82 	void *np;
83 	uintptr p;
84 
85 	p = (uintptr)op;
86 	b = *bin;
87 	if(b != nil && p == b->v && p + size <= b->end){
88 		b->pos = p + size;
89 		if(zero)
90 			memset((char*)p + osize, 0, size - osize);
91 		return op;
92 	}
93 	np = binalloc(bin, size, zero);
94 	if(np == nil)
95 		return nil;
96 	memmove(np, op, osize);
97 	return np;
98 }
99 
100 void
binfree(Bin ** bin)101 binfree(Bin **bin)
102 {
103 	Bin *last;
104 
105 	while(*bin != nil){
106 		last = *bin;
107 		*bin = (*bin)->next;
108 		last->pos = (uintptr)last->body;
109 		free(last);
110 	}
111 }
112