#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
struct buddy2 {
|
|
unsigned size;
|
|
unsigned longest[1];
|
|
};
|
|
|
|
struct buddy2* buddy2_new( int size );
|
|
void buddy2_destroy( struct buddy2* self );
|
|
|
|
int buddy2_alloc(struct buddy2* self, int size);
|
|
void buddy2_free(struct buddy2* self, int offset);
|
|
|
|
int buddy2_size(struct buddy2* self, int offset);
|
|
void buddy2_dump(struct buddy2* self);
|
|
|
|
#define LEFT_LEAF(index) ((index) * 2 + 1)
|
|
#define RIGHT_LEAF(index) ((index) * 2 + 2)
|
|
#define PARENT(index) ( ((index) + 1) / 2 - 1)
|
|
|
|
#define IS_POWER_OF_2(x) (!((x)&((x)-1)))
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
#define ALLOC malloc
|
|
#define FREE free
|
|
|
|
static unsigned fixsize(unsigned size) {
|
|
size |= size >> 1;
|
|
size |= size >> 2;
|
|
size |= size >> 4;
|
|
size |= size >> 8;
|
|
size |= size >> 16;
|
|
return size+1;
|
|
}
|
|
|
|
struct buddy2* buddy2_new( int size ) {
|
|
struct buddy2* self;
|
|
unsigned node_size;
|
|
int i;
|
|
|
|
if (size < 1 || !IS_POWER_OF_2(size))
|
|
return NULL;
|
|
|
|
self = (struct buddy2*)ALLOC( 2 * size * sizeof(unsigned));
|
|
self->size = size;
|
|
node_size = size * 2;
|
|
|
|
for (i = 0; i < 2 * size - 1; ++i) {
|
|
if (IS_POWER_OF_2(i+1))
|
|
node_size /= 2;
|
|
self->longest[i] = node_size;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
void buddy2_destroy( struct buddy2* self) {
|
|
FREE(self);
|
|
}
|
|
|
|
int buddy2_alloc(struct buddy2* self, int size) {
|
|
unsigned index = 0;
|
|
unsigned node_size;
|
|
unsigned offset = 0;
|
|
|
|
if (self==NULL)
|
|
return -1;
|
|
|
|
if (size <= 0)
|
|
size = 1;
|
|
else if (!IS_POWER_OF_2(size))
|
|
size = fixsize(size);
|
|
|
|
if (self->longest[index] < size)
|
|
return -1;
|
|
|
|
for(node_size = self->size; node_size != size; node_size /= 2 ) {
|
|
if (self->longest[LEFT_LEAF(index)] >= size)
|
|
index = LEFT_LEAF(index);
|
|
else
|
|
index = RIGHT_LEAF(index);
|
|
}
|
|
|
|
self->longest[index] = 0;
|
|
offset = (index + 1) * node_size - self->size;
|
|
|
|
while (index) {
|
|
index = PARENT(index);
|
|
self->longest[index] =
|
|
MAX(self->longest[LEFT_LEAF(index)], self->longest[RIGHT_LEAF(index)]);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
void buddy2_free(struct buddy2* self, int offset) {
|
|
unsigned node_size, index = 0;
|
|
unsigned left_longest, right_longest;
|
|
|
|
assert(self && offset >= 0 && offset < self->size);
|
|
|
|
node_size = 1;
|
|
index = offset + self->size - 1;
|
|
|
|
for (; self->longest[index] ; index = PARENT(index)) {
|
|
node_size *= 2;
|
|
if (index == 0)
|
|
return;
|
|
}
|
|
|
|
self->longest[index] = node_size;
|
|
|
|
while (index) {
|
|
index = PARENT(index);
|
|
node_size *= 2;
|
|
|
|
left_longest = self->longest[LEFT_LEAF(index)];
|
|
right_longest = self->longest[RIGHT_LEAF(index)];
|
|
|
|
if (left_longest + right_longest == node_size)
|
|
self->longest[index] = node_size;
|
|
else
|
|
self->longest[index] = MAX(left_longest, right_longest);
|
|
}
|
|
}
|
|
|
|
int buddy2_size(struct buddy2* self, int offset) {
|
|
unsigned node_size, index = 0;
|
|
|
|
assert(self && offset >= 0 && offset < self->size);
|
|
|
|
node_size = 1;
|
|
for (index = offset + self->size - 1; self->longest[index] ; index = PARENT(index))
|
|
node_size *= 2;
|
|
|
|
return node_size;
|
|
}
|
|
|
|
void buddy2_dump(struct buddy2* self) {
|
|
char canvas[65];
|
|
int i,j;
|
|
unsigned node_size, offset;
|
|
|
|
if (self == NULL) {
|
|
printf("buddy2_dump: (struct buddy2*)self == NULL");
|
|
return;
|
|
}
|
|
|
|
if (self->size > 64) {
|
|
printf("buddy2_dump: (struct buddy2*)self is too big to dump");
|
|
return;
|
|
}
|
|
|
|
memset(canvas,'_', sizeof(canvas));
|
|
node_size = self->size * 2;
|
|
|
|
for (i = 0; i < 2 * self->size - 1; ++i) {
|
|
if ( IS_POWER_OF_2(i+1) )
|
|
node_size /= 2;
|
|
|
|
if ( self->longest[i] == 0 ) {
|
|
if (i >= self->size - 1) {
|
|
canvas[i - self->size + 1] = '*';
|
|
}
|
|
else if (self->longest[LEFT_LEAF(i)] && self->longest[RIGHT_LEAF(i)]) {
|
|
offset = (i+1) * node_size - self->size;
|
|
|
|
for (j = offset; j < offset + node_size; ++j)
|
|
canvas[j] = '*';
|
|
}
|
|
}
|
|
}
|
|
canvas[self->size] = '\0';
|
|
puts(canvas);
|
|
}
|
|
|
|
int main() {
|
|
char cmd[80];
|
|
int arg;
|
|
struct buddy2* buddy = buddy2_new(32);
|
|
buddy2_dump(buddy);
|
|
for (;;) {
|
|
scanf("%s %d", cmd, &arg);
|
|
if (strcmp(cmd, "alloc") == 0) {
|
|
printf("allocated@%d\n", buddy2_alloc(buddy, arg));
|
|
buddy2_dump(buddy);
|
|
} else if (strcmp(cmd, "free") == 0) {
|
|
buddy2_free(buddy, arg);
|
|
buddy2_dump(buddy);
|
|
} else if (strcmp(cmd, "size") == 0) {
|
|
printf("size: %d\n", buddy2_size(buddy, arg));
|
|
buddy2_dump(buddy);
|
|
} else
|
|
buddy2_dump(buddy);
|
|
}
|
|
}
|