cmDList.h/c/Tpl.h : Initial commit.

This commit is contained in:
Kevin Larke 2015-08-02 15:07:59 -07:00
parent fd59f5ae69
commit 042b1173f5
3 changed files with 795 additions and 0 deletions

612
cmDList.c Normal file
View File

@ -0,0 +1,612 @@
#include "cmGlobal.h"
#include "cmRpt.h"
#include "cmErr.h"
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmDList.h"
typedef struct cmDListRecd_str
{
void* dV;
unsigned dN;
struct cmDListRecd_str* prev;
struct cmDListRecd_str* next;
} cmDListRecd_t;
typedef struct cmDListIndexRecd_str
{
cmDListRecd_t* r;
struct cmDListIndexRecd_str* prev;
struct cmDListIndexRecd_str* next;
} cmDListIndexRecd_t;
typedef struct cmDListIndex_str
{
unsigned id;
cmDListCmpFunc_t cmpFunc;
void* funcArg;
cmDListIndexFreeFunc_t freeFunc;
cmDListIndexRecd_t* first;
cmDListIndexRecd_t* last;
unsigned recdN;
struct cmDListIndex_str* link;
} cmDListIndex_t;
struct cmDList_str;
typedef struct cmDListIter_str
{
struct cmDList_str* p;
cmDListIndex_t* x;
cmDListIndexRecd_t* s;
struct cmDListIter_str* link;
} cmDListIter_t;
typedef struct cmDList_str
{
cmErr_t err;
cmDListRecd_t* first;
cmDListRecd_t* last;
unsigned recdN;
cmDListIndex_t* indexes;
cmDListIter_t* iters;
} cmDList_t;
cmDListH_t cmDListNullHandle = cmSTATIC_NULL_HANDLE;
cmDListIterH_t cmDListIterNullHandle = cmSTATIC_NULL_HANDLE;
cmDList_t* _cmDListHandleToPtr( cmDListH_t h )
{
cmDList_t* p = (cmDList_t*)h.h;
assert( p!=NULL );
return p;
}
cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId )
{
cmDListIndex_t* x = p->indexes;
for(; x!=NULL; x=x->link)
if( x->id == indexId )
return x;
return NULL;
}
void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n )
{
unsigned i;
for(i=0; i<n; ++i)
{
cmDListIndexRecd_t* s = cmMemAllocZ(cmDListIndexRecd_t,1);
s->prev = x->last;
if( x->last != NULL )
x->last->next = s;
else
{
assert( x->first == NULL );
x->first = s;
}
x->last = s;
}
x->recdN += n;
}
void _cmDListIndexUpdate( cmDList_t* p, cmDListIndex_t* x )
{
cmDListIndexRecd_t* first = NULL;
cmDListIndexRecd_t* last = NULL;
cmDListIndexRecd_t* avail = x->first;
// for each data recd
cmDListRecd_t* r = p->first;
for(; r!=NULL; r=r->next)
{
// get the next available index record
cmDListIndexRecd_t* a = avail;
avail = avail->next;
// The count of index records and data records should always be the same.
assert( a != NULL );
a->r = r;
cmDListIndexRecd_t* s = first;
// for each index recd that has already been sorted
for(; s!=NULL; s=s->next)
if( x->cmpFunc( x->funcArg, r->dV, r->dN, s->r->dV, s->r->dN ) < 0 )
{
// r is less than s->r
// insert 'a' prior to 's' in the index
a->next = s;
a->prev = s->prev;
// if 's' is not first
if( s->prev != NULL )
s->prev->next = a;
else
{ // 's' was first - now 'a' is first
assert( s == first );
first = a;
}
s->prev = a;
break;
}
// No records are greater than r or the index is empty - 'a' is last in the index.
if( s == NULL )
{
// insert 'a' after 'last'
// if the index is empty
if( last == NULL )
{
first = a;
a->prev = NULL;
}
else // make 'a' last in the index
{
a->prev = last;
a->next = NULL;
assert( last->next == NULL );
last->next = a;
}
a->next = NULL;
last = a;
}
}
x->first = first;
x->last = last;
}
void _cmDListRecdFree( cmDList_t* p, cmDListRecd_t* r )
{
if( r->prev != NULL )
r->prev->next = r->next;
else
p->first = r->next;
if( r->next != NULL )
r->next->prev = r->prev;
else
p->last = r->prev;
cmMemFree(r);
}
// Unlink and free the index record s;
void _cmDListIndexRecdFree( cmDListIndex_t* x, cmDListIndexRecd_t* s )
{
if( s->prev != NULL )
s->prev->next = s->next;
else
x->first = s->next;
if( s->next != NULL )
s->next->prev = s->prev;
else
x->last = s->prev;
cmMemFree(s);
}
// Unlink and release an index.
void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x )
{
if( x == NULL )
return;
cmDListIndex_t* x0 = NULL;
cmDListIndex_t* x1 = p->indexes;
// unlink 'x' from p->indexes
while( x1 != NULL )
{
if( x1 == x )
{
// x is the first index
if( x0 == NULL )
{
assert( x1 = p->indexes );
p->indexes = x->link;
}
else
{
x0->link = x1->link;
}
break;
}
x0 = x1;
x1 = x1->link;
}
// 'x' must have been found
assert( x1 == x );
// release each index record in 'x'
cmDListIndexRecd_t* s = x->first;
while( s != NULL )
{
cmDListIndexRecd_t* ns = s->next;
cmMemFree(s);
s = ns;
}
if( x->freeFunc != NULL )
x->freeFunc(x->id,x->funcArg);
cmMemFree(x);
}
// Unlink and release the iterator 'e'.
cmDlRC_t _cmDListIterFree( cmDListIter_t* e )
{
cmDList_t* p = e->p;
cmDListIter_t* e0 = NULL;
cmDListIter_t* e1 = p->iters;
while( e1 != NULL )
{
if( e1 == e )
{
if( e0 == NULL )
p->iters = e1->link;
else
e0->link = e1->link;
cmMemFree(e0);
break;
}
e0 = e1;
e1 = e1->link;
}
if( e1 == NULL )
return cmErrMsg(&p->err,kIterNotFoundDlRC,"The delete target iterator could not be found.");
return kOkDlRC;
}
cmDlRC_t _cmDListFree( cmDList_t* p )
{
cmDlRC_t rc = kOkDlRC;
// release all indexes
while( p->indexes != NULL )
_cmDListIndexFree(p,p->indexes);
while( p->iters != NULL )
_cmDListIterFree(p->iters);
// release all data records
while( p->first != NULL )
_cmDListRecdFree(p,p->first);
cmMemFree(p);
return rc;
}
cmDlRC_t _cmDListIndexAlloc( cmDList_t* p, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
{
cmDListIndex_t* x;
if((x =_cmDListIdToIndex(p, indexId )) != NULL )
return cmErrMsg(&p->err,kDuplicateIndexIdDlRC,"The indexId '%i' has already been used.",indexId);
x = cmMemAllocZ(cmDListIndex_t,1);
x->id = indexId;
x->cmpFunc = func;
x->funcArg = funcArg;
x->link = p->indexes;
p->indexes = x;
_cmDListIndexAllocRecds(x,p->recdN);
_cmDListIndexUpdate(p,x);
return kOkDlRC;
}
cmDlRC_t cmDListAlloc( cmCtx_t* ctx, cmDListH_t* hp, cmDListCmpFunc_t func, void* funcArg )
{
cmDlRC_t rc = kOkDlRC;
if((rc = cmDListFree(hp)) != kOkDlRC )
return rc;
cmDList_t* p = cmMemAllocZ(cmDList_t,1);
cmErrSetup(&p->err,&ctx->rpt,"cmDList");
if( func!=NULL )
if((rc = _cmDListIndexAlloc(p,0,func,funcArg)) != kOkDlRC )
goto errLabel;
hp->h = p;
errLabel:
if( rc != kOkDlRC )
_cmDListFree(p);
return rc;
}
cmDlRC_t cmDListFree( cmDListH_t* hp )
{
cmDlRC_t rc;
if( hp==NULL || cmDListIsValid(*hp)==false)
return kOkDlRC;
cmDList_t* p = _cmDListHandleToPtr(*hp);
if((rc = _cmDListFree(p)) != kOkDlRC )
return rc;
hp->h = NULL;
return rc;
}
bool cmDListIsValid( cmDListH_t h )
{ return h.h != NULL; }
cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN )
{
cmDList_t* p = _cmDListHandleToPtr(h);
char* vp = cmMemAllocZ(char,sizeof(cmDListRecd_t) + recdByteN );
cmDListRecd_t* r = (cmDListRecd_t*)vp;
r->dV = r + 1;
r->dN = recdByteN;
memcpy( r->dV, recd, recdByteN );
// Add records at the end of the list.
// If the list is not empty
if( p->last != NULL )
p->last->next = r;
else
{
// The list was empty
assert( p->first == NULL );
p->first = r;
}
r->prev = p->last;
r->next = NULL;
p->last = r;
p->recdN += 1;
// update the indexes
cmDListIndex_t* x = p->indexes;
for(; x!=NULL; x=x->link)
{
_cmDListIndexAllocRecds(x,1);
_cmDListIndexUpdate(p,x);
}
return kOkDlRC;
}
cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd )
{
cmDList_t* p = _cmDListHandleToPtr(h);
cmDListIndex_t* x = p->indexes;
cmDListIndexRecd_t* s = NULL;
cmDListRecd_t* r = NULL;
for(; x!=NULL; x=x->link)
{
for(s=x->first; s!=NULL; s=s->next)
if( s->r->dV == recd )
{
if( r == NULL )
r = s->r;
else
{
// the same data record should be found for all indexes
assert( s->r == r );
}
_cmDListIndexRecdFree(x,s);
break;
}
if( r == NULL )
return cmErrMsg(&p->err,kDataRecdNotFoundDlRC,"The delete target data record could not be found.");
// if the indexes are valid then the recd should always be found
assert( s!=NULL );
}
// release the data record
_cmDListRecdFree(p,r);
return kOkDlRC;
}
cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
{
cmDList_t* p = _cmDListHandleToPtr(h);
return _cmDListIndexAlloc(p,indexId,func,funcArg);
}
cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId )
{
cmDList_t* p = _cmDListHandleToPtr(h);
cmDListIndex_t* x;
if((x = _cmDListIdToIndex(p,indexId)) == NULL )
return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
_cmDListIndexFree(p,x);
return kOkDlRC;
}
cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFreeFunc_t func )
{
cmDList_t* p = _cmDListHandleToPtr(h);
cmDListIndex_t* x;
if((x = _cmDListIdToIndex(p,indexId)) == NULL )
return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
x->freeFunc = func;
return kOkDlRC;
}
cmDListIter_t* _cmDListIterHandleToPtr( cmDListIterH_t h )
{
cmDListIter_t* e = (cmDListIter_t*)h.h;
assert(e != NULL );
return e;
}
cmDlRC_t cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId )
{
cmDlRC_t rc = kOkDlRC;
cmDList_t* p = _cmDListHandleToPtr(h);
cmDListIndex_t* x;
if((rc = cmDListIterFree(iHp)) != kOkDlRC )
return rc;
if((x = _cmDListIdToIndex(p, indexId)) == NULL )
return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
cmDListIter_t* e = cmMemAllocZ(cmDListIter_t,1);
e->p = p;
e->x = x;
e->s = x->first;
e->link = p->iters;
p->iters = e;
iHp->h = e;
return rc;
}
cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp )
{
cmDlRC_t rc;
if( iHp==NULL || cmDListIterIsValid(*iHp)==false )
return kOkDlRC;
cmDListIter_t* e = _cmDListIterHandleToPtr(*iHp);
if(( rc = _cmDListIterFree( e )) != kOkDlRC )
return rc;
iHp->h = NULL;
return rc;
}
bool cmDListIterIsValid( cmDListIterH_t iH )
{ return iH.h != NULL; }
cmDlRC_t cmDListIterSeekBegin( cmDListIterH_t iH )
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
e->s = e->x->first;
return kOkDlRC;
}
cmDlRC_t cmDListIterSeekLast( cmDListIterH_t iH )
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
e->s = e->x->last;
return kOkDlRC;
}
const void* _cmDListIterGet( cmDListIter_t* e, unsigned* recdByteNRef )
{
if( e->s == NULL )
{
if( recdByteNRef != NULL )
*recdByteNRef = 0;
return NULL;
}
if( recdByteNRef != NULL )
*recdByteNRef = e->s->r->dN;
return e->s->r->dN==0 ? NULL : e->s->r->dV;
}
const void* cmDListIterGet( cmDListIterH_t iH, unsigned* recdByteNRef )
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
return _cmDListIterGet(e,recdByteNRef);
}
const void* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef )
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
const void* rv = _cmDListIterGet(e,recdByteNRef);
if( e->s != NULL )
e->s = e->s->prev;
return rv;
}
const void* cmDListIterNext( cmDListIterH_t iH, unsigned* recdByteNRef )
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
const void* rv = _cmDListIterGet(e,recdByteNRef);
if( e->s != NULL )
e->s = e->s->next;
return rv;
}
const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef)
{
cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
cmDListIndexRecd_t* s = e->s;
for(; s!=NULL; s=s->next)
if( e->x->cmpFunc( e->x->funcArg, s->r->dV, s->r->dN, key, keyN ) == 0 )
{
e->s = s;
return _cmDListIterGet(e,recdByteNRef);
}
if( recdByteNRef != NULL )
*recdByteNRef = 0;
return NULL;
}

