dm_alloc Q7-14
This commit is contained in:
parent
8c2bc954a6
commit
9c9e2ef5ad
184
dm_alloc/allocateur_entete_pied.c
Normal file
184
dm_alloc/allocateur_entete_pied.c
Normal file
@ -0,0 +1,184 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user