commit 638ca1dfb964cbec03899453ef452acb190eebc9
parent 03ca6b6c5a2318d1d03e1fc62b50b993f652a632
Auteur: Loïc Daignault-Pichette <loic@asteride.xyz>
Date: Fri, 3 Apr 2026 17:28:29 -0400
Apporter des changements substanciels à tampinf
Ils peuvent maintenant être manipulés comme des tableaux normaux dans un
grand nombre de cas.
Diffstat:
| M | tampinf.c | | | 220 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
| M | tampinf.h | | | 42 | ++++++++++++++---------------------------- |
2 fichiers modifiés, 102 insertions(+), 160 suppressions(-)
diff --git a/tampinf.c b/tampinf.c
@@ -5,222 +5,178 @@
#include "tampinf.h"
+/* Calculer l’adresse de l’entête d’un taminf. */
+#define ENTETE(ti) ((Entete *)ti - 1)
+
+/* Calculer l’adresse du tampon d’un tampinf. */
+#define TAMPON(ent) (ent + 1)
+
+/* Tester la cohérence du tampon. */
#define TAMPINF_COHERENT(ti) \
/* Le pointeur n’est pas NULL. */ \
- assert(ti); \
- /* Le pointeur vers le contenu n’est pas NULL. */ \
- assert((ti)->ctn); \
- /* Un élément a une taille supérieure à zéro. */ \
- assert((ti)->tll > 0); \
- /* Le tampon peut contenir au moins un élément. */ \
- assert((ti)->lngr > 0); \
- /* Le nombre d’éléments est inférieur ou égal à la longueur. */ \
- assert((ti)->nelem <= (ti)->lngr);
-
-/* La structure d’un tampinf comporte quatre champs. Le premier contient est un
- * pointeur vers le contenu du tampon, placé dans un espace alloué par malloc().
- * Le deuxième champ contient la taille d’un élément du tampon, exprimée en
- * octets. Le troisième champ donne la longueur actuelle du tampon, en multiples
- * de la taille. Le caracètre extensible de la structure fait qu’elle est
- * susceptible d’augmenter. Enfin, le quatrième champ indique le nombre
- * d’éléments placés dans le tampon. */
-
-struct tampinf {
- void *ctn; /* Contenu. */
- size_t tll; /* Taille d’un élément. */
- size_t lngr; /* Longueur du tampon. */
- size_t nelem; /* Nombre d’éléments dans le tampon. */
-};
+ assert(ENTETE(ti)); \
+ /* Un élémENTETE(ti) a une taille supérieure à zéro. */ \
+ assert((ENTETE(ti))->s.tll > 0); \
+ /* Le tampon peut contenir au moins un élémENTETE(ti). */ \
+ assert((ENTETE(ti))->s.lngr > 0); \
+ /* Le nombre d’élémENTETE(ti)s est inférieur ou égal à la longueur. */ \
+ assert((ENTETE(ti))->s.nelem <= (ENTETE(ti))->s.lngr);
+
+/* La structure du tampon infini a été conçue pour que son utilisation
+ * ressemble le plus possible à celle des tableaux statiques. C’est donc sous
+ * cette forme qu’ils se présentent à l’utilisateur. Or, une partie de la
+ * réalité lui est cachée, car sous le tampon qui lui est renvoyé sous trouve
+ * une entête contenant l’information nécessaires au bon fonctionnement des
+ * fonctions de cette bilbiothèque: la taille des éléments du tampon, exprimée
+ * en octets, la longueur du tampon, excluant l’entête et exprimée en multiples
+ * de la taille, et enfin le nombre d’éléments que contient le tampon. */
+
+/* Entête d’un tampinf.
+ * L’union assure que l’entête occupe un multiple de sizeof(long) octets. */
+typedef union entete {
+ struct {
+ size_t tll; /* Taille des éléments. */
+ size_t lngr; /* Longueur du tampon. */
+ size_t nelem; /* Nombre d’éléments dans le tampon. */
+ } s;
+ long alignement;
+} Entete;
/* Faire qu’un tampon soit au moins aussi grand que lngr.
* Prend pour acquis que la longueur du tampon est inférieure à lngr.
- * Renvoie la longueur du tatmpon, ou -1 en cas d’erreur. */
-static ssize_t tampinf_agr(struct tampinf *ti, size_t lngr);
+ * Renvoie l’adresse du tampon, ou NULL en cas d’erreur. */
+static void *tampinf_agr(void *ti, size_t lngr);
-struct tampinf *
+void *
tampinf_init(size_t lngr, size_t tll)
{
- struct tampinf *ti;
+ Entete *ent;
assert(lngr > 0);
assert(tll > 0);
- if ((ti = malloc(sizeof(struct tampinf))) == NULL)
+ if ((ent = malloc(sizeof(Entete) + lngr * tll)) == NULL)
return NULL;
- if ((ti->ctn = calloc(lngr, tll)) == NULL) {
- free(ti);
- return NULL;
- }
+ ent->s.tll = tll;
+ ent->s.lngr = lngr;
+ ent->s.nelem = 0;
- ti->lngr = lngr;
- ti->tll = tll;
- ti->nelem = 0;
+ tampinf_reinit(TAMPON(ent));
- TAMPINF_COHERENT(ti);
+ TAMPINF_COHERENT(TAMPON(ent));
- return ti;
+ return TAMPON(ent);
}
void
-tampinf_reinit(struct tampinf *ti)
+tampinf_reinit(void *ti)
{
TAMPINF_COHERENT(ti);
- memset(ti->ctn, 0, ti->nelem);
- ti->nelem = 0;
+ memset(ti, 0, ENTETE(ti)->s.tll * ENTETE(ti)->s.nelem);
+
+ ENTETE(ti)->s.nelem = 0;
}
void
-tampinf_libr(struct tampinf *ti)
+tampinf_libr(void *ti)
{
TAMPINF_COHERENT(ti);
- free(ti->ctn);
- free(ti);
+ free(ENTETE(ti));
}
-ssize_t
-tampinf_plc(struct tampinf *ti, size_t i, size_t n, void *elem)
-{
- TAMPINF_COHERENT(ti);
- assert(n > 0);
- assert(elem);
-
- /* Agrandir le tampon s’il est trop petit.
- * La taille minimale du tampon est i + n. */
- if (ti->lngr < i + n && tampinf_agr(ti, i + n) < 0)
- return -1;
-
- memcpy((char *)ti->ctn + (i * ti->tll), elem, n * ti->tll);
-
- /* Mettre à jour nelem s’il le faut. */
- if (i + n > ti->nelem)
- ti->nelem = i + n;
-
- TAMPINF_COHERENT(ti);
-
- return i;
-}
-
-ssize_t
-tampinf_obt(struct tampinf *ti, size_t i, size_t n, void *elem)
+void *
+tampinf_plc(void *ti, size_t i, size_t n, void *elem)
{
TAMPINF_COHERENT(ti);
assert(n > 0);
assert(elem);
/* Agrandir le tampon s’il est trop petit.
- * La taille minimale du tampon est i + n. */
- if (ti->lngr < i + n && tampinf_agr(ti, i + n) < 0)
- return -1;
+ * La taille minimale que le tampon devrait avoir est i + n. */
+ if (ENTETE(ti)->s.lngr < i + n
+ && (ti = tampinf_agr(ti, i + n)) == NULL)
+ return NULL;
- /* Copier dans elem. */
- memcpy(elem, (char *)ti->ctn + (i * ti->tll), n * ti->tll);
+ memcpy((char *)ti + (i * ENTETE(ti)->s.tll), elem,
+ n * ENTETE(ti)->s.tll);
/* Mettre à jour nelem s’il le faut. */
- if (i + n > ti->nelem)
- ti->nelem = i + n;
+ if (i + n > ENTETE(ti)->s.nelem)
+ ENTETE(ti)->s.nelem = i + n;
TAMPINF_COHERENT(ti);
- return i;
+ return ti;
}
-ssize_t
-tampinf_ajt(struct tampinf *ti, size_t n, void *elem)
+void *
+tampinf_ajt(void *ti, size_t n, void *elem)
{
- int i; /* Indice où elem aura été placé. */
-
TAMPINF_COHERENT(ti);
assert(n > 0);
assert(elem);
/* Placer elem à ti->nelem. */
- if ((i = tampinf_plc(ti, ti->nelem, n, elem)) < 0)
- return -1;
-
- TAMPINF_COHERENT(ti);
-
- return i;
-}
-
-ssize_t
-tampinf_dpl(struct tampinf *ti, size_t n, void *elem)
-{
- TAMPINF_COHERENT(ti);
- assert(n > 0);
- assert(elem);
-
- /* Il doit y avoir assez d’éléments dans le tampon. */
- assert(ti->nelem >= n);
-
- /* Obtenir n éléments à ti->nelem - n. */
- if (tampinf_obt(ti, ti->nelem - n, n, elem) < 0)
- return -1;
-
- /* Mettre à jour ti->nelem. */
- ti->nelem -= n;
-
- return ti->nelem;
-}
+ if ((ti = tampinf_plc(ti, ENTETE(ti)->s.nelem, n, elem)) == NULL)
+ return NULL;
-void *
-tampinf_ctn(struct tampinf *ti)
-{
TAMPINF_COHERENT(ti);
- return ti->ctn;
+ return ti;
}
size_t
-tampinf_nelem(struct tampinf *ti)
+tampinf_nelem(void *ti)
{
TAMPINF_COHERENT(ti);
- return ti->nelem;
+ return ENTETE(ti)->s.nelem;
}
size_t
-tampinf_esp(struct tampinf *ti)
+tampinf_esp(void *ti)
{
TAMPINF_COHERENT(ti);
- return ti->nelem * ti->tll;
+ return ENTETE(ti)->s.nelem * ENTETE(ti)->s.tll;
}
bool
-tampinf_dedans(struct tampinf *ti, size_t i)
+tampinf_dedans(void *ti, size_t i)
{
TAMPINF_COHERENT(ti);
- if (i < ti->nelem)
+ if (i < ENTETE(ti)->s.nelem)
return 1;
return 0;
}
-static ssize_t
-tampinf_agr(struct tampinf *ti, size_t lngr)
+static void *
+tampinf_agr(void *ti, size_t lngr)
{
size_t nlngr; /* Nouvelle longueur. */
- void *nctn; /* Nouveau contenu. */
+ Entete *nent; /* Nouvelle entête. */
TAMPINF_COHERENT(ti);
- assert(ti->lngr < lngr);
+ assert(ENTETE(ti)->s.lngr < lngr);
- /* Doubler la longueur jusqu’à ce quelle soit supérieure ou égale à la longueur
- * recherchée. */
- for (nlngr = ti->lngr; nlngr < lngr; nlngr *= 2)
+ /* Doubler la longueur jusqu’à ce quelle soit supérieure ou égale à la
+ * longueur recherchée. */
+ for (nlngr = ENTETE(ti)->s.lngr; nlngr < lngr; nlngr *= 2)
;
/* Agrandir le tampon et en initialiser à zéro la nouvelle partie. */
- if ((nctn = realloc(ti->ctn, nlngr * ti->tll)) == NULL)
- return -1;
- memset((char *)nctn + ti->lngr * ti->tll, 0, (nlngr - ti->lngr) * ti->tll);
- ti->ctn = nctn;
- ti->lngr = nlngr;
+ if ((nent = realloc(ENTETE(ti),
+ sizeof(Entete) + nlngr * ENTETE(ti)->s.tll)) == NULL)
+ return NULL;
+ memset((char *)TAMPON(nent) + nent->s.lngr * nent->s.tll, 0,
+ (nlngr - nent->s.lngr) * nent->s.tll);
+ nent->s.lngr = nlngr;
- TAMPINF_COHERENT(ti);
+ TAMPINF_COHERENT(TAMPON(nent));
- return ti->lngr;
+ return TAMPON(nent);
}
diff --git a/tampinf.h b/tampinf.h
@@ -7,54 +7,40 @@
/* Un tampinf est un tampon qui donne l’illusion d’être infini.
*
- * L’emplacement du contenu du tampon n’étant pas statique, utiliser le résultat
- * de tampinf_ctn() après une fonction susceptible d’agrandir le tampon est
- * dangereux. */
-
-struct tampinf;
+ * L’adresse d’un tampon n’est pas statique, et plusieurs fonctions sont
+ * susceptibles de la changer. Ces fonctions renvoient toutes l’adresse
+ * courante du tampon. Toute variable qui contiendrait l’adresse du tampon doit
+ * être mise à jour à l’occasion de l’appel de ce genre de fonctions. */
/* Initialiser un tampon.
* La longueur est interprétée en multiples de tll. Le tampon est initialisé à
- * zéro. Renvoie NULL en cas d’erreur. */
-struct tampinf *tampinf_init(size_t lngr, size_t tll);
+ * zéro.
+ * Renvoie le tampon, ou NULL en cas d’erreur. */
+void *tampinf_init(size_t lngr, size_t tll);
/* Réinitialiser le tampon ti.
* Son contenu est aussi réinitialisé à zéro. */
-void tampinf_reinit(struct tampinf *ti);
+void tampinf_reinit(void *ti);
/* Libérer l’espace utilisé par le tampon ti. */
-void tampinf_libr(struct tampinf *ti);
+void tampinf_libr(void *ti);
/* Placer n éléments contenus dans elem à l’emplacement i dans le tampon ti.
* Renvoie i, ou -1 en cas d’erreur. */
-ssize_t tampinf_plc(struct tampinf *ti, size_t i, size_t n, void *elem);
-
-/* Placer dans elem n éléments à l’emplacement i du tampon ti.
- * Renvoie i, ou -1 en cas d’erreur. */
-ssize_t tampinf_obt(struct tampinf *ti, size_t i, size_t n, void *elem);
+void *tampinf_plc(void *ti, size_t i, size_t n, void *elem);
/* Ajouter au tampon ti n éléments contenus dans elem.
* Renvoie l’indice du nouvel élément, ou -1 en cas d’erreur. */
-ssize_t tampinf_ajt(struct tampinf *ti, size_t n, void *elem);
-
-/* Retirer et copier dans elem les n derniers éléments du tampon ti.
- * L’espace libéré n’est pas réinitialisé à zéro. Renvoie l’indice le plus
- * faible des éléments retirés, ou -1 en cas d’erreur. */
-ssize_t tampinf_dpl(struct tampinf *ti, size_t n, void *elem);
-
-/* Renvoyer un pointeur vers le contenu du tampon ti.
- * Le pointeur n’est plus utilisable après qu’une routine susceptible
- * d’agrandir le tampon ait été exécutée. */
-void *tampinf_ctn(struct tampinf *ti);
+void *tampinf_ajt(void *ti, size_t n, void *elem);
/* Obtenir le nombre d’éléments contenus dans le tampon ti. */
-size_t tampinf_nelem(struct tampinf *tp);
+size_t tampinf_nelem(void *ti);
/* Obtenir l’espace utilisé par les éléments du tampon ti. */
-size_t tampinf_esp(struct tampinf *ti);
+size_t tampinf_esp(void *ti);
/* Renvoie 1 si l’indice i est dans la partie utilisée du tampon, 0
* autrement. */
-bool tampinf_dedans(struct tampinf *ti, size_t i);
+bool tampinf_dedans(void *ti, size_t i);
#endif