1 #include "buddy.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <assert.h>
6 #include <string.h>
7
8 #define NODE_UNUSED 0
9 #define NODE_USED 1
10 #define NODE_SPLIT 2
11 #define NODE_FULL 3
12
13 struct buddy {
14 int level;
15 uint8_t tree[1];
16 };
17
18 struct buddy *
19 buddy_new(int level) {
20 int size = 1 << level;
21 struct buddy * self = malloc(sizeof(struct buddy) + sizeof(uint8_t) * (size * 2 - 2));
22 self->level = level;
23 memset(self->tree , NODE_UNUSED , size*2-1);
24 return self;
25 }
26
27 void
28 buddy_delete(struct buddy * self) {
29 free(self);
30 }
31
32 static inline int
33 is_pow_of_2(uint32_t x) {
34 return !(x & (x-1));
35 }
36
37 static inline uint32_t
38 next_pow_of_2(uint32_t x) {
39 if ( is_pow_of_2(x) )
40 return x;
41 x |= x>>1;
42 x |= x>>2;
43 x |= x>>4;
44 x |= x>>8;
45 x |= x>>16;
46 return x+1;
47 }
48
49 static inline int
50 _index_offset(int index, int level, int max_level) {
51 return ((index + 1) - (1 << level)) << (max_level - level);
52 }
53
54 static void
55 _mark_parent(struct buddy * self, int index) {
56 for (;;) {
57 int buddy = index - 1 + (index & 1) * 2;
58 if (buddy > 0 && (self->tree[buddy] == NODE_USED || self->tree[buddy] == NODE_FULL)) {
59 index = (index + 1) / 2 - 1;
60 self->tree[index] = NODE_FULL;
61 } else {
62 return;
63 }
64 }
65 }
66
67 int
68 buddy_alloc(struct buddy * self , int s) {
69 int size;
70 if (s==0) {
71 size = 1;
72 } else {
73 size = (int)next_pow_of_2(s);
74 }
75 int length = 1 << self->level;
76
77 if (size > length)
78 return -1;
79
80 int index = 0;
81 int level = 0;
82
83 while (index >= 0) {
84 if (size == length) {
85 if (self->tree[index] == NODE_UNUSED) {
86 self->tree[index] = NODE_USED;
87 _mark_parent(self, index);
88 return _index_offset(index, level, self->level);
89 }
90 } else {
91 // size < length
92 switch (self->tree[index]) {
93 case NODE_USED:
94 case NODE_FULL:
95 break;
96 case NODE_UNUSED:
97 // split first
98 self->tree[index] = NODE_SPLIT;
99 self->tree[index*2+1] = NODE_UNUSED;
100 self->tree[index*2+2] = NODE_UNUSED;
101 default:
102 index = index * 2 + 1;
103 length /= 2;
104 level++;
105 continue;
106 }
107 }
108 if (index & 1) {
109 ++index;
110 continue;
111 }
112 for (;;) {
113 level--;
114 length *= 2;
115 index = (index+1)/2 -1;
116 if (index < 0)
117 return -1;
118 if (index & 1) {
119 ++index;
120 break;
121 }
122 }
123 }
124
125 return -1;
126 }
127
128 static void
129 _combine(struct buddy * self, int index) {
130 for (;;) {
131 int buddy = index - 1 + (index & 1) * 2;
132 if (buddy < 0 || self->tree[buddy] != NODE_UNUSED) {
133 self->tree[index] = NODE_UNUSED;
134 while (((index = (index + 1) / 2 - 1) >= 0) && self->tree[index] == NODE_FULL){
135 self->tree[index] = NODE_SPLIT;
136 }
137 return;
138 }
139 index = (index + 1) / 2 - 1;
140 }
141 }
142
143 void
144 buddy_free(struct buddy * self, int offset) {
145 assert( offset < (1<< self->level));
146 int left = 0;
147 int length = 1 << self->level;
148 int index = 0;
149
150 for (;;) {
151 switch (self->tree[index]) {
152 case NODE_USED:
153 assert(offset == left);
154 _combine(self, index);
155 return;
156 case NODE_UNUSED:
157 assert(0);
158 return;
159 default:
160 length /= 2;
161 if (offset < left + length) {
162 index = index * 2 + 1;
163 } else {
164 left += length;
165 index = index * 2 + 2;
166 }
167 break;
168 }
169 }
170 }
171
172 int
173 buddy_size(struct buddy * self, int offset) {
174 assert( offset < (1<< self->level));
175 int left = 0;
176 int length = 1 << self->level;
177 int index = 0;
178
179 for (;;) {
180 switch (self->tree[index]) {
181 case NODE_USED:
182 assert(offset == left);
183 return length;
184 case NODE_UNUSED:
185 assert(0);
186 return length;
187 default:
188 length /= 2;
189 if (offset < left + length) {
190 index = index * 2 + 1;
191 } else {
192 left += length;
193 index = index * 2 + 2;
194 }
195 break;
196 }
197 }
198 }
199
200 static void
201 _dump(struct buddy * self, int index , int level) {
202 switch (self->tree[index]) {
203 case NODE_UNUSED:
204 printf("(%d:%d)", _index_offset(index, level, self->level) , 1 << (self->level - level));
205 break;
206 case NODE_USED:
207 printf("[%d:%d]", _index_offset(index, level, self->level) , 1 << (self->level - level));
208 break;
209 case NODE_FULL:
210 printf("{");
211 _dump(self, index * 2 + 1 , level+1);
212 _dump(self, index * 2 + 2 , level+1);
213 printf("}");
214 break;
215 default:
216 printf("(");
217 _dump(self, index * 2 + 1 , level+1);
218 _dump(self, index * 2 + 2 , level+1);
219 printf(")");
220 break;
221 }
222 }
223
224 void
225 buddy_dump(struct buddy * self) {
226 _dump(self, 0 , 0);
227 printf("\n");
228 }