From 9bf87e175b2762e3594524db47a0c2b106e5f945 Mon Sep 17 00:00:00 2001 From: Kevin Larke Date: Mon, 3 Aug 2015 08:28:22 -0700 Subject: [PATCH] cmDList.h/c/Tpl.h : Changes to support initial debugging of cmDList. --- cmDList.c | 296 ++++++++++++++++++++++++++++++++------------------- cmDList.h | 53 +++++++-- cmDListTpl.h | 14 +-- 3 files changed, 234 insertions(+), 129 deletions(-) diff --git a/cmDList.c b/cmDList.c index 5795133..831b106 100644 --- a/cmDList.c +++ b/cmDList.c @@ -39,10 +39,10 @@ struct cmDList_str; typedef struct cmDListIter_str { - struct cmDList_str* p; - cmDListIndex_t* x; - cmDListIndexRecd_t* s; - struct cmDListIter_str* link; + struct cmDList_str* p; // pointer to the owner cmDList + cmDListIndex_t* x; // pointer to the index this iterator traverses + cmDListIndexRecd_t* s; // current record + struct cmDListIter_str* link; // p->iters list link } cmDListIter_t; typedef struct cmDList_str @@ -66,6 +66,7 @@ cmDList_t* _cmDListHandleToPtr( cmDListH_t h ) return p; } +// Given an indexId return the associated index. cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId ) { cmDListIndex_t* x = p->indexes; @@ -76,12 +77,14 @@ cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId ) return NULL; } +// Allocate 'n' new index records for the index 'x'. void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n ) { unsigned i; for(i=0; iprev = x->last; if( x->last != NULL ) @@ -99,82 +102,6 @@ void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned 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 ) @@ -202,7 +129,7 @@ void _cmDListIndexRecdFree( cmDListIndex_t* x, cmDListIndexRecd_t* s ) s->next->prev = s->prev; else x->last = s->prev; - + cmMemFree(s); } @@ -274,7 +201,7 @@ cmDlRC_t _cmDListIterFree( cmDListIter_t* e ) else e0->link = e1->link; - cmMemFree(e0); + cmMemFree(e1); break; } @@ -307,6 +234,99 @@ cmDlRC_t _cmDListFree( cmDList_t* p ) return rc; } + +void _cmDListIndexUpdate( cmDList_t* p, cmDListIndex_t* x ) +{ + cmDListIndexRecd_t* first = NULL; + cmDListIndexRecd_t* last = NULL; + + assert( x->recdN >= p->recdN ); + + // for each data recd + cmDListRecd_t* r = p->first; + for(; r!=NULL; r=r->next) + { + // get the next available index record + cmDListIndexRecd_t* a = x->first; + assert(a!=NULL); + x->first = x->first->next; + if( x->first != NULL ) + x->first->prev = NULL; + + // 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; + } + } + + // release any index records that are not in use + while(x->first!=NULL) + { + _cmDListIndexRecdFree(x,x->first); + x->recdN -= 1; + } + + assert( x->recdN == p->recdN ); + + // Invalidate all iterators which use index x. + cmDListIter_t* e = p->iters; + for(; e!=NULL; e=e->link) + if( e->x == x ) + e->s = NULL; + + x->first = first; + x->last = last; +} + + cmDlRC_t _cmDListIndexAlloc( cmDList_t* p, unsigned indexId, cmDListCmpFunc_t func, void* funcArg ) { cmDListIndex_t* x; @@ -373,7 +393,8 @@ cmDlRC_t cmDListFree( cmDListH_t* hp ) bool cmDListIsValid( cmDListH_t h ) { return h.h != NULL; } -cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN ) + +cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN, bool resyncFl ) { cmDList_t* p = _cmDListHandleToPtr(h); char* vp = cmMemAllocZ(char,sizeof(cmDListRecd_t) + recdByteN ); @@ -383,7 +404,7 @@ cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN ) r->dN = recdByteN; memcpy( r->dV, recd, recdByteN ); - // Add records at the end of the list. + // Add records at the end of the data record list. // If the list is not empty if( p->last != NULL ) @@ -400,51 +421,88 @@ cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN ) p->last = r; p->recdN += 1; - // update the indexes + // add a record to each index cmDListIndex_t* x = p->indexes; for(; x!=NULL; x=x->link) { - _cmDListIndexAllocRecds(x,1); - _cmDListIndexUpdate(p,x); + if( x->recdN < p->recdN ) + _cmDListIndexAllocRecds(x,1); + + assert( x->recdN >= p->recdN ); + + if( resyncFl ) + _cmDListIndexUpdate(p,x); } + return kOkDlRC; } -cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd ) +cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd, bool resyncFl ) { - cmDList_t* p = _cmDListHandleToPtr(h); - cmDListIndex_t* x = p->indexes; + cmDList_t* p = _cmDListHandleToPtr(h); + cmDListIndex_t* x = p->indexes; cmDListIndexRecd_t* s = NULL; - cmDListRecd_t* r = NULL; - - for(; x!=NULL; x=x->link) + cmDListRecd_t* r = NULL; + + if( resyncFl==false ) { - for(s=x->first; s!=NULL; s=s->next) - if( s->r->dV == recd ) + r = p->first; + for(; r!=NULL; r=r->next) + if( 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); - + _cmDListRecdFree(p,r); break; } - if( r == NULL ) - return cmErrMsg(&p->err,kDataRecdNotFoundDlRC,"The delete target data record could not be found."); + } + else + { + // for each index + for(; x!=NULL; x=x->link) + { + // for each index recd + for(s=x->first; s!=NULL; s=s->next) + if( s->r->dV == recd ) // if this index recd points to the deletion target + { + // store a ptr to the data recd to be deleted + if( r == NULL ) + r = s->r; + else + { + // the same data record should be found for all indexes + assert( s->r == r ); + } + + // free the index record + _cmDListIndexRecdFree(x,s); + + break; + } + + // if the deletion target was not found + if( r == NULL ) + goto errLabel; - // if the indexes are valid then the recd should always be found - assert( s!=NULL ); + } + + // advance any iterators that are pointing to the deleted record + cmDListIter_t* e = p->iters; + for(; e!=NULL; e=e->link) + if( e->s != NULL && e->s->r != NULL && e->s->r == r ) + e->s = e->s->next; + + // release the data record + _cmDListRecdFree(p,r); + } - // release the data record - _cmDListRecdFree(p,r); + errLabel: + if( r == NULL ) + return cmErrMsg(&p->err,kDataRecdNotFoundDlRC,"The deletion target record could not be found."); + + assert( p->recdN > 0 ); + p->recdN -= 1; return kOkDlRC; @@ -479,6 +537,18 @@ cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFre return kOkDlRC; } +cmDlRC_t cmDListIndexUpdateAll( cmDListH_t h ) +{ + cmDList_t* p = _cmDListHandleToPtr(h); + cmDListIndex_t* x = p->indexes; + + for(; x!=NULL; x=x->link) + _cmDListIndexUpdate(p,x); + + return kOkDlRC; +} + + cmDListIter_t* _cmDListIterHandleToPtr( cmDListIterH_t h ) { @@ -557,6 +627,8 @@ const void* _cmDListIterGet( cmDListIter_t* e, unsigned* recdByteNRef ) return NULL; } + assert( e->s->r != NULL ); + if( recdByteNRef != NULL ) *recdByteNRef = e->s->r->dN; @@ -585,7 +657,7 @@ 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; diff --git a/cmDList.h b/cmDList.h index 97f22d1..aff47e1 100644 --- a/cmDList.h +++ b/cmDList.h @@ -30,27 +30,60 @@ extern "C" { 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 ); + // If 'cmpFunc' 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 cmpFunc, void* funcArg ); + cmDlRC_t cmDListFree( cmDListH_t* hp ); + bool cmDListIsValid( cmDListH_t h ); - - cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t f, void* farg ); - cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId ); + // Set resyncFl to automatically update the indexes to reflect the new record, otherwise + // cmDListIndexUpdateAll() should be called to resynchronize the data list to the indexes. + // If many inserts are to be performed with no intervening accesses to the list then it + // is more efficient to defer updating the indexes until all the inserts are completed. + cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN, bool resyncFl ); + + // Delete a data record. + // 'recd' should be set to a value returned via one of the iterator accessors. + // If 'resyncFl' is set then the indexes and interators will be + // automatically synchronized with the data list after the deletion. + // If 'resyncFl' is not set then the client must call cmDListIndexUpdateAll() + // to resynchronize the indexes and iterators after the deletion. + // Note that if multiple records are to be deleted without intervening accesses + // to the list then it is more efficient to defer update the indexes until + // all the deletions are completed. + cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd, bool resyncFl ); + + // Allocate a new index. 'indexId' is used to identify this index and must be unique among all + // previously allocated indexes. + cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t cmpFunc, void* funcArg ); + cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId ); + + // Refresh all the indexes. This function should be called after new records are inserted + // via cmDListInsert(..,false). + cmDlRC_t cmDListIndexUpdateAll( cmDListH_t h ); + + // Set a function to be called when indexes are released. cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFreeFunc_t func ); - + // Allocate an interator. By default the new iterator is pointing to the first record + // in the index identified by 'indexId'. cmDlRC_t cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId ); cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp ); bool cmDListIterIsValid( cmDListIterH_t iH ); + + // Set the current iteration location to the begin/end of the index it is attached to. cmDlRC_t cmDListIterSeekBegin( cmDListIterH_t iH ); cmDlRC_t cmDListIterSeekEnd( cmDListIterH_t iH ); + + // Return the current record this iterator is pointing to. const void* cmDListIterGet( cmDListIterH_t iH, unsigned* recdByteNRef ); + + // Return the current record this iterator is pointint to and advance the iterator. const void* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef ); const void* cmDListIterNext( cmDListIterH_t iH, unsigned* recdByteNRef ); + + // Make the record which matches 'key' the current iterator. + // The match is made by using the compare function which is assigned to the index + // which this iterator is attached to. const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef); diff --git a/cmDListTpl.h b/cmDListTpl.h index a87ad93..50f089f 100644 --- a/cmDListTpl.h +++ b/cmDListTpl.h @@ -12,8 +12,8 @@ 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(cmDListInsert)( cmDListH_t h, const cmTYPE* recd, bool resyncFl ); +cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd, bool resyncFl ); cmDlRC_t cmSFX(cmDListAllocIndex)( cmDListH_t h, unsigned indexId, cmSFX(cmDListFunc) f, void* farg ); @@ -43,7 +43,7 @@ void cmSFX(_cmDListIndexOnFree)( unsigned indexId, void* 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); + assert(vn0==vn1); cmSFX(_cmDListArg)* a = (cmSFX(_cmDListArg)*)arg; return a->func(a->funcArg,(const cmTYPE*)v0,(const cmTYPE*)v1); } @@ -96,11 +96,11 @@ cmDlRC_t cmSFX(cmDListIndexAlloc)( cmDListH_t h, unsigned indexId, cmSFX(cmDLi return rc; } -cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd ) -{ return cmDListInsert(h,recd,sizeof(recd)); } +cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd, bool resyncFl ) +{ return cmDListInsert(h,recd,sizeof(cmTYPE),resyncFl); } -cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd ) -{ return cmDListDelete(h,recd); } +cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd, bool resyncFl ) +{ return cmDListDelete(h,recd,resyncFl); } const cmTYPE* cmSFX(cmDListIterGet)( cmDListIterH_t iH )