#include #include #include #include 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); } }