/* heap-1.c */ #include #include #include #include #define HEAP_BLOCKS 16 #define BLOCK_CAPACITY 1024 enum block_status { BLK_FREE = 0, BLK_ONE, BLK_FIRST, BLK_CONT, BLK_LAST }; struct heap { struct block { char contents[BLOCK_CAPACITY]; } blocks[HEAP_BLOCKS]; enum block_status status[HEAP_BLOCKS]; } global_heap = {0}; struct block_id { size_t value; bool valid; struct heap* heap; }; struct block_id block_id_new(size_t value, struct heap* from) { return (struct block_id){.valid = true, .value = value, .heap = from}; } struct block_id block_id_invalid() { return (struct block_id){.valid = false}; } bool block_id_is_valid(struct block_id bid) { return bid.valid && bid.value < HEAP_BLOCKS; } /* Find block */ bool block_is_free(struct block_id bid) { if (!block_id_is_valid(bid)) return false; return bid.heap->status[bid.value] == BLK_FREE; } /* Allocate */ struct block_id block_allocate(struct heap* heap, size_t size) { if (size <= 0) return block_id_invalid(); enum block_status* first_status = NULL; enum block_status* last_status = NULL; for (size_t i = 0; i < HEAP_BLOCKS; i++) { if (i + size > HEAP_BLOCKS) return block_id_invalid(); first_status = &(heap->status[i]); if (*first_status != BLK_FREE) continue; bool not_enough_space = false; for (size_t j = i + 1; j < i + size; j++) { last_status = &(heap->status[j]); if (*last_status != BLK_FREE) { not_enough_space = true; break; } } if (not_enough_space) continue; if (size == 1) *first_status = BLK_ONE; else { *first_status = BLK_FIRST; *last_status = BLK_LAST; for (size_t j = i + 1; j < i + size - 1; j++) heap->status[j] = BLK_CONT; } return block_id_new(i, heap); } return block_id_invalid(); } void heap_debug_info(struct heap*, FILE*); /* Free */ void block_free(struct block_id b) { if (!b.valid) return; if (b.heap->status[b.value] == BLK_FREE) return; bool is_last = b.heap->status[b.value] == BLK_ONE; b.heap->status[b.value] = BLK_FREE; for (size_t i = b.value + 1; !is_last; i++) { is_last = b.heap->status[i] == BLK_LAST; b.heap->status[i] = BLK_FREE; } } /* Printer */ const char* block_repr(struct block_id b) { static const char* const repr[] = {[BLK_FREE] = " .", [BLK_ONE] = " *", [BLK_FIRST] = "[=", [BLK_LAST] = "=]", [BLK_CONT] = " ="}; if (b.valid) return repr[b.heap->status[b.value]]; else return "INVALID"; } void block_debug_info(struct block_id b, FILE* f) { fprintf(f, "%s", block_repr(b)); } void block_foreach_printer(struct heap* h, size_t count, void printer(struct block_id, FILE* f), FILE* f) { for (size_t c = 0; c < count; c++) printer(block_id_new(c, h), f); } void heap_debug_info(struct heap* h, FILE* f) { block_foreach_printer(h, HEAP_BLOCKS, block_debug_info, f); fprintf(f, "\n"); } /* -------- */ void heap_free(struct heap* heap) { for (size_t i = 0; i < HEAP_BLOCKS; i++) heap->status[i] = BLK_FREE; } void allocate_block_test(struct heap* heap) { printf("allocate_block_test: "); block_allocate(heap, 1); heap_debug_info(heap, stdout); heap_free(heap); } void allocate_big_block_test(struct heap* heap) { printf("allocate_big_block_test: "); block_allocate(heap, 5); heap_debug_info(heap, stdout); heap_free(heap); } void allocate_multiple_blocks_test(struct heap* heap) { printf("allocate_multiple_blocks_test: "); block_allocate(heap, 7); block_allocate(heap, 1); block_allocate(heap, 3); heap_debug_info(heap, stdout); heap_free(heap); } void allocate_more_than_available_test(struct heap* heap) { printf("allocate_more_than_available_test: "); block_allocate(heap, 17); heap_debug_info(heap, stdout); heap_free(heap); } void allocate_limit_test(struct heap* heap) { printf("allocate_limit_test: "); block_allocate(heap, 16); heap_debug_info(heap, stdout); heap_free(heap); } void allocate_middle_test(struct heap* heap) { printf("allocate_middle_test: "); block_allocate(heap, 5); struct block_id id = block_allocate(heap, 3); block_allocate(heap, 7); block_free(id); block_allocate(heap, 2); heap_debug_info(heap, stdout); heap_free(heap); } void free_block_test(struct heap* heap) { printf("free_block_test: "); struct block_id id = block_allocate(heap, 1); block_free(id); heap_debug_info(heap, stdout); heap_free(heap); } void free_big_block_test(struct heap* heap) { printf("free_big_block_test: "); struct block_id id = block_allocate(heap, 5); block_free(id); heap_debug_info(heap, stdout); heap_free(heap); } void free_multiple_blocks_test(struct heap* heap) { printf("free_multiple_blocks_test: "); struct block_id id1 = block_allocate(heap, 7); struct block_id id2 = block_allocate(heap, 1); struct block_id id3 = block_allocate(heap, 5); block_free(id1); block_free(id2); block_free(id3); heap_debug_info(heap, stdout); heap_free(heap); } int main() { printf("\n"); allocate_block_test(&global_heap); allocate_big_block_test(&global_heap); allocate_multiple_blocks_test(&global_heap); allocate_more_than_available_test(&global_heap); allocate_limit_test(&global_heap); allocate_middle_test(&global_heap); free_block_test(&global_heap); free_big_block_test(&global_heap); free_multiple_blocks_test(&global_heap); printf("\n"); return 0; }