Partage
  • Partager sur Facebook
  • Partager sur Twitter

Vector, Stack, Queue en préprocesseur

Petite immitation des templates du C++

    8 mai 2012 à 14:31:06

    Bonjour à vous tous.

    J'ai récemment commencer un début de moteur 3D, et pour avoir un moteur 3D complet, il faut au moins une petite gestions de structures de données.

    Le côté des tableaux dynamiques du C++ m'attiraient pas mal (std::vector), ainsi que les piles et les files sont utiles pour certaines choses.

    J'ai donc décidé, avec l'astuce d'un ami qui se reconnaîtra, et l'aide pour l'optimisation au niveau de la compilation de rz0, j'ai put "finir" ou presque du moins, le vector, la pile, et la file.

    J'ai aussi implémenter une petite gestion d'erreur(mais ça on s'en fout un peu). J'aimerais donc savoir, si pour des utilisateurs, ma façon de faire est plutôt naturel, si il y a des bugs, c'est possible aussi, (bien que valgrind ne m'en est pas trouver, mais je n'ai pas fait beaucoup de test faut dire ^^.)

    Je n'ai pas put faire de commentaire sur le code en préprocesseur, mais bon, il y a environ 100 / 150 lignes maximum(et certaines revienne plusieurs fois), et plusieurs fonctions, cela permet de s'y retrouver un peu.

    Voilà la gestion d'erreur.

    Header
    #ifndef ERROR_H_INCLUDED
    #define ERROR_H_INCLUDED
    
    typedef enum{
        /** Succès **/
        QGM_SUCCESS,            /** Rien à signalé **/
    
        /** Mauvaise allocations **/
        QGM_BADALLOC,           /** Allocation de mémoire échouée **/
    
        /** Fuites de mémoires **/
        QGM_MEMORYLEAKSALLOC,   /** Fuites de mémoires  (Allocation) **/
    
        /** L'élément n'existe pas **/
        QGM_NOELEMENTALLOC,     /** Pointeur à détruire n'existe pas **/
        QGM_NOELEMENTSTACK,     /** Aucun élément à dépiler **/
        QGM_NOELEMENTQUEUE,     /** Aucun élement à défiler **/
        QGM_NOELEMENTVECTOR,    /** Aucun élément à supprimer **/
    }QGM_Error_t;
    
    /** Variable recevant l'erreur **/
    extern QGM_Error_t QGM_Error;
    
    /** Synopsis    : Indique si il y a ou non une erreur
        Retour      : 1 : erreur. 0 : Pas d'erreur **/
    int QGM_IsError(void);
    
    /** Synopsis    : Permet de récupèrer l'erreur
        Retour      : Chaîne de caractère contenant l'erreur **/
    char const *QGM_GetError(void);
    
    #endif
    

    fichier C
    #include <stdio.h>
    
    #include "error.h"
    
    /** Variable recevant l'erreur **/
    QGM_Error_t QGM_Error = QGM_SUCCESS;
    
    /** Tableau des erreurs en fonction de QGM_Error **/
    char const *QGM_String_Error[] = {
    /** Succès **/
    "",
    
    /** Mauvaise allocations **/
    "Not space\n",
    
    /** Fuites de mémoires **/
    "Memory Leaks Are Detected (Allocation)\n",
    
    /** L'élément n'existe pas **/
    "This pointer can't be free (Allocation)\n",
    "Nothing element to pop (Stack)\n",
    "Nothing element to pop (Queue)\n",
    "Nothing element to delete (Vector)\n",
    };
    
    int QGM_IsError(void){
        return (QGM_Error == QGM_SUCCESS) ? 0 : 1;
    }
    
    /** Fonction permettant de récupérer l'erreur **/
    char const *QGM_GetError(void)
    {
        char const *t = QGM_String_Error[QGM_Error];
        QGM_Error = QGM_SUCCESS;
        return t;
    }
    


    et voilà mes structures de données implémenter sous forme de préprocesseur.
    On y retrouver au début la macro permettant de "dévoiler" les prototypes et structures. A mettre dans le fichier structure.h par exemple.
    Et la macro permettant de "dévoiler" les fonctions. A mettre dans le fichier structure.c par exemple.

    #ifndef DATA_H_INCLUDED
    #define DATA_H_INCLUDED
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include "error.h"
    
    /*****************************************************************************/
    /********************************** HEADER ***********************************/
    /*****************************************************************************/
    /********************************** VECTOR ***********************************/
    /*****************************************************************************/
    #define QGM_Vector_Header(TYPE)\
    typedef struct{\
        TYPE *data;\
        size_t size;\
        unsigned nElem;\
    }QGM_Vector_##TYPE;\
    \
    QGM_Vector_##TYPE *QGM_Vector_##TYPE##_Init(void);\
    int QGM_Vector_##TYPE##_Resize(QGM_Vector_##TYPE*);\
    int QGM_Vector_##TYPE##_PushFront(QGM_Vector_##TYPE*, TYPE);\
    int QGM_Vector_##TYPE##_PushBack(QGM_Vector_##TYPE*, TYPE);\
    int QGM_Vector_##TYPE##_Insert(QGM_Vector_##TYPE*, TYPE, unsigned);\
    TYPE QGM_Vector_##TYPE##_PopFront(QGM_Vector_##TYPE*);\
    TYPE QGM_Vector_##TYPE##_PopBack(QGM_Vector_##TYPE*);\
    TYPE QGM_Vector_##TYPE##_Erase(QGM_Vector_##TYPE*, unsigned);\
    size_t QGM_Vector_##TYPE##_Size(QGM_Vector_##TYPE*);\
    void QGM_Vector_##TYPE##_Quit(QGM_Vector_##TYPE*);
    
    /*****************************************************************************/
    /********************************** STACK ************************************/
    /*****************************************************************************/
    #define QGM_Stack_Header(TYPE)\
    typedef struct{\
        TYPE *data;\
        size_t size;\
        unsigned nElem;\
    }QGM_Stack_##TYPE;\
    \
    QGM_Stack_##TYPE *QGM_Stack_##TYPE##_Init(void);\
    int QGM_Stack_##TYPE##_Resize(QGM_Stack_##TYPE*);\
    int QGM_Stack_##TYPE##_Push(QGM_Stack_##TYPE*, TYPE);\
    TYPE QGM_Stack_##TYPE##_Pop(QGM_Stack_##TYPE*);\
    size_t QGM_Stack_##TYPE##_Size(QGM_Stack_##TYPE*);\
    void QGM_Stack_##TYPE##_Quit(QGM_Stack_##TYPE*);
    
    /*****************************************************************************/
    /********************************** Queue ************************************/
    /*****************************************************************************/
    #define QGM_Queue_Header(TYPE)\
    typedef struct{\
        TYPE *data;\
        size_t size;\
        unsigned nElem;\
        unsigned pop;\
        unsigned push;\
    }QGM_Queue_##TYPE;\
    \
    QGM_Queue_##TYPE *QGM_Queue_##TYPE##_Init(void);\
    int QGM_Queue_##TYPE##_Resize(QGM_Queue_##TYPE*);\
    void QGM_Queue_##TYPE##_Adjust(QGM_Queue_##TYPE*);\
    int QGM_Queue_##TYPE##_Push(QGM_Queue_##TYPE*, TYPE);\
    TYPE QGM_Queue_##TYPE##_Pop(QGM_Queue_##TYPE*);\
    size_t QGM_Queue_##TYPE##_Size(QGM_Queue_##TYPE*);\
    void QGM_Queue_##TYPE##_Quit(QGM_Queue_##TYPE*);
    
    /*****************************************************************************/
    /********************************* FONCTIONS *********************************/
    /*****************************************************************************/
    /********************************** VECTOR ***********************************/
    /*****************************************************************************/
    
    #define QGM_Vector_Functions(TYPE)\
    QGM_Vector_##TYPE *QGM_Vector_##TYPE##_Init(void){\
        QGM_Vector_##TYPE *self;\
        if((self = (malloc)(sizeof *self)) == NULL)\
            goto _error;\
        if((self->data = (malloc)(sizeof *self->data)) == NULL)\
            goto _error;\
        self->nElem = 0;\
        self->size  = 1;\
        return self;\
        _error:\
            free(self);\
            QGM_Error = QGM_BADALLOC;\
            return NULL;\
    }\
    \
    int QGM_Vector_##TYPE##_Resize(QGM_Vector_##TYPE *self){\
        TYPE *ptr = (realloc)(self->data,\
                              self->size * 3 * sizeof *ptr);\
        if(ptr == NULL)\
            goto _error;\
        self->size *= 3;\
        self->data  = ptr;\
        return 1;\
        _error :\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    int QGM_Vector_##TYPE##_PushFront(QGM_Vector_##TYPE *self, TYPE data){\
        if(self->nElem >= self->size)\
            if(QGM_Vector_##TYPE##_Resize(self) == 0)\
                goto _error;\
        memmove(self->data + 1,\
                self->data,\
                self->nElem++ * sizeof *self->data);\
        *self->data = data;\
        return 1;\
        _error :\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    int QGM_Vector_##TYPE##_PushBack(QGM_Vector_##TYPE *self, TYPE data){\
        if(self->nElem >= self->size)\
            if(QGM_Vector_##TYPE##_Resize(self) == 0)\
                goto _error;\
        self->data[self->nElem++] = data;\
        return 1;\
        _error :\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    int QGM_Vector_##TYPE##_Insert\
    (QGM_Vector_##TYPE *self, TYPE data, unsigned place){\
        if(self->nElem >= self->size)\
            if(QGM_Vector_##TYPE##_Resize(self) == 0)\
                goto _error;\
        if(place >= self->nElem)\
            place = self->nElem;\
        memmove(self->data + place + 1,\
                self->data + place,\
               (self->nElem++ - place) * sizeof *self->data);\
        self->data[place] = data;\
        return 1;\
        _error:\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    TYPE QGM_Vector_##TYPE##_PopFront(QGM_Vector_##TYPE *self){\
        TYPE ifError;\
        TYPE data;\
        if(self->nElem == 0)\
            goto _error;\
        data = *self->data;\
        memmove(self->data,\
                self->data + 1,\
                --self->nElem * sizeof *self->data);\
        return data;\
        _error:\
            QGM_Error = QGM_NOELEMENTVECTOR;\
            memset(&ifError, 255, sizeof ifError);\
            return ifError;\
    }\
    \
    TYPE QGM_Vector_##TYPE##_PopBack(QGM_Vector_##TYPE *self){\
        TYPE ifError;\
        if(self->nElem == 0)\
            goto _error;\
        return self->data[--self->nElem];\
        _error:\
            QGM_Error = QGM_NOELEMENTVECTOR;\
            memset(&ifError, 255, sizeof ifError);\
            return ifError;\
    }\
    \
    TYPE QGM_Vector_##TYPE##_Erase(QGM_Vector_##TYPE *self, unsigned place){\
        TYPE ifError;\
        TYPE data;\
        if(self->nElem == 0)\
            goto _error;\
        if(place >= self->nElem)\
            place = self->nElem;\
        data = self->data[place];\
        memmove(self->data + place,\
                self->data + place + 1,\
             (--self->nElem - place) * sizeof *self->data);\
        return data;\
        _error:\
            QGM_Error = QGM_NOELEMENTVECTOR;\
            memset(&ifError, 255, sizeof ifError);\
            return ifError;\
    }\
    \
    size_t QGM_Vector_##TYPE##_Size(QGM_Vector_##TYPE *self){\
        return self->nElem;\
    }\
    \
    void QGM_Vector_##TYPE##_Quit(QGM_Vector_##TYPE *self){\
        free(self->data);\
        free(self);\
    }
    
    /*****************************************************************************/
    /********************************** STACK ************************************/
    /*****************************************************************************/
    
    #define QGM_Stack_Functions(TYPE)\
    QGM_Stack_##TYPE *QGM_Stack_##TYPE##_Init(void){\
        QGM_Stack_##TYPE *self;\
        if((self = (malloc)(sizeof *self)) == NULL)\
            goto _error;\
        if((self->data = (malloc)(sizeof *self->data)) == NULL)\
            goto _error;\
        self->nElem = 0;\
        self->size  = 1;\
        return self;\
        _error:\
            free(self);\
            QGM_Error = QGM_BADALLOC;\
            return NULL;\
    }\
    \
    int QGM_Stack_##TYPE##_Resize(QGM_Stack_##TYPE *self){\
        TYPE *ptr = (realloc)(self->data,\
                              self->size * 3 * sizeof *ptr);\
        if(ptr == NULL)\
            goto _error;\
        self->size *= 3;\
        self->data  = ptr;\
        return 1;\
        _error :\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    int QGM_Stack_##TYPE##_Push(QGM_Stack_##TYPE *self, TYPE data){\
        if(self->nElem >= self->size)\
            if(QGM_Stack_##TYPE##_Resize(self) == 0)\
                goto _error;\
        self->data[self->nElem++] = data;\
        return1;\
        _error :\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    TYPE QGM_Stack_##TYPE##_Pop(QGM_Stack_##TYPE *self){\
        TYPE ifError;\
        if(self->nElem == 0)\
            goto _error;\
        return self->data[--self->nElem];\
        _error:\
            QGM_Error = QGM_NOELEMENTSTACK;\
            memset(&ifError, 255, sizeof ifError);\
            return ifError;\
    }\
    \
    size_t QGM_Stack_##TYPE##_Size(QGM_Stack_##TYPE *self){\
        return self->nElem;\
    }\
    \
    void QGM_Stack_##TYPE##_Quit(QGM_Stack_##TYPE *self){\
        free(self->data);\
        free(self);\
    }
    
    /*****************************************************************************/
    /********************************** Queue ************************************/
    /*****************************************************************************/
    
    #define QGM_Queue_Functions(TYPE)\
    QGM_Queue_##TYPE *QGM_Queue_##TYPE##_Init(void){\
        QGM_Queue_##TYPE *self;\
        if((self = (malloc)(sizeof *self)) == NULL)\
            goto _error;\
        if((self->data = (malloc)(sizeof *self)) == NULL)\
            goto _error;\
        self->nElem = 0;\
        self->size  = 1;\
        self->push = self->pop = 0;\
        return self;\
        _error:\
            free(self);\
            QGM_Error = QGM_BADALLOC;\
            return NULL;\
    }\
    \
    int QGM_Queue_##TYPE##_Resize(QGM_Queue_##TYPE *self){\
        TYPE *ptr = (realloc)(self->data,\
                              self->size * 3 * sizeof *ptr);\
        if(ptr == NULL)\
            goto _error;\
        self->size *= 3;\
        self->data  = ptr;\
        return 1;\
        _error:\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    void QGM_Queue_##TYPE##_Adjust(QGM_Queue_##TYPE *self){\
        memmove(self->data,\
                self->data + self->pop,\
               (self->push - self->pop) * sizeof *self->data);\
        self->push -= self->pop;\
        self->pop = 0;\
    }\
    \
    int QGM_Queue_##TYPE##_Push(QGM_Queue_##TYPE *self, TYPE data){\
        if(self->nElem >= self->size)\
            if(QGM_Queue_##TYPE##_Resize(self) == 0)\
                goto _error;\
        if(self->push == self->size)\
            QGM_Queue_##TYPE##_Adjust(self);\
        self->data[self->push++] = data;\
        ++self->nElem;\
        return 1;\
        _error:\
            QGM_Error = QGM_BADALLOC;\
            return 0;\
    }\
    \
    TYPE QGM_Queue_##TYPE##_Pop(QGM_Queue_##TYPE *self){\
        TYPE ifError;\
        TYPE data;\
        if(self->nElem == 0)\
            goto _error;\
        data = self->data[self->pop++];\
        if(--self->nElem == 0)\
            self->push = self->pop = 0;\
        return data;\
        _error:\
            QGM_Error = QGM_NOELEMENTQUEUE;\
            memset(&ifError, 255, sizeof ifError);\
            return ifError;\
    }\
    \
    size_t QGM_Queue_##TYPE##_Size(QGM_Queue_##TYPE *self){\
        return self->nElem;\
    }\
    \
    void QGM_Queue_##TYPE##_Quit(QGM_Queue_##TYPE *self){\
        free(self->data);\
        free(self);\
    }
    
    #endif
    


    Le push / pop de la file est différent du pushBack / PopFront du vector. Cela est normalement plus optimisé et plus rapide.

    Si il n'y a plus d'élement, on renvoie un objet avec tout les bits de cette objet mis à 1, et on met l'erreur dans QGM_Error.

    Voici un exemple utilisant le vector

    #include "QGM/alloc.h"
    #include "QGM/error.h"
    #include "QGM/data.h"
    
    /** Active le vector int**/
    QGM_Vector_Header(int);
    QGM_Vector_Functions(int);
    
    /** Active le vector double **/
    QGM_Vector_Header(double);
    QGM_Vector_Functions(double);
    
    int main(void){
        QGM_Vector_int *vectorInt;
        QGM_Vector_double *vectorDouble;
        int i;
    
        if((vectorDouble = QGM_Vector_double_Init()) == NULL)
            return 1;
    
        if((vectorInt = QGM_Vector_int_Init()) == NULL){
            QGM_Vector_double_Quit(vectorDouble);
            return 1;
        }
    
        for(i = 0; i < 20; ++i)
            if(QGM_Vector_double_PushFront(vectorDouble, (double)i / 10.0) == 0)
                goto end;
    
        for(i = 0; i < 20; ++i)
            if(QGM_Vector_int_PushFront(vectorInt, i) == 0)
                goto end;
    
        /** Affichage du vector double sans rien supprimer **/
        printf("Vector Double\n");
    
        for(i = 0; i < 20; ++i)
            printf("%.1f ", vectorDouble->data[i]);
        printf("Il y a %u elements dans le vectorDouble\n",
               QGM_Vector_double_Size(vectorDouble));
    
        /** Affichage du vector int en supprimant toutes les données **/
        printf("\nVector int\n");
    
        for(i = 0; i < 20; ++i)
            printf("%d ", QGM_Vector_int_PopBack(vectorInt));
        printf("\nIl y a %u element dans le vectorInt\n",
               QGM_Vector_int_Size(vectorInt));
    
        end:
        QGM_Vector_int_Quit(vectorInt);
        QGM_Vector_double_Quit(vectorDouble);
    
        return 0;
    }
    


    Un exemple utilisant la pile
    #include "QGM/alloc.h"
    #include "QGM/error.h"
    #include "QGM/data.h"
    
    /** Active la pile double **/
    QGM_Stack_Header(double);
    QGM_Stack_Functions(double);
    
    int main(void){
        QGM_Stack_double *stack = QGM_Stack_double_Init();
        int i;
    
        for(i = 0; i < 20; ++i)
            if(QGM_Stack_double_Push(stack, (double)i / 10.0) == 0)
                goto end;
    
        for(i = 0; i < 21; ++i)
            printf("%.1f ", QGM_Stack_double_Pop(stack));
    
        printf("\n%s", QGM_GetError());
    
        end:
        QGM_Stack_double_Quit(stack);
    
        return 0;
    }
    


    Et un utilisant la file
    #include "QGM/alloc.h"
    #include "QGM/error.h"
    #include "QGM/data.h"
    
    /** Active la file long **/
    QGM_Queue_Header(long);
    QGM_Queue_Functions(long);
    
    int main(void){
        QGM_Queue_long *queue = QGM_Queue_long_Init();
        int i;
    
        for(i = 0; i < 20; ++i)
            if(QGM_Queue_long_Push(queue, i) == 0)
                goto end;
    
        for(i = 0; i < 21; ++i)
            printf("%d ", QGM_Queue_long_Pop(queue));
    
        printf("\n%s", QGM_GetError());
    
        end:
        QGM_Queue_long_Quit(queue);
    
        return 0;
    }
    


    Merci de votre compréhension.

    Cordialement.
    • Partager sur Facebook
    • Partager sur Twitter
    http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
      8 mai 2012 à 14:43:03

      J'ai regardé en travers. Je pense savoir qui est ton ami vu ton implémentation. :p
      Tu pourrais essayer de faire quelque chose de plus générique encore, à la manière de queue.h et stack.h. :)
      • Partager sur Facebook
      • Partager sur Twitter
        8 mai 2012 à 14:46:38

        bonjour,

        pourquoi avoir besoin de faire
        QGM_Stack_Header(type);
        QGM_Stack_Functions(type);
        


        Pour chaque nouveau type, pourquoi générer le header et les fonctions séparément? Pas possible en 1 seule fois?

        Dans tes fonctions, comme par exemple ici
        int QGM_Vector_##TYPE##_Insert\
        (QGM_Vector_##TYPE *self, TYPE data, unsigned place){\
        

        Tu ne testes pas le pointeur self, à l'entrée.
        Si l'utilisateur pass un pointeur NULL, par exemple, ça va crasher sans infos. peut être utiliser un assert non?

        Citation : Qnope


        si il y a des bugs, c'est possible aussi, (bien que valgrind ne m'en est pas trouver, mais je n'ai pas fait beaucoup de test faut dire ^^.)


        C'est pas trop le rôle de valgrind de détecter les bugs(c'est très spécifique :-° ).
        Il faut vraiment que tu fasses une batterie des test!

        et la gestion d'erreur, à base de goto n'apporte rien. :-°
        • Partager sur Facebook
        • Partager sur Twitter
        Zeste de Savoir, le site qui en a dans le citron !
          8 mai 2012 à 18:16:25

          Salut,

          C'est étrange, ton code me rappel quelque chose :p
          Plus sérieusement, comme l'a souligné GurneyH, la gestion des erreurs via goto n'apporte ici pas grand chose, tu pourrais la plupart du temps te contenter de deux return (sauf pour la fonction Vector_Init et la fonction main). Pour le reste, ton implémentation m'a l'air correcte, sauf pour une petite chose (mais qui a son importance):

          TYPE *ptr = (realloc)(self->data, self->size * 3 * sizeof *ptr);
          


          Il faut bien faire attention à ce que le calcul ne dépasse pas la capacité maximale du type size_t, auquel cas tu vas allouer une taille nulle ou inférieure à tes besoins. Sinon, personnellement, j'aurais plutôt recouru à une méthode utilisant les pointeurs génériques histoire de n'avoir qu'une seule suite de fonction.

          Citation : GurneyH


          Tu ne testes pas le pointeur self, à l'entrée.
          Si l'utilisateur pass un pointeur NULL, par exemple, ça va crasher sans infos. peut être utiliser un assert non?



          Je serais plutôt d'avis de ne pas le tester, sauf pour la fonction de destruction (afin de facilité la gestion d'éventuelles erreurs). Au final, un pointeur nul n'est qu'un cas d'argument invalide et n'empêchera pas l'utilisateur de provoquer un crash avec ce type d'appel : QGM_Vector_int_PushBack((void *)42, 42). Si l'utilisateur ne vérifie pas la validité des données qu'il envoie, il ne peut s'en prendre qu'à lui-même ;)
          • Partager sur Facebook
          • Partager sur Twitter
            8 mai 2012 à 18:41:42

            Citation : Pouet_forever

            J'ai regardé en travers. Je pense savoir qui est ton ami vu ton implémentation. :p
            Tu pourrais essayer de faire quelque chose de plus générique encore, à la manière de queue.h et stack.h. :)



            Salut. Merci de ta réponse. Peux tu mieux expliqué pour queue.h et stack.h?
            Tu parles de sys/queue.h par exemple? Si oui, je trouve que c'est un peu compliqué. Mais je ne vois pas en quoi c'est encore plus générique ^^ .

            @GurneyH. Pour le header, et fonctions, je pense que c'est plus "naturel" de faire comme ça. En effet, l'utilisateur n'aura qu'à mettre dans un fichier vector.h les header des types qu'il souhaite utilisé. Et dans vector.c, les fonctions des types qu'il souhaite utilisé.

            Enfin, ce n'est qu'un avis personnel ça.
            Ensuite pour testé les valeurs d'entrée, je ne veux pas pour les même raison de Taurre, mais je ne le teste pas non plus pour la fin, pour les mêmes raisons. De plus, une comparaison de gagner, ça fait toute la différence sur les performances :-°^^ .

            Pour la gestion d'erreur à base de goto, c'est surtout que j'ai copier le _error: ^^ .

            Sinon Taurre, que veux tu dire par pointeur générique? Le pointeur void*?
            Il est légèrement moins efficace je dirais non? Car il faut utiliser de la recopie par memcpy, et même si la fonction est interne au compilateur, je pense que le fait de faire de la copie par type sera plus rapide non? Puis, c'est moins naturel, car on ne peut pas retourner directement le code .

            Le type size_t == unsigned long; ?
            • Partager sur Facebook
            • Partager sur Twitter
            http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
              8 mai 2012 à 19:28:02

              Ouep, je parle de ça !
              Bah ça évite de créer des fonction et cie...
              Que vaut ton code sur un type long long ? struct a ? :)
              • Partager sur Facebook
              • Partager sur Twitter
                8 mai 2012 à 19:34:25

                Citation : Pouet_forever

                Ouep, je parle de ça !
                Bah ça évite de créer des fonction et cie...
                Que vaut ton code sur un type long long ? struct a ? :)


                typedef long long Long;
                typedef struct a A;
                

                ? o_O
                • Partager sur Facebook
                • Partager sur Twitter
                Zeste de Savoir, le site qui en a dans le citron !
                  8 mai 2012 à 19:36:23

                  C'est ce que je dis, obligé de taper sur un typedef. ^^
                  C'est là que je voulais en venir. :p
                  • Partager sur Facebook
                  • Partager sur Twitter
                    8 mai 2012 à 20:03:28

                    Ouais, il y a quelques petits problème, mais je pige rien au sys/queue.h xD

                    Mais je vais étudier tout ça, et je reviens vous voir :)
                    • Partager sur Facebook
                    • Partager sur Twitter
                    http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                      8 mai 2012 à 20:50:46

                      Citation : qnope


                      Sinon Taurre, que veux tu dire par pointeur générique? Le pointeur void*?



                      Tout à fait.

                      Citation : qnope


                      Il est légèrement moins efficace je dirais non? Car il faut utiliser de la recopie par memcpy, et même si la fonction est interne au compilateur, je pense que le fait de faire de la copie par type sera plus rapide non? Puis, c'est moins naturel, car on ne peut pas retourner directement le code.



                      Effectivement, tu vas perdre un peu de temps comparer au code que tu as actuellement. Cependant, je pense que tu y gagneras en lisibilité, en maintenabilité et en facilité d'utilisation.

                      Citation : qnope


                      Le type size_t == unsigned long; ?



                      Sur une architecture 64 bits c'est le plus souvent le cas, oui. Maintenant, la norme ne spécifie pas le type correspondant de size_t, elle précise juste qu'il s'agit d'un entier non signé. Toutefois, depuis le C99, tu peux connaître le maximum possible du type size_t à l'aide de la macroconstante SIZE_MAX (déclarée dans stdint.h). À noter que si tu souhaites rester en C89, tu peux aussi l'obtenir à l'aide de ce code:

                      size_t n = ~(size_t)0;
                      
                      • Partager sur Facebook
                      • Partager sur Twitter
                        8 mai 2012 à 21:14:38

                        Ha oui, j'avais pas penser à cet opérateur ^^.

                        Niveau facilité d'utilisation, je pense que ma méthode est la meilleur, car il n'est pas possible de récupérer la valeur par pop comme je le fais par exemple.

                        Je me suis renseigné sur sys/queue.h, et pareil, on ne peut pas récupérer les valeurs, hors c'est pour ça que je suis attaché à cette méthode ^^. Elle est super naturel.

                        Donc je vais rajouter le test de la taille maximale, même si je pense, qu'en théorie, ce n'est pas vraiment important ^^. En effet, avant d'avoir 3 go de donnée dans une pile, ou une stack, je pense que le malloc l'aura virer avant ^^.
                        • Partager sur Facebook
                        • Partager sur Twitter
                        http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                          8 mai 2012 à 21:27:37

                          Citation : qnope


                          Niveau facilité d'utilisation, je pense que ma méthode est la meilleur, car il n'est pas possible de récupérer la valeur par pop comme je le fais par exemple.



                          Si, c'est possible.
                          Il te suffit de demander à l'utilisateur de fournir une variable dans laquelle tu stockeras la valeur à l'aide de memcpy comme pour l'ajout.

                          Citation : qnope


                          Je me suis renseigné sur sys/queue.h, et pareil, on ne peut pas récupérer les valeurs



                          Si, il faut juste parcourir la liste ;)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            8 mai 2012 à 21:30:38

                            Ce que je veux dire, c'est qu'il n'est pas possible, par exemple, de faire.

                            printf("%d\n", pop());

                            Après oui, pour le pointeur void *, il suffit d'envoyer un pointeur sur la data, d'ailleurs tu m'as aidé il y a plus d'un an sur ce sujet ^^.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                              8 mai 2012 à 21:39:05

                              Citation : qnope


                              Ce que je veux dire, c'est qu'il n'est pas possible, par exemple, de faire.

                              printf("%d\n", pop());



                              Aah ok, je comprends mieux où tu veux en venir. En effet, ce n'est pas possible avec une implémentation utilisant des pointeurs génériques ou sys/queue.h.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                8 mai 2012 à 21:59:53

                                Ouais, mais cependant, tu as raison, c'est mieux quand même. On a très rarement besoin de l'exemple que j'ai donner. Au pire, ça m'a permis d'apprendre à utiliser le ## ^^.

                                Je recoderais tout en mode préprocesseur(sans cacher de fonctions), et je reviendrais vous faire chierdemandez des conseils
                                quand j'aurais finit, donc je pense vers vendredi soir. Ou samedi. De plus, mon objectif est d'être le plus rapide possible, donc c'est justement un bon avantage, on économisera tout les appels de fonctions, mais l’exécutable sera plus gros, mais ça, c'est pas trop grave ^^.

                                Merci. A samedi^^.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                                  8 mai 2012 à 22:45:08

                                  Citation : qnope


                                  De plus, mon objectif est d'être le plus rapide possible, donc c'est justement un bon avantage, on économisera tout les appels de fonctions, mais l’exécutable sera plus gros, mais ça, c'est pas trop grave ^^.


                                  Comme déjà dit qnope, code une structure de donnée de manière simple.
                                  Si il y a des problèmes de perfs et seulement si, alors tu pourras penser profiler pour savoir quels sont les goulots d'étranglements.
                                  Avant, c'est prématuré de pensé à l'optimisation(voir la célèbre phrase de Knuth ;) ).

                                  Citation : Qnope


                                  Au pire, ça m'a permis d'apprendre à utiliser le ## ^^.


                                  Tout à fait! :)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Zeste de Savoir, le site qui en a dans le citron !
                                    9 mai 2012 à 15:41:43

                                    Ça me fait penser à utlist et utarray.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Zeste de Savoirbépocode minimal  — Ge0 <3
                                      9 mai 2012 à 18:26:32

                                      Salut.

                                      Gurney, tu connais mon perfectionnisme ^^. Je fais ça pour m’amuser, si, même dans 3 mois mon moteur 3D ne sait toujours pas créer une fenêtre, ça ne me dérange pas du tout. Ce que je souhaite c'est m’amuser à programmer, et ce qui m’amuse sur des trucs comme ça, c'est d'être le plus efficace possible ^^.

                                      Finalement, tu m'as encore appris un truc ^^ "L'optimisation prématurée est la source de tous les maux :D ".

                                      En fait, ce n'est pas que d'être efficace qui m'intèrésse, c'est le fait de pouvoir voir des débutants en C pouvoir relire mes codes, et les utilisateurs de mon moteur 3D (cf dans 3 ans le prochain call of duty, utilisera mon moteur vous verrez :D) ont le plus de facilités possible ^^.

                                      A Simbilou : Ce n'est pas pareil, apparemment ut utilise des pointeurs de type void* (enfin je pense, je suis pas sûr).

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                                        13 mai 2012 à 0:43:43

                                        Bonne nuit Bonsoir.

                                        J'ai donc "amélioré" ma façon de gérer mes structures. Vous m'avez conseillez de regarder du côté de queue.h, mais je vous est dit kikoo c'est nul, on ne peut pas récupérer les valeurs dans un printf ^^.

                                        J'ai donc trouvé le moyen de le faire, en utilisant le magnifique opérateur virgule, plus des ternaires. (Pouet, je comprends pourquoi tu ne codes qu'en prépro ^^ (ou avant du moins :-° ))

                                        Je n'étais pas parti sur ça au début, mais en réfléchissant bien, on voit que ça passe tranquillement ^^ .
                                        Je ne gère pas les erreurs du type pointeur NULL, et je ne gère pas le cas ou "place" est supérieur a nElements, l'utilisateur doit donc savoir ce qu'il fait.

                                        Voilà le code, qui est normalement fonctionnel, il est légèrement plus long que l'ancien, mais est tout aussi compréhensible si on va doucement je pense. Par ordre de facilité : La pile, le vector, et enfin la file(Le push m'a fait galérer ^^ )

                                        QGM_Data.h

                                        #ifndef DATA_H_INCLUDED
                                        #define DATA_H_INCLUDED
                                        
                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        #include <string.h>
                                        
                                        #include "error.h"
                                        
                                        /** Définit la Pile
                                                -Un tableau dynamique
                                                -Le nombre d'élément
                                                -Le nombre d'élément allouer
                                                -Le nombre d'élément maximale :~(size_t)0;
                                                -Un pointeur inutile pour la réallocation **/
                                        #define QGM_STACK(TYPE)\
                                        struct{\
                                            TYPE *data;\
                                            size_t nElements;\
                                            size_t sizeAlloc;\
                                            size_t sizeMaxAlloc;\
                                            TYPE *unusedPointer;\
                                        }*
                                        
                                        /** Définit la File
                                                -Un tableau dynamique
                                                -Le nombre d'élément
                                                -Le nombre d'élément allouer
                                                -Le nombre d'élément maximale : ~(size_t)0;
                                                -L'index de fin de file
                                                -L'index de début de file
                                                -Un pointeur inutile pour la réallocation
                                                -Une valeure inutile pour accélérer la file si push = pop d'élément **/
                                        #define QGM_QUEUE(TYPE)\
                                        struct{\
                                            TYPE *data;\
                                            size_t nElements;\
                                            size_t sizeAlloc;\
                                            size_t sizeMaxAlloc;\
                                            unsigned push;\
                                            unsigned pop;\
                                            TYPE *unusedPointer;\
                                            TYPE  unusedData;\
                                        }*
                                        
                                        /** Définit le Vector
                                            -Un tableau dynamique
                                            -Le nombre d'élément
                                            -Le nombre d'élément allouer
                                            -Le nombre d'élément maximale : ~(size_t)0;
                                            -Un pointeur inutile pour la réallocation
                                            -Une valeure inutile pour certains retraits **/
                                        #define QGM_VECTOR(TYPE) \
                                        struct{\
                                            TYPE *data;\
                                            size_t nElements;\
                                            size_t sizeAlloc;\
                                            size_t sizeMaxAlloc;\
                                            TYPE *unusedPointer;\
                                            TYPE unusedData;\
                                        }*
                                        
                                        /** Initialise la structure
                                                -Créer la structure
                                                -Création d'un élément non initialisé
                                                -Paramètre les attributs :
                                                    -0 élément
                                                    -1 élément pré-alloué
                                                    -maxAlloc = maxSize_t / taille d'une donnée
                                                Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_INIT(self)\
                                        ((((self) = (malloc)(sizeof *(self))) != NULL) ?\
                                                ((((self)->data = (malloc)(sizeof *(self)->data)) != NULL) ?\
                                                    ((self)->nElements = 0,\
                                                     (self)->sizeAlloc = 1,\
                                                     (self)->sizeMaxAlloc = ~(size_t)0 / sizeof(*(self)->data),\
                                                      QGM_SUCCESS)\
                                                :\
                                                    (free((self)),\
                                                     QGM_Error = QGM_BADALLOC,\
                                                     QGM_BADALLOC))\
                                        :\
                                            (QGM_Error = QGM_BADALLOC, QGM_BADALLOC))\
                                        
                                        /** Réalloue les données des Stacks, Vector, Queue
                                                -On vérifie que la taille ne dépassera pas un size_t.
                                                -On realloue une taille plus grande.
                                                -On réinitialise les paramètres, et on renvoie QGM_SUCCESS.
                                        
                                                Si pas d'erreur, retorune QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_RESIZE(self)\
                                        (((self)->sizeAlloc * 3 <= (self)->sizeMaxAlloc) ?\
                                                ((((self)->unusedPointer = (realloc)((self)->data,\
                                                                                     (self)->sizeAlloc * 3 *\
                                                                                      sizeof *(self)->data))\
                                                                            != NULL) ? \
                                                     ((self)->data = (self)->unusedPointer,\
                                                      (self)->sizeAlloc *= 3,\
                                                      QGM_SUCCESS)\
                                                :\
                                                    (QGM_Error = QGM_BADALLOC,\
                                                     QGM_BADALLOC))\
                                            :\
                                                (QGM_Error = QGM_BADALLOC,\
                                                 QGM_BADALLOC))
                                        
                                        /** QGM_SIZE : Renvoie le nombre d'élément **/
                                        #define QGM_SIZE(self) (self)->nElements
                                        
                                        /** EMPTY : Renvoie 1 si vide, sinon 0 **/
                                        #define QGM_EMPTY(self) !(self)->nElements
                                        
                                        /** QGM_QUIT : Détruit la structure **/
                                        #define QGM_QUIT(self) (free((self)->data), free(self))
                                        
                                        /*****************************************************************************/
                                        /*********************************** STACK ***********************************/
                                        /*****************************************************************************/
                                        
                                        /** Initialise la Pile
                                                Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_STACK_INIT(self) QGM_INIT(self)
                                        
                                        /** Push : Ajoute un élément sur la pile.
                                                -Véfifie si il y a de la place, sinon realloue
                                                -Ajoute _data sur la pile
                                        
                                                Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_STACK_PUSH(self, _data)\
                                        (((self)->nElements == (self)->sizeAlloc) ?\
                                            ((QGM_RESIZE(self) == QGM_SUCCESS) ?\
                                                ((self)->data[(self)->nElements++] = (_data), QGM_SUCCESS)\
                                            :\
                                                (QGM_Error = QGM_BADALLOC, QGM_BADALLOC))\
                                        :\
                                            ((self)->data[(self)->nElements++] = (_data), QGM_SUCCESS))\
                                        
                                        /** POP : Dépile un élément.
                                                Si erreur, tout les bits de la valeur renvoyé sont mis à un,
                                                    et QGM_Error = QGM_NOELEMENTSTACK
                                                Si pas d'erreur, renvoie tout simplement la donnée **/
                                        #define QGM_STACK_POP(self)\
                                        ((QGM_STACK_EMPTY(self) == 0) ?\
                                            ((self)->data[--(self)->nElements])\
                                        :\
                                            (QGM_Error = QGM_NOELEMENTSTACK,\
                                             memset((self)->data, 0xFF, sizeof *(self)->data),\
                                             *(self)->data))
                                        
                                        /** CLEAR : Remet a 0 la pile **/
                                        #define QGM_STACK_CLEAR(self) (self)->nElements = 0
                                        
                                        /** QGM_SIZE : Renvoie le nombre d'élément **/
                                        #define QGM_STACK_SIZE QGM_SIZE
                                        
                                        /** EMPTY : Renvoit un si la pile est vide **/
                                        #define QGM_STACK_EMPTY QGM_EMPTY
                                        
                                        /** Détruit la pile **/
                                        #define QGM_STACK_QUIT QGM_QUIT
                                        
                                        /*****************************************************************************/
                                        /*********************************** QUEUE ***********************************/
                                        /*****************************************************************************/
                                        
                                        /** Initialisation :
                                            Appele QGM_INIT, et met a 0 push et pop
                                            Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_QUEUE_INIT(self)\
                                        ((QGM_INIT((self)) == QGM_SUCCESS) ?\
                                            (((self)->push = (self)->pop = 0, QGM_SUCCESS)) : QGM_BADALLOC)
                                        
                                        /** ADJUST : déplace la file au début du bloc de mémoire
                                            push = nElements;
                                            pop = 0 **/
                                        #define QGM_QUEUE_ADJUST(self)\
                                        (memmove((self)->data,\
                                                 (self)->data + (self)->pop,\
                                                ((self)->push - (self)->pop) * sizeof *(self)->data),\
                                        (self)->push = (self)->nElements,\
                                        (self)->pop  = 0)
                                        
                                        /** PUSH : Ajoute un élément à la file
                                                Si il n'y a plus de place, on réalloue
                                                Si on n'arrive à la fin du bloc de mémoire avec la fin de la file
                                                    Alors on ajuste : On déplace la file au début de la mémoire
                                                On ajoute _data
                                                Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_QUEUE_PUSH(self, _data)\
                                        (((self)->nElements == (self)->sizeAlloc) ?\
                                            ((QGM_RESIZE(self) == QGM_SUCCESS) ?\
                                                (((self)->push == (self)->sizeAlloc) ?\
                                                    (QGM_QUEUE_ADJUST(self),\
                                                    (self)->data[(self)->push++] = (_data),\
                                                  ++(self)->nElements,\
                                                     QGM_SUCCESS)\
                                                :\
                                                    ((self)->data[(self)->push++] = (_data),\
                                                   ++(self)->nElements,\
                                                      QGM_SUCCESS))\
                                            :\
                                                (QGM_Error = QGM_BADALLOC,\
                                                 QGM_BADALLOC))\
                                        :\
                                            (((self)->push == (self)->sizeAlloc) ?\
                                                (QGM_QUEUE_ADJUST(self),\
                                                (self)->data[(self)->push++] = (_data),\
                                              ++(self)->nElements,\
                                                 QGM_SUCCESS)\
                                             :\
                                               ((self)->data[(self)->push++] = (_data),\
                                              ++(self)->nElements,\
                                                 QGM_SUCCESS)))
                                        
                                        /** POP : Défile un élément.
                                                Si il n'y a plus d'élément, on accèlère la file avec pop = push = 0
                                                    ce qui évite un éventuel déplacement inutile, ou le ralentit
                                        
                                                Si erreur, tout les bits de la valeur renvoyé sont mis à un,
                                                    et QGM_Error = QGM_NOELEMENTQUEUE
                                                Si pas d'erreur, renvoie tout simplement la donnée **/
                                        #define QGM_QUEUE_POP(self)\
                                        ((QGM_QUEUE_EMPTY(self) == 0) ?\
                                            ((--(self)->nElements == 0) ?\
                                               ((self)->unusedData = (self)->data[(self)->pop],\
                                                (self)->push = (self)->pop = 0,\
                                                (self)->unusedData)\
                                            :\
                                                (self)->data[(self)->pop++])\
                                        :\
                                            (QGM_Error = QGM_NOELEMENTQUEUE,\
                                             memset((self)->data, 0xFF, sizeof *(self)->data),\
                                             *(self)->data))
                                        
                                        
                                        /** CLEAR : Remet a 0 la file **/
                                        #define QGM_QUEUE_CLEAR(self) (self)->nElements = (self)->push = (self)->pop = 0
                                        
                                        /** SIZE : Renvoie le nombre d'élément **/
                                        #define QGM_QUEUE_SIZE QGM_SIZE
                                        
                                        /** EMPTY : Renvoit un si la file est vide **/
                                        #define QGM_QUEUE_EMPTY QGM_EMPTY
                                        
                                        /** QUIT **/
                                        #define QGM_QUEUE_QUIT QGM_QUIT
                                        
                                        /*****************************************************************************/
                                        /*********************************** VECTOR **********************************/
                                        /*****************************************************************************/
                                        
                                        /** Initialise un vector **/
                                        #define QGM_VECTOR_INIT QGM_INIT
                                        
                                        /** PUSH_BACK : équivalent à un empilement **/
                                        #define QGM_VECTOR_PUSH_BACK QGM_STACK_PUSH
                                        
                                        /** PUSH_FRONT : Ajoute un élément au début
                                                On déplace toutes les données de 1, et on ajoute la donnée
                                            Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_VECTOR_PUSH_FRONT(self, _data)\
                                        (((self)->nElements == (self)->sizeAlloc) ?\
                                            ((QGM_RESIZE(self) == QGM_SUCCESS) ?\
                                                (memmove((self)->data + 1,\
                                                         (self)->data,\
                                                         (self)->nElements++ * sizeof *(self)->data),\
                                                *(self)->data = (_data),\
                                                QGM_SUCCESS)\
                                            :\
                                                (QGM_Error = QGM_BADALLOC,\
                                                 QGM_BADALLOC))\
                                        :\
                                            (memmove((self)->data + 1,\
                                                     (self)->data,\
                                                     (self)->nElements++ * sizeof *(self)->data),\
                                             *(self)->data = (_data),\
                                             QGM_SUCCESS))
                                        
                                        /** INSERT : Insère un élément
                                                même principe que PUSH_FRONT, sauf que l'on fait en fonction d'une "place"
                                            Si pas d'erreur, retourne QGM_SUCCESS, sinon QGM_BADALLOC **/
                                        #define QGM_VECTOR_INSERT(self, _data, place)\
                                        (((self)->nElements == (self)->sizeAlloc) ?\
                                            ((QGM_RESIZE(self) == QGM_SUCCESS) ?\
                                                (memmove((self)->data + place + 1,\
                                                          (self)->data + place,\
                                                         ((self)->nElements++ - place) * sizeof *(self)->data),\
                                                (self)->data[place] = (_data),\
                                                QGM_SUCCESS)\
                                            :\
                                                (QGM_Error = QGM_BADALLOC,\
                                                 QGM_BADALLOC))\
                                        :\
                                            (memmove((self)->data + place + 1,\
                                                     (self)->data + place,\
                                                    ((self)->nElements++ - place) * sizeof *(self)->data),\
                                            (self)->data[place] = (_data),\
                                            QGM_SUCCESS))
                                        
                                        /** POP_BACK : équivalent à un dépilement
                                        
                                            Si erreur, tout les bits de la valeur renvoyé sont mis à un,
                                                et QGM_Error = QGM_NOELEMENTVECTOR
                                                Si pas d'erreur, renvoie tout simplement la donnée **/
                                        #define QGM_VECTOR_POP_BACK(self)\
                                        ((QGM_VECTOR_EMPTY(self) == 0) ?\
                                            ((self)->data[--(self)->nElements])\
                                        :\
                                            (QGM_Error = QGM_NOELEMENTVECTOR,\
                                             memset((self)->data, 0xFF, sizeof *(self)->data),\
                                             *(self)->data))
                                        
                                        /** POP_FRONT : Retire un élément en début de tableau
                                                On récupère la donnée, et on déplace le tableau de 1 case vers le début
                                        
                                            Si erreur, tout les bits de la valeur renvoyé sont mis à un,
                                                et QGM_Error = QGM_NOELEMENTVECTOR
                                                Si pas d'erreur, renvoie tout simplement la donnée **/
                                        #define QGM_VECTOR_POP_FRONT(self)\
                                        ((QGM_VECTOR_EMPTY(self) == 0) ?\
                                            ((self)->unusedData = *(self)->data,\
                                              memmove((self)->data,\
                                                      (self)->data + 1,\
                                                    --(self)->nElements * sizeof *(self)->data),\
                                             (self)->unusedData)\
                                        :\
                                            (QGM_Error = QGM_NOELEMENTVECTOR,\
                                             memset((self)->data, 0xFF, sizeof *(self)->data),\
                                             *(self)->data))
                                        
                                        /** ERASE : Retire un élément
                                                même principe que POP_FRONT, sauf que l'on fait en fonction d'une place
                                            Si erreur, tout les bits de la valeur renvoyé sont mis à un,
                                                et QGM_Error = QGM_NOELEMENTVECTOR
                                                Si pas d'erreur, renvoie tout simplement la donnée **/
                                        #define QGM_VECTOR_ERASE(self, place)\
                                        ((QGM_VECTOR_EMPTY(self) == 0) ?\
                                            ((self)->unusedData = (self)->data[place],\
                                              memmove((self)->data + place,\
                                                      (self)->data + place + 1,\
                                                   (--(self)->nElements - place)* sizeof *(self)->data),\
                                             (self)->unusedData)\
                                        :\
                                            (QGM_Error = QGM_NOELEMENTVECTOR,\
                                             memset((self)->data, 0xFF, sizeof *(self)->data),\
                                             *(self)->data))
                                        
                                        /** CLEAR : Remet a 0 le vector **/
                                        #define QGM_VECTOR_CLEAR(self) (self)->nElements = 0
                                        
                                        /** SIZE : Renvoie le nombre d'élément **/
                                        #define QGM_VECTOR_SIZE QGM_SIZE
                                        
                                        /** EMPTY : Renvoit un si le vector est vide **/
                                        #define QGM_VECTOR_EMPTY QGM_EMPTY
                                        
                                        /** Détruit un vector **/
                                        #define QGM_VECTOR_QUIT QGM_QUIT
                                        
                                        #endif
                                        


                                        Et voilà quelques codes exemples.

                                        Vector :
                                        #include "QGM/alloc.h"
                                        #include "QGM/error.h"
                                        #include "QGM/data.h"
                                        
                                        int main(void){
                                            QGM_VECTOR(int) vectorInt;
                                            QGM_VECTOR(double) vectorDouble;
                                            int i;
                                        
                                            if(QGM_VECTOR_INIT(vectorInt) != QGM_SUCCESS)
                                                return 1;
                                        
                                            if(QGM_VECTOR_INIT(vectorDouble) != QGM_SUCCESS){
                                                QGM_VECTOR_QUIT(vectorInt);
                                                return 1;
                                            }
                                        
                                            for(i = 0; i < 20; ++i)
                                                if(QGM_VECTOR_PUSH_FRONT(vectorDouble, (double)i / 10.0)
                                                   != QGM_SUCCESS)
                                                    goto end;
                                        
                                            for(i = 0; i < 20; ++i)
                                                if(QGM_VECTOR_PUSH_BACK(vectorInt, i) != QGM_SUCCESS)
                                                    goto end;
                                        
                                            /** Affichage du vector double sans rien supprimer **/
                                            printf("Vector Double\n");
                                        
                                            for(i = 0; i < 20; ++i)
                                                printf("%.1f ", vectorDouble->data[i]);
                                            printf("Il y a %u elements dans le vectorDouble\n",
                                                   QGM_VECTOR_SIZE(vectorDouble));
                                        
                                            /** Affichage du vector int en supprimant toutes les données **/
                                            printf("\nVector int\n");
                                        
                                            for(i = 0; i < 20; ++i)
                                                printf("%d ", QGM_VECTOR_POP_BACK(vectorInt));
                                            printf("\nLe vector int est il vide ? %d\n",
                                                   QGM_VECTOR_EMPTY(vectorInt));
                                        
                                            end:
                                            QGM_VECTOR_QUIT(vectorInt);
                                            QGM_VECTOR_QUIT(vectorDouble);
                                        
                                            return 0;
                                        }
                                        


                                        Pile

                                        #include "QGM/alloc.h"
                                        #include "QGM/error.h"
                                        #include "QGM/data.h"
                                        
                                        int main(void){
                                            QGM_STACK(double) stack;
                                            int i;
                                        
                                            if(QGM_STACK_INIT(stack) != QGM_SUCCESS) return 1;
                                        
                                            for(i = 0; i < 20; ++i)
                                                if(QGM_STACK_PUSH(stack, (double)i / 10.0) != QGM_SUCCESS)
                                                    goto end;
                                        
                                            printf("Il ya %u elements\n", QGM_STACK_SIZE(stack));
                                            for(i = 0; i < 21; ++i)
                                                printf("%.1f ", QGM_STACK_POP(stack));
                                        
                                            printf("\n%s\n", QGM_GetError());
                                            printf("La pile est elle vide?%d", QGM_STACK_EMPTY(stack));
                                        
                                            end:
                                            QGM_STACK_QUIT(stack);
                                        
                                            return 0;
                                        }
                                        


                                        file
                                        #include "QGM/alloc.h"
                                        #include "QGM/error.h"
                                        #include "QGM/data.h"
                                        
                                        int main(void){
                                            QGM_QUEUE(double) queue;
                                            int i;
                                        
                                            if(QGM_QUEUE_INIT(queue) != QGM_SUCCESS) return 1;
                                        
                                            for(i = 0; i < 20; ++i)
                                                if(QGM_QUEUE_PUSH(queue, (double)i / 10.0) != QGM_SUCCESS)
                                                    goto end;
                                        
                                            printf("il y a %u elements\n", QGM_QUEUE_SIZE(queue));
                                        
                                            for(i = 0; i < 18; ++i)
                                                printf("%.1f ", QGM_QUEUE_POP(queue));
                                        
                                            printf("\nLa queue est elle vide?%d", QGM_QUEUE_EMPTY(queue));
                                        
                                            end:
                                            QGM_QUEUE_QUIT(queue);
                                        
                                            return 0;
                                        }
                                        


                                        Pour moi ce fut un vrai entraînement :
                                        -Découverte de l'opérateur virgule(approfondissement)
                                        -Découverte de l'utilité des ternaires
                                        -Découverte de la puissance du préprocesseur.

                                        Et un grand progrès sur le langage C.


                                        Merci pour vos conseils (passés, et futur)

                                        Cordialement
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                                          13 mai 2012 à 1:46:34

                                          *Soudain*, Pleins de questions!

                                          • Pourquoi utiliser la syntaxe (realloc)() (alors que memmove est appeler correctement) (m'en suis jamais servi)?
                                          • Il se passe quoi si tu mets des ';' avec des parenthèses au lieu des ',' partout?
                                          • Utiliser realloc/memmove/etc. est plus opti qu'une liste chaînée? (surtout les memmove) :S
                                          • En sommes tout ce code est pour éviter les void* c'est bien ça?
                                          • Est-ce comme ça, que sont implémenté les conteneurs de la STL?


                                          dsl, mais j'ai jamais codé en vert comme ça.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            13 mai 2012 à 2:52:15

                                            Salut.

                                            Alors :
                                            Realloc permet d augmenté la taille de mes tableaux. Memmove me permet de déplacer les données de un cran pour les vector.

                                            ; à la place de , déclencherais sûrement une erreur de compilation. De plus, un ; signale la fin d une instruction, hors ce que l on veut justement nous, c est avoir seulement une seule instruction par macro. Histoire de faire par exemple variable = pop(pile);

                                            Realloc a la place d une liste chaine est certainement bien plus optimisé dans le cas de la pile et de la file. Pour le vector, ce sera plus rapide dans le push / pop back et de plus en plus long vers l ajout au début où pres du début. Mais vut que généralement, on s en sert comme ça, ça ne doit pas poser de problème de vitesses d exécution.
                                            Cependant, il est vrai que si l on souhaite utilisé mon vector comme liste chainee, on risque d avoir de gros problème de perf sur l ajout en début, car il faut tout redeplacer de une case.
                                            Cependant, je ne vois pas l intérêt d utilisé une liste chaine. J ai cependant envie de coder, pour mon vector, une macro permettant d ajouter les données en les triant. Mais pas tout de suite, je verrais plus tard.

                                            Mon code permet certe de ne pas utilisé de pointeur void, mais bien plus que cela, permet une utilisation naturel de ces structures de données. Pouvoir récupéré à l intérieur d un appel de fonction une valeur avec pop est par exemple impossible( à moins de renvoyer le pointeur directement ) . Cela permet aussi d écrire push(self, 5). Alors que avec le type void on est obligé de passé l adresse d une variable près initialisée.

                                            Les conteneurs de la SL sont sûrement coder dans le même genre, mais en utilisant des template, et avec du code sûrement plus optimisé que le mien.( bien que je sois fier du mien, je doute être plus rapide que la SL.

                                            Moi aussi c est la première fois que je code en prepo xD
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
                                              13 mai 2012 à 3:16:07

                                              Citation

                                              Realloc permet d augmenté la taille de mes tableaux. Memmove me permet de déplacer les données de un cran pour les vector.

                                              Yeap, nan ça je savais, c'est juste pourquoi entouré le "realloc" de parenthèses en fait.

                                              Citation

                                              Les conteneurs de la SL sont sûrement coder dans le même genre, mais en utilisant des templates

                                              Bah oui mais finalement c'est pas ça des templates?
                                              Car là je retrouve bien le "T" partout.

                                              Je comprend pour les ';' finalement.

                                              C'est vraiment plein de nouveau réflex, faudrait que j'y aille à tatons je pourrais vraiment pas pondre ça du premier coup..

                                              Merci :)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                13 mai 2012 à 3:25:51

                                                En fait c est a la base pour éviter d appelée une eventuele macro realloc dans le cas ou je code une gestion d allocation dynamique. Mais je pense retirer les parenthèse afin d appeler ma propre fonction ;)
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !

                                                Vector, Stack, Queue en préprocesseur

                                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                • Editeur
                                                • Markdown