yone's Journal
 
[Most Recent Entries] [Calendar View] [Friends]

Below are the 1 most recent journal entries recorded in yone's LiveJournal:

    Wednesday, December 28th, 2016
    3:20 pm
    Первый пост мой.

    Смотрите, какую я фигню написал. Полностью типобезопасный вектор на сишных макросах:

    #include <stdlib.h>
    #include <stdio.h>
    
    // сами напишите, короче:
    //   void *xmalloc(size_t nelems, size_t elemsz)
    //   void *xrealloc(void *p, size_t nelems, size_t elemsz)
    //   void *x2realloc(void *p, size_t *pnelems, size_t elemsz)
    #define XNEW(Type_, N_) ((Type_*) xmalloc(N_, sizeof(Type_)))
    
    #define VECTOR_OF(Type_) struct { Type_ *data; size_t size, capacity; }
    
    #define VECTOR_NEW_RESERVE(Type_, Capa_) {XNEW(Type_, Capa_), 0, Capa_}
    
    #define VECTOR_INIT(Vec_) \
        do { \
            (Vec_).data = NULL; \
            (Vec_).size = 0; \
            (Vec_).capacity = 0; \
        } while (0)
    
    #define VECTOR_INIT_RESERVE(Vec_, Capa_) \
        do { \
            (Vec_).data = XNEW(Type_, Capa_); \
            (Vec_).size = 0; \
            (Vec_).capacity = (Capa_); \
        } while (0)
    
    #define VECTOR_CLEAR(Vec_) \
        do { (Vec_).size = 0; } while (0)
    
    #define VECTOR_RESERVE(Vec_, Capa_) \
        do { \
            if ((Vec_).capacity < (Capa_)) { \
                (Vec_).capacity = (Capa_); \
                (Vec_).data = xrealloc((Vec_).data, (Vec_).capacity, sizeof(*(Vec_).data)); \
            } \
        } while (0)
    
    #define VECTOR_ENSURE(Vec_, Capa_) \
        do { \
            if ((Vec_).capacity < (Capa_)) { \
                (Vec_).data = x2realloc((Vec_).data, &(Vec_).capacity, sizeof(*(Vec_).data)); \
            } \
        } while (0)
    
    #define VECTOR_SHRINK(Vec_) \
        do { \
            (Vec_).capacity = (Vec_).size; \
            (Vec_).data = xrealloc((Vec_).data, (Vec_).capacity, sizeof(*(Vec_).data)); \
        } while (0)
    
    #define VECTOR_PUSH(Vec_, Elem_) \
        do { \
            VECTOR_ENSURE(Vec_, (Vec_).size + 1); \
            (Vec_).data[(Vec_).size++] = (Elem_); \
        } while (0)
    
    #define VECTOR_FREE(Vec_) free((Vec_).data)
    
    int main()
    {
        VECTOR_OF(int) v = {}; // прям как в крестах
        //VECTOR_OF(int) v = {1, 2, 3}; // не, так нельзя — warning: initialization makes pointer from integer without a cast
        int x = 1;
        VECTOR_PUSH(v, x++); // no side effects
        VECTOR_PUSH(v, x++);
        VECTOR_PUSH(v, x++);
        for (size_t i = 0; i < v.size; ++i) {
            printf("%d\n", v.data[i]);
        }
        VECTOR_FREE(v);
     
        //VECTOR_OF(char) u = VECTOR_NEW_RESERVE(int, 32); // warning: initialization from incompatible pointer type
        VECTOR_OF(char) u = VECTOR_NEW_RESERVE(char, 32);
        //VECTOR_PUSH(u, "x"); // warning: assignment makes integer from pointer without a cast
        VECTOR_FREE(u);
    }
    


    Их ещё тайпдефать можно, типа typedef VECTOR_OF(char) String;. Только вот незатайпдефенные нельзя передавать и возвращать из функций, потому что анонимные структуры в сишке считаются ничему не равными (а вот в составе других структур — можно). Можно было бы предложить делать так:
    void push_next(VECTOR_OF(int) *pv)
    {
        static int x = 1;
        VECTOR_PUSH(*pv, x++);
    }
    
    void print_vec(VECTOR_OF(int) *pv)
    {
        for (size_t i = 0; i < pv->size; ++i) {
            printf("%d\n", pv->data[i]);
        }
    }
    
    int main()
    {
        VECTOR_OF(int) v = {};
        push_next((void*) v);
        push_next((void*) v);
        push_next((void*) v);
        print_vec((void*) v);
        VECTOR_FREE(v);
    }
    

    но это включает предупреждения о том, что функция принимает указатель на анонимную структуру, описанную прямо в списке аргументов.
    Но на самом-то деле, это нинужно:
    1. если функция вообще не меняет вектор, а только читает, то ей достаточно константного указателся и длины;
    2. если функция не меняет размер вектора, а только читает и изменяет элементы, то ей достаточно неконстантного указателся и длины;
    3. если функция может менять размер вектора, но только в меньшую сторону, то ей достаточно неконстантного указателся и указателся на длину;
    4. если функция может менять размер вектора в большую сторону, то ей нужны (увы): указатель на указатель, указатель на длину, указатель на capacity — см. x2realloc.
    Такие функции будут работать не только с векторами, а с любыми непрерывными кусками данных (в последнем случае — только с полученными с помощью malloc). Хорошо же.

    Кто-нибудь делает так же?
About LJ.Rossia.org