tampex.c (4337B)
1 #include <assert.h> 2 #include <stddef.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 #include "tampex.h" 7 8 /* Calculer l’adresse de l’entête d’un tampex. */ 9 #define ENTETE(te) ((Entete *)te - 1) 10 11 /* Calculer l’adresse du tampon d’un tampex. */ 12 #define TAMPON(ent) ((void *)(ent + 1)) 13 14 /* Tester la cohérence d’un tampex. */ 15 #define TAMPINF_COHERENT(te) \ 16 /* Le pointeur n’est pas NULL. */ \ 17 assert(ENTETE(te)); \ 18 /* Un élément a une taille supérieure à zéro. */ \ 19 assert((ENTETE(te))->s.tll > 0); \ 20 /* Le tampon peut contenir au moins un élément. */ \ 21 assert((ENTETE(te))->s.lngr > 0); \ 22 /* Le nombre d’éléments est inférieur ou égal à la longueur. */ \ 23 assert((ENTETE(te))->s.nelem <= (ENTETE(te))->s.lngr); 24 25 /* La structure du tampon extensible a été conçue pour que son utilisation 26 * ressemble le plus possible à celle des tampons renvoyés par malloc(3). C’est 27 * donc sous cette forme qu’ils se présentent à l’utilisateur. Or, une partie 28 * de la réalité lui est cachée, car immédiatement sous le tampon qui lui est 29 * renvoyé se trouve une entête contenant l’information nécessaire au bon 30 * fonctionnement des fonctions de cette bilbiothèque: la taille des éléments 31 * du tampon, exprimée en octets, la longueur du tampon, excluant l’entête et 32 * exprimée en multiples de la taille, et enfin le nombre d’éléments que 33 * contient le tampon. */ 34 35 /* Entête d’un tampex. 36 * L’union assure que l’entête occupe un multiple de sizeof(long) octets. Cette 37 * solution vient de la seconde édition de « The C Programming Language ». */ 38 typedef union entete { 39 struct { 40 size_t tll; /* Taille des éléments. */ 41 size_t lngr; /* Longueur du tampon. */ 42 size_t nelem; /* Nombre d’éléments dans le tampon. */ 43 } s; 44 long alignement; 45 } Entete; 46 47 void * 48 tampex_init(size_t lngr, size_t tll) 49 { 50 Entete *ent; 51 52 assert(lngr > 0); 53 assert(tll > 0); 54 55 if ((ent = malloc(sizeof(Entete) + lngr * tll)) == NULL) 56 return NULL; 57 58 ent->s.tll = tll; 59 ent->s.lngr = lngr; 60 ent->s.nelem = 0; 61 62 /* Initialiser le tampon à zéro. */ 63 tampex_reinit(TAMPON(ent)); 64 65 TAMPINF_COHERENT(TAMPON(ent)); 66 67 return TAMPON(ent); 68 } 69 70 void 71 tampex_reinit(void *te) 72 { 73 TAMPINF_COHERENT(te); 74 75 /* Il faut réinitialiser tout le tampon, non seulement la portion sous 76 * nelem, puisque nelem peut diminuer. Par exemple, tampex_dpl() retire 77 * un élément sans le réinitialiser à zéro. */ 78 memset(te, 0, ENTETE(te)->s.tll * ENTETE(te)->s.lngr); 79 80 ENTETE(te)->s.nelem = 0; 81 } 82 83 void 84 tampex_libr(void *te) 85 { 86 TAMPINF_COHERENT(te); 87 88 free(ENTETE(te)); 89 } 90 91 ssize_t 92 tampex_minim(void **te, size_t i) 93 { 94 size_t nlngr; /* Nouvelle longueur. */ 95 Entete *nent; /* Nouvelle entête. */ 96 size_t nnelem; /* Nouveau nombre d’éléments. */ 97 98 assert(te); 99 TAMPINF_COHERENT(*te); 100 101 /* Mettre à jour le nombre d’éléments, mais ne pas lui permettre de 102 * décroître. */ 103 nnelem = ENTETE(*te)->s.nelem; 104 if (nnelem < i + 1) 105 nnelem = i + 1; 106 107 /* Ne pas agrandir le tampon s’il est déjà assez grand. */ 108 if (ENTETE(*te)->s.lngr > i) { 109 ENTETE(*te)->s.nelem = nnelem; 110 TAMPINF_COHERENT(*te); 111 return i; 112 } 113 114 /* Doubler la longueur jusqu’à ce qu’elle soit supérieure ou égale à la 115 * longueur recherchée. */ 116 for (nlngr = ENTETE(*te)->s.lngr; nlngr <= i; nlngr *= 2) 117 ; 118 119 /* Agrandir le tampon et initialiser à zéro la nouvelle partie. */ 120 if ((nent = realloc(ENTETE(*te), 121 sizeof(Entete) + nlngr * ENTETE(*te)->s.tll)) == NULL) 122 return -1; 123 memset((char *)TAMPON(nent) + nent->s.lngr * nent->s.tll, 0, 124 (nlngr - nent->s.lngr) * nent->s.tll); 125 nent->s.lngr = nlngr; 126 nent->s.nelem = nnelem; 127 128 TAMPINF_COHERENT(TAMPON(nent)); 129 130 *te = TAMPON(nent); 131 132 return i; 133 } 134 135 ssize_t 136 tampex_empl(void **te) 137 { 138 assert(te); 139 TAMPINF_COHERENT(*te); 140 141 return tampex_minim(te, ENTETE(*te)->s.nelem); 142 } 143 144 size_t 145 tampex_dpl(void *te) 146 { 147 TAMPINF_COHERENT(te); 148 149 /* Il doit rester quelque chose à dépiler. */ 150 assert(ENTETE(te)->s.nelem > 0); 151 152 return --ENTETE(te)->s.nelem; 153 } 154 155 size_t 156 tampex_nelem(void *te) 157 { 158 TAMPINF_COHERENT(te); 159 160 return ENTETE(te)->s.nelem; 161 } 162 163 size_t 164 tampex_esp(void *te) 165 { 166 TAMPINF_COHERENT(te); 167 168 return ENTETE(te)->s.nelem * ENTETE(te)->s.tll; 169 } 170 171 bool 172 tampex_dedans(void *te, size_t i) 173 { 174 TAMPINF_COHERENT(te); 175 176 if (i < ENTETE(te)->s.nelem) 177 return 1; 178 return 0; 179 }