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 }
时间: 2024-11-10 09:13:07