C言語環境では,独自のVectorコンテナを作成する.

16964 ワード


C言語環境では,独自のVectorコンテナを作成する.
 
王宇がオリジナルで発表した.
 
最近の仕事では、いくつかの統計データの機能を標準Cで実現する必要があります.開発中に容器がないのはとても不便なので、簡単なVector容器を自分で作成してみました.
 
一、機能説明:
 
このVectorの使用方法を一例で説明します.
#include "containers.h"
#include 
//        
typedef struct tagTextStruct
{
             int key;
             char* value;
}TestStruct;
 
//       
static void ABORT( char *file,int line)
{
             fprintf(stderr ,"*****

ABORT
File %s Line %d
**********

",file,line); abort(); } #define Abort () ABORT(__FILE__,__LINE__) // static int destructorFunc( void *v) { // Vector TestStruct* ts = (TestStruct*)v; if(ts->value != NULL ) { int l = strlen (ts->value); // free(ts->value); ts->value = NULL; } return 0; } // Vector static void PrintVector(Vector *AL) { size_t i; TestStruct* ts; // Vector , printf("Count %ld, Capacity %ld
",(long)iVector. Size(AL),(long )iVector.GetCapacity(AL)); // Vector for (i=0; ikey); printf("%s
" ,ts->value); } printf("
" ); } // Vector static int testVector(Vector** AL) { int errors=0; char* s1 = "ts1 value." ; char* s2 = "ts2 value" ; char* temp1 = NULL ; char* temp2 = NULL ; TestStruct ts1, ts2; *AL = iVector. Create(sizeof (TestStruct),5); // , destructorFunc 。 iVector. SetDestructor(*AL, destructorFunc ); // , ts1.key = 1; temp1 = ( char*)malloc (strlen(s1) + 1); if(temp1 == NULL) { Abort(); } strcpy(temp1, s1); ts1.value = temp1; ts2.key = 2; temp2 = ( char*)malloc (strlen(s2) + 1); if(temp2 == NULL) { Abort(); } strcpy(temp2, s2); ts2.value = temp2; // Vecotor iVector. Add(*AL,&ts1); iVector. Add(*AL,&ts2); // Vector iVector. Erase(*AL, &ts1); // if (1 != iVector.Size (*AL)) Abort(); return errors; } // int main (void) { int errors=0; Vector* AL = NULL; // Vector errors += testVector (&AL); // Vector iVector.Finalize(*AL); return errors; }

   
 
 
 
二、Vectorの構造:
 
   
宣言Vectorタイプ:
 
/*----------------------------------------------------------------------------*/
/* Definition of the vector type                                              */
/*----------------------------------------------------------------------------*/
struct _Vector {
    VectorInterface *VTable;       /* The table of functions */
    size_t count;                  /* number of elements in the array */
    unsigned int Flags;            /* Read-only or other flags */
    size_t ElementSize;            /* Size of the elements stored in this array. */
    void *contents;                /* The contents of the collection */
    size_t capacity;               /* allocated space in the contents vector */
    unsigned timestamp;            /* Incremented at each change */
    CompareFunction CompareFn;     /* Element comparison function */
    ErrorFunction RaiseError;      /* Error function */
    const ContainerAllocator *Allocator;
    DestructorFunction DestructorFn;
} ;

 
 
Vectorインタフェースの宣言:
/****************************************************************************
 *           Vectors        Interface                                                 *
  ****************************************************************************/
 
/* Definition of the functions associated with this type. */
typedef struct tagVector {
    size_t (* Size)(const Vector *AL);
    int (* Clear)(Vector *AL);
    int (* Erase)(Vector *AL,const void *);
    int (* EraseAll)(Vector *AL,const void *);
    int (* Finalize)(Vector *AL);
    int (* Apply)(Vector *AL,int (*Applyfn)( void *element,void * arg),void *arg);
    int (* Equal)(const Vector *first,const Vector *second);
    Vector *(* Copy)(const Vector *AL);
    ErrorFunction (* SetErrorFunction)(Vector *AL,ErrorFunction );
    size_t (* Sizeof)(const Vector *AL);
    Vector *(* Load)(FILE *stream, ReadFunction readFn,void *arg);
    size_t (* GetElementSize)(const Vector *AL);
    int (* Add)(Vector *AL,const void *newval);
    void *(* GetElement)(const Vector *AL,size_t idx);
    int (* EraseAt)(Vector *AL,size_t idx);
    int (* ReplaceAt)(Vector *AL,size_t idx,void *newval);
    int (* IndexOf)(const Vector *AL,const void *data,void *ExtraArgs,size_t *result);
 
    /* Vector container specific fields */
    size_t (* GetCapacity)(const Vector *AL);
    int (* SetCapacity)(Vector *AL,size_t newCapacity);
 
    CompareFunction (* SetCompareFunction)(Vector *l,CompareFunction fn);
    int (* Sort)(Vector *AL);
    Vector *(* Create)(size_t elementsize,size_t startsize);
    Vector *(* CreateWithAllocator)(size_t elemsiz,size_t startsiz,const ContainerAllocator *mm);
    int (* CopyElement)(const Vector *AL,size_t idx,void *outbuf);
    void **(* CopyTo)(const Vector *AL);
    int (* Append)(Vector *AL1, Vector *AL2);
    const ContainerAllocator *(* GetAllocator)(const Vector *AL);
    DestructorFunction (* SetDestructor)(Vector *v,DestructorFunction fn);
    int (* SearchWithKey)(Vector *vec,size_t startByte,size_t sizeKey,size_t startIndex,void *item,size_t *result);
    int (* Resize)(Vector *AL,size_t newSize);
} VectorInterface;

  
 
 
メモリ割り当てオブジェクト:
/************************************************************************** */
/*                                                                          */
/*                          Memory allocation object                        */
/*                                                                          */
/************************************************************************** */
typedef struct tagAllocator {
    void *(* malloc)(size_t);        /* Function to allocate memory */
    void (* free)(void *);           /* Function to release it      */
    void *(* realloc)(void *,size_t);/* Function to resize a block of memory */
    void *(* calloc)(size_t,size_t);
} ContainerAllocator;

  
三、機能の実現:
 
1,Vectorの作成
static Vector *CreateWithAllocator (size_t elementsize,size_t startsize,const ContainerAllocator *allocator)
{
    Vector *result;
    size_t es;
   //  Vector         。
    /* Allocate space for the array list header structure */
    result = allocator-> malloc(sizeof (*result));//      malloc  stdlib.h  malloc,         ContainerAllocator   。
     //           。
     if (result == NULL) {
        iError.RaiseError( "iVector.Create",CONTAINER_ERROR_NOMEMORY );
        return NULL ;
    }
    //      。
    memset(result,0, sizeof(*result));
    if (startsize == 0)
        startsize = DEFAULT_START_SIZE;
 
   //  Vector           。
    es = startsize * elementsize;              //               ,        ,            。                     
    result->contents = allocator-> malloc(es); //      malloc  stdlib.h  malloc,         ContainerAllocator   。
     //           。
    if (result->contents == NULL) {
        iError.RaiseError( "iVector.Create",CONTAINER_ERROR_NOMEMORY ); //               iError
        allocator-> free(result);  //    free  stdlib.h free,          ContainerAllocator   。
        result = NULL;
    }
    else {
        //      
        memset(result->contents,0,es);
       // Vector   
        result->capacity = startsize;
       // Vector   
        result->VTable = &iVector;
       // Vector           
        result->ElementSize = elementsize;
       //     
        result->CompareFn = DefaultVectorCompareFunction;
        result->RaiseError = iError.RaiseError;
       //      
        result->Allocator = (ContainerAllocator *)allocator;
    }
    return result;
}
 
//     ,             :Vector *(* Create)(size_t elementsize,size_t startsize);
static Vector *Create (size_t elementsize,size_t startsize)
{
    return CreateWithAllocator(elementsize,startsize,CurrentAllocator);
}

  
2.Vectorに要素を追加するには:
//         (vector->capacity),      。
static int grow(Vector *AL)
{
            size_t newcapacity;
             void **oldcontents;
             int r = 1;
            //            
            newcapacity = AL->capacity + 1+AL->capacity/4;
            oldcontents = ( void **)AL->contents;
            //       
            AL->contents = AL->Allocator->realloc (AL->contents,newcapacity*AL->ElementSize);
             if (AL->contents == NULL ) {
                         NoMemory(AL,"Resize" );                                     //     。
                        AL->contents = oldcontents;
                        r = CONTAINER_ERROR_NOMEMORY;
            }
             else {
                         //     
                        AL->capacity = newcapacity;
                        AL->timestamp++;
            }
             return r;
}
 
//     ,             : int (* Add)(Vector *AL,const void *newval);
/*------------------------------------------------------------------------
 Procedure:     Add ID:1
 Purpose:       Adds an item at the end of the Vector
 Input:         The Vector and the item to be added
 Output:        The number of items in the Vector or negative if
                error
 Errors:
------------------------------------------------------------------------*/
static int Add(Vector *AL, const void *newval)
{
             char *p;
             //           
             if (AL == NULL ) {
                         return NullPtrError ("Add");
            }
 
             if (newval == NULL ) {
                        AL->RaiseError( "iVector.Add",CONTAINER_ERROR_BADARG );
                         return CONTAINER_ERROR_BADARG ;
            }
            //   
             if (AL->count >= AL->capacity) {
                         int r = grow (AL);
                         if (r <= 0)
                                     return r;
            }
           //              
            p = ( char *)AL->contents;
            p += AL-> count*AL->ElementSize;
             memcpy(p,newval,AL->ElementSize);
            AL->timestamp++;
   
            ++AL-> count;
             return 1;
}
 

 
3、Vectorの要素を削除します.
//   index   Vector    
static int EraseAt(Vector *AL,size_t idx)
{
    char *p;
     //           
    if (AL == NULL) {
        return NullPtrError ("EraseAt");
    }
    if (idx >= AL-> count) {
        AL->RaiseError( "iVector.Erase",CONTAINER_ERROR_INDEX ,AL,idx);
        return CONTAINER_ERROR_INDEX ;
    }
   //            
    p = ( char *)AL->contents;
    p += AL->ElementSize * idx;
   //              ,   
    if (AL->DestructorFn) {
        AL->DestructorFn(p);
    }
     //     ,    
    if (idx < (AL-> count-1)) {
        memmove(p,p+AL->ElementSize,(AL->count -idx-1)*AL->ElementSize);
    }
    AL-> count--;
    AL->timestamp++;
    return 1;
}
 
 
static int EraseInternal(Vector *AL, const void *elem,int all)
{
    size_t i;
    char *p;
    CompareInfo ci;
    int result = CONTAINER_ERROR_NOTFOUND;
     //           
    if (AL == NULL) {
        return NullPtrError ("Erase");
    }
    if (elem == NULL) {
        AL->RaiseError( "iVector.Erase",CONTAINER_ERROR_BADARG );
        return CONTAINER_ERROR_BADARG ;
    }
    if (AL->Flags & CONTAINER_READONLY)
    return ErrorReadOnly(AL,"Erase" );
  
restart:
    p = AL->contents;
    ci.ContainerLeft = AL;
    ci.ContainerRight = NULL;
    ci.ExtraArgs = NULL;
   //   Vecotr  
    for (i=0; i count;i++) {
   //        ,    CompareFn        ,        ,    Vector
    if (!AL->CompareFn(p,elem,&ci)) {
        if (i > 0) {
        //          
        p = GetElement(AL,--i);
        result = EraseAt(AL,i+1);
        } else {
       //        
        result = EraseAt(AL,0);
       // all = 0       ,    Vector
        if (result < 0 || all == 0) return result;
        if (all) goto restart;
        }
        if (all == 0) return result;
        result = 1;
    }
    p += AL->ElementSize;
    }
    return result;
 
}
//     ,             : int (* Erase)(Vector *AL,const void *);
static int Erase(Vector *AL, const void *elem)
{
  //   0 ,         
    return EraseInternal(AL,elem,0);
}

  
4、Vectorのサイズを決定する:
//     ,             : size_t (* Size)(const Vector *AL);
static size_t Size(const Vector *AL)
{
     //           
    if (AL == NULL) {
        NullPtrError("Size" );
        return 0;
    }
     //   Vector     
    return AL-> count;
}

  
5、Vectorの要素を取得します.
//     ,             :    void *(* GetElement)(const Vector *AL,size_t idx);
static void *GetElement( const Vector *AL,size_t idx)
{
    char *p;
    //           
    if (AL == NULL) {
        NullPtrError("GetElement" );
        return NULL ;
    }
 
    if (idx >=AL-> count ) {
        return  AL->RaiseError("iVector.GetElement" ,CONTAINER_ERROR_INDEX,AL,idx);
    }
   //         
    p = AL->contents;
   //       
    p += idx*AL->ElementSize;
    return p;
}

  
6,Vectorリソースを解放する:
//     ,             : int (* Clear)(Vector *AL);
/*------------------------------------------------------------------------
 Procedure:     Clear ID:1
 Purpose:       Frees all memory from an array list object without
        freeing the object itself
 Input:         The array list to be cleared
 Output:        The number of objects that were in the array list
 Errors:        The array list must be writable
------------------------------------------------------------------------*/
static int Clear(Vector *AL)
{
//           
    if (AL == NULL) {
        return NullPtrError ("Clear");
    }
//              ,   DestructorFn        。    ,    destructorFunc()
    if (AL->DestructorFn) {
        size_t i;
        unsigned char *p = (unsigned char *)AL->contents;
        //   Vector     DestructorFn           
        for(i=0; icount ;i++) {
            AL->DestructorFn(p);
            p += AL->ElementSize;
        }
    }
 
    AL-> count = 0;
    AL->timestamp = 0;
    AL->Flags = 0;
 
    return 1;
}
 
//     ,             :    int (* Finalize)(Vector *AL);
/*------------------------------------------------------------------------
 Procedure:     Finalize ID:1
 Purpose:       Releases all memory associated with an Vector,
        including the Vector structure itself
 Input:         The Vector to be destroyed
 Output:        The number of items that the Vector contained or
        zero if error
 Errors:        Input must be writable
------------------------------------------------------------------------*/
static int Finalize(Vector *AL)
{
    unsigned Flags;
    int result;
//           
    if (AL == NULL)
        return CONTAINER_ERROR_BADARG ;
//           
    result = Clear(AL);
    if (result < 0)
        return result;
//   Vector         
    if (AL->VTable != &iVector)
        AL->Allocator-> free(AL->VTable);      //   free  stdlib.h free,          ContainerAllocator   。
    AL->Allocator-> free(AL->contents);
    AL->Allocator-> free(AL);
    return result;
}

  
四、まとめ
     
紙面の都合上、ここではこのVectorの基本的な機能、すなわちCreate、Add、Erase、Size、GetElement、Finalizeのみを紹介した.その他の機能としては、Appent RelaceAt Search IndexOf Sort Resizeなどがあります.ここでは紹介しません.なぜなら、このブログの目的はC言語を勉強し研究する友达のために玉を投げることだけです.私は学習の過程で以下のいくつかの方面の比較的重要な内容を総括して、みんなに参考を提供します.
 
 
1、C言語のプログラムを十分に理解して、メモリの中の分布.スタック、スタック、データエリアなど.
2、メモリの割り当てと解放.
3、ポインタとポインタ関数の活用.
4、構造体とポインタ関数を組み合わせて使用し、インタフェースオブジェクトを形成する.