diff --git a/dm_alloc/allocateur_entete_pied.c b/dm_alloc/allocateur_entete_pied.c new file mode 100644 index 0000000..edc6f2d --- /dev/null +++ b/dm_alloc/allocateur_entete_pied.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include + +// Comme uint64_t est un peu pénible à taper, on utilise +// un typedef : +typedef uint64_t ui; + +#define HEAP_SIZE 32 + +ui heap[HEAP_SIZE]; + +// Cette fonction convertit un pointeur (qui doit être issu de +// malloc_ui) en un indice dans le tableau heap. +// Vous en aurez besoin pour écrire les différentes versions +// de free_ui (juste un appel au début, ensuite on ne manipule plus +// que des indices), mais il est complètement normal de ne pas +// comprendre comment elle fonctionne : c'est de l'arithmétique des +// pointeurs, qui est hors programme. +ui heap_index(ui *p) { return p - heap; } + +// Cette fonction initialise le tas à une valeur particulière, que +// vous avez peu de chance d'utiliser par hasard. Cela nous +// permettra en pratique de repérer les cases dont la valeur n'a +// jamais été modifiée quand on affiche le contenu du tas. +// Elle est destinée à être appelée une unique fois, tout au début +// de l'exécution du programme. +void pre_initialize_heap(void) { + for (ui i = 0; i < HEAP_SIZE; i++) { + heap[i] = 0xFFFFFFFF; + } +} + +// La fonction suivante affiche le contenu du tas. Les cases +// identifiées comme n'ayant jamais été modifiées sont affichées +// de manière particulière. +void print_heap(void) { + for (ui i = 0; i < HEAP_SIZE; i++) { + ui x = heap[i]; + if (x == 0xFFFFFFFF) { + printf("... "); + } else { + printf("%3" PRIu64 " ", x); + } + } + printf("\n"); +} + +void set_memory(ui *p, ui size, ui value) { + for (ui i = 0; i < size; i++) { + p[i] = value; + } +} + +const uint64_t prologue = 2; + +bool is_free(uint64_t i) { return heap[i - 1] % 2 == 0; } + +uint64_t read_size(uint64_t i) { return heap[i - 1] - (heap[i - 1] & 0b1); } + +void set_free(uint64_t i, uint64_t size) { + size += ((size & 0b1) << 1); + heap[i - 1] = size - (size & 0b1); + heap[i + size] = size - (size & 0b1); +} + +void set_used(uint64_t i, uint64_t size) { + size += ((size & 0b1) << 1); + heap[i - 1] = size | 0b1; + heap[i + size] = size | 0b1; +} + +// À ne pas appeler sur l'épilogue +uint64_t next(uint64_t i) { return i + read_size(i) + 2; } + +// À ne pas appeler sur le prologue +uint64_t previous(uint64_t i) { + return i - (heap[i - 2] - (heap[i - 2] % 2)) - 2; +} + +void init_heap(void) { + heap[0] = 4; + heap[1] = 1; + heap[2] = 1; + heap[3] = 1; + heap[4] = 1; +} + +// Complexité : O(n) +uint64_t *malloc_ui64(uint64_t size) { + if (size == 0) { + return NULL; + } + size += ((size & 0b1) << 1) - (size & 0b1); + ui i = 2; + while (i < heap[0]) { + ui rs = read_size(i); + if (is_free(i) && rs >= size) { + set_used(i, size); + if (rs >= size + 2) { + set_free(i + size + 2, rs - size - 2); + } + return &heap[i]; + } else { + i = next(i); + } + } + if (i + size + 2 >= HEAP_SIZE) { + return NULL; + } else { + set_used(i, size); + set_used(i + size + 2, 0); + heap[0] = i + size + 2; + return &heap[i]; + } +} + +// Complexité : O(1) +void free_ui64(uint64_t *p) { + uint64_t i = heap_index(p); + ui size = read_size(i); + ui pre = previous(i); + ui nex = next(i); + if (is_free(pre)) { + i = pre; + size += read_size(pre) + 2; + } + if (is_free(nex)) { + size += read_size(nex) + 2; + } + if (nex == heap[0]) { + set_used(i, 0); + heap[0] = i; + } else { + set_free(i, size); + } +} + +// Q13 : Pour qu'une allocations future n'ai pas à additionner les capacités +// pour savoir si elle peut allouer une grosse zone + +// Q14 : first fit est plus efficace en temps, best fit est plus efficace en +// espace. + +int main(void) { + + pre_initialize_heap(); + + // Pour tester, une fois que les fonctions sont implémentées + init_heap(); + + ui *p = malloc_ui64(8); + set_memory(p, 8, 33); + ui *q = malloc_ui64(2); + set_memory(q, 2, 44); + free_ui64(p); + ui *r = malloc_ui64(7); + set_memory(r, 7, 55); + print_heap(); + free_ui64(r); + free_ui64(q); + + uint64_t *p1 = malloc_ui64(6); + uint64_t *p2 = malloc_ui64(7); + uint64_t *p3 = malloc_ui64(1); + set_memory(p1, 6, 42); + set_memory(p2, 7, 52); + set_memory(p3, 1, 62); + print_heap(); + + free_ui64(p2); + print_heap(); + + uint64_t *p4 = malloc_ui64(2); + set_memory(p4, 2, 72); + print_heap(); + + free_ui64(p3); + print_heap(); + + return EXIT_SUCCESS; +}