61
cmDList.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef cmDList_h
#define cmDList_h
#ifdef __cplusplus
extern "C" {
#endif
enum
{
kOkDlRC = cmOkRC,
kDuplicateIndexIdDlRC,
kInvalidIndexDlRC,
kIterNotFoundDlRC,
kDataRecdNotFoundDlRC,
};
typedef unsigned cmDlRC_t;
typedef cmHandle_t cmDListH_t;
typedef cmHandle_t cmDListIterH_t;
extern cmDListH_t cmDListNullHandle;
extern cmDListIterH_t cmDListIterNullHandle;
// Return < 0 if v0 < v1
// == 0 if v0 == v1
// > 0 if v0 > v1
typedef int (*cmDListCmpFunc_t)( void* arg, const void* v0, unsigned v0N, const void* v1, unsigned v1N );
typedef void (*cmDListIndexFreeFunc_t)( unsigned indexId, void* arg );
// If 'f' is not NULL then a default index with an indexId==0 will be automatically created.
cmDlRC_t cmDListAlloc( cmCtx_t* ctx, cmDListH_t* hp, cmDListCmpFunc_t f, void* farg );
cmDlRC_t cmDListFree( cmDListH_t* hp );
bool cmDListIsValid( cmDListH_t h );
cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN );
cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd );
cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t f, void* farg );
cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId );
cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFreeFunc_t func );
cmDlRC_t cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId );
cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp );
bool cmDListIterIsValid( cmDListIterH_t iH );
cmDlRC_t cmDListIterSeekBegin( cmDListIterH_t iH );
cmDlRC_t cmDListIterSeekEnd( cmDListIterH_t iH );
const void* cmDListIterGet( cmDListIterH_t iH, unsigned* recdByteNRef );
const void* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef );
const void* cmDListIterNext( cmDListIterH_t iH, unsigned* recdByteNRef );
const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef);
#ifdef __cplusplus
}
#endif
#endif

122
cmDListTpl.h Normal file
View File

@ -0,0 +1,122 @@
// The following two macros must be defined prior to including this code:
// #define cmSFX(a) a##_MySuffix
// #define cmTYPE My_Type
// Also define cmGEN_HDR to generate the .h code and/or
// cmGEN_CODE to generate the .c code
#ifdef cmGEN_HDR
typedef int (*cmSFX(cmDListFunc))( void* arg, const cmTYPE* v0, const cmTYPE* v1 );
cmDlRC_t cmSFX(cmDListAlloc)( cmCtx_t* ctx, cmDListH_t* hp, cmSFX(cmDListFunc) func, void* funcArg );
cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd );
cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd );
cmDlRC_t cmSFX(cmDListAllocIndex)( cmDListH_t h, unsigned indexId, cmSFX(cmDListFunc) f, void* farg );
const cmTYPE* cmSFX(cmDListIterGet)( cmDListIterH_t iH );
const cmTYPE* cmSFX(cmDListIterPrev)( cmDListIterH_t iH );
const cmTYPE* cmSFX(cmDListIterNext)( cmDListIterH_t iH );
const cmTYPE* cmSFX(cmDListIterFind)( cmDListIterH_t iH, const cmTYPE* key);
#endif // cmGEN_HDR
#ifdef cmGEN_CODE
typedef struct
{
cmSFX(cmDListFunc) func;
void* funcArg;
} cmSFX(_cmDListArg);
// This function is called when the index identified by indexId is about to be deleted.
// It is used to cleanup the arg record created by cmSFX(cmDListIndexAlloc()).
void cmSFX(_cmDListIndexOnFree)( unsigned indexId, void* arg )
{
cmMemFree(arg);
}
// Proxy function used to cast generic compare function to the user defined compare function.
int cmSFX(_cmDListCmp)( void* arg, const void* v0, unsigned vn0, const void* v1, unsigned vn1 )
{
assert(vn0==vn1 && sizeof(cmTYPE)==vn0);
cmSFX(_cmDListArg)* a = (cmSFX(_cmDListArg)*)arg;
return a->func(a->funcArg,(const cmTYPE*)v0,(const cmTYPE*)v1);
}
cmDlRC_t cmSFX(cmDListAlloc)( cmCtx_t* ctx, cmDListH_t* hp, cmSFX(cmDListFunc) func, void* funcArg )
{
cmDlRC_t rc;
cmSFX(_cmDListArg)* a = NULL;
if( func != NULL )
{
// allocate a record to redirect the compare function callback
a = cmMemAllocZ(cmSFX(_cmDListArg),1);
a->func = func;
a->funcArg = funcArg;
}
if((rc = cmDListAlloc(ctx,hp,cmSFX(_cmDListCmp),a)) != kOkDlRC )
return rc;
if( func != NULL )
if((rc = cmDListIndexSetFreeFunc(*hp,0,cmSFX(_cmDListIndexOnFree))) != kOkDlRC )
cmDListFree(hp);
return rc;
}
cmDlRC_t cmSFX(cmDListIndexAlloc)( cmDListH_t h, unsigned indexId, cmSFX(cmDListFunc) func, void* funcArg )
{
cmDlRC_t rc;
// allocate a record to redirect the compare function callback
cmSFX(_cmDListArg)* a = cmMemAllocZ(cmSFX(_cmDListArg),1);
a->func = func;
a->funcArg = funcArg;
// allocate the index
if((rc = cmDListIndexAlloc(h,indexId,cmSFX(_cmDListCmp),a)) != kOkDlRC )
{
cmMemFree(a);
goto errLabel;
}
// set the index clean up handler
if((rc = cmDListIndexSetFreeFunc(h,indexId,cmSFX(_cmDListIndexOnFree))) != kOkDlRC )
cmDListIndexFree(h,indexId);
errLabel:
return rc;
}
cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd )
{ return cmDListInsert(h,recd,sizeof(recd)); }
cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd )
{ return cmDListDelete(h,recd); }
const cmTYPE* cmSFX(cmDListIterGet)( cmDListIterH_t iH )
{ return (const cmTYPE*)cmDListIterGet(iH,NULL);}
const cmTYPE* cmSFX(cmDListIterPrev)( cmDListIterH_t iH )
{ return (const cmTYPE*)cmDListIterPrev(iH,NULL); }
const cmTYPE* cmSFX(cmDListIterNext)( cmDListIterH_t iH )
{ return (const cmTYPE*)cmDListIterNext(iH,NULL); }
const cmTYPE* cmSFX(cmDListIterFind)( cmDListIterH_t iH, const cmTYPE* key)
{ return (const cmTYPE*)cmDListIterFind(iH,key,sizeof(cmTYPE),NULL); }
#endif // cmGEN_CODE
#undef cmSFX
#undef cmTYPE