pl-sem/sem6/heap-1.c
2023-08-18 01:08:53 +03:00

212 lines
5.5 KiB
C

/* heap-1.c */
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}