trafi

Transducteurs finis
git clone git://git.asteride.xyz/trafi.git
Journaux | Fichiers | Références

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 }