Buddy Memorry

  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("
");
228 }
原文地址:https://www.cnblogs.com/YipWingTim/p/4379513.html