|
|
@ -0,0 +1,198 @@ |
|
|
|
#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); |
|
|
|
} |
|
|
|
} |