cmDList.h/c/Tpl.h : Changes to support initial debugging of cmDList.

This commit is contained in:
Kevin Larke 2015-08-03 08:28:22 -07:00
parent ac3f7cb3a1
commit 9bf87e175b
3 changed files with 234 additions and 129 deletions

290
cmDList.c
View File

@ -39,10 +39,10 @@ struct cmDList_str;
typedef struct cmDListIter_str typedef struct cmDListIter_str
{ {
struct cmDList_str* p; struct cmDList_str* p; // pointer to the owner cmDList
cmDListIndex_t* x; cmDListIndex_t* x; // pointer to the index this iterator traverses
cmDListIndexRecd_t* s; cmDListIndexRecd_t* s; // current record
struct cmDListIter_str* link; struct cmDListIter_str* link; // p->iters list link
} cmDListIter_t; } cmDListIter_t;
typedef struct cmDList_str typedef struct cmDList_str
@ -66,6 +66,7 @@ cmDList_t* _cmDListHandleToPtr( cmDListH_t h )
return p; return p;
} }
// Given an indexId return the associated index.
cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId ) cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId )
{ {
cmDListIndex_t* x = p->indexes; cmDListIndex_t* x = p->indexes;
@ -76,12 +77,14 @@ cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId )
return NULL; return NULL;
} }
// Allocate 'n' new index records for the index 'x'.
void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n ) void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n )
{ {
unsigned i; unsigned i;
for(i=0; i<n; ++i) for(i=0; i<n; ++i)
{ {
cmDListIndexRecd_t* s = cmMemAllocZ(cmDListIndexRecd_t,1); cmDListIndexRecd_t* s = cmMemAllocZ(cmDListIndexRecd_t,1);
s->prev = x->last; s->prev = x->last;
if( x->last != NULL ) 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 ) void _cmDListRecdFree( cmDList_t* p, cmDListRecd_t* r )
{ {
if( r->prev != NULL ) if( r->prev != NULL )
@ -274,7 +201,7 @@ cmDlRC_t _cmDListIterFree( cmDListIter_t* e )
else else
e0->link = e1->link; e0->link = e1->link;
cmMemFree(e0); cmMemFree(e1);
break; break;
} }
@ -307,6 +234,99 @@ cmDlRC_t _cmDListFree( cmDList_t* p )
return rc; 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 ) cmDlRC_t _cmDListIndexAlloc( cmDList_t* p, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
{ {
cmDListIndex_t* x; cmDListIndex_t* x;
@ -373,7 +393,8 @@ cmDlRC_t cmDListFree( cmDListH_t* hp )
bool cmDListIsValid( cmDListH_t h ) bool cmDListIsValid( cmDListH_t h )
{ return h.h != NULL; } { 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); cmDList_t* p = _cmDListHandleToPtr(h);
char* vp = cmMemAllocZ(char,sizeof(cmDListRecd_t) + recdByteN ); 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; r->dN = recdByteN;
memcpy( r->dV, recd, 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 the list is not empty
if( p->last != NULL ) if( p->last != NULL )
@ -400,51 +421,88 @@ cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN )
p->last = r; p->last = r;
p->recdN += 1; p->recdN += 1;
// update the indexes // add a record to each index
cmDListIndex_t* x = p->indexes; cmDListIndex_t* x = p->indexes;
for(; x!=NULL; x=x->link) for(; x!=NULL; x=x->link)
{ {
_cmDListIndexAllocRecds(x,1); if( x->recdN < p->recdN )
_cmDListIndexUpdate(p,x); _cmDListIndexAllocRecds(x,1);
assert( x->recdN >= p->recdN );
if( resyncFl )
_cmDListIndexUpdate(p,x);
} }
return kOkDlRC; 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); cmDList_t* p = _cmDListHandleToPtr(h);
cmDListIndex_t* x = p->indexes; cmDListIndex_t* x = p->indexes;
cmDListIndexRecd_t* s = NULL; cmDListIndexRecd_t* s = NULL;
cmDListRecd_t* r = NULL; cmDListRecd_t* r = NULL;
for(; x!=NULL; x=x->link) if( resyncFl==false )
{ {
for(s=x->first; s!=NULL; s=s->next) r = p->first;
if( s->r->dV == recd ) for(; r!=NULL; r=r->next)
if( r->dV == recd )
{ {
if( r == NULL ) _cmDListRecdFree(p,r);
r = s->r;
else
{
// the same data record should be found for all indexes
assert( s->r == r );
}
_cmDListIndexRecdFree(x,s);
break; 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;
}
// 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);
// if the indexes are valid then the recd should always be found
assert( s!=NULL );
} }
// release the data record errLabel:
_cmDListRecdFree(p,r); 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; return kOkDlRC;
@ -479,6 +537,18 @@ cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFre
return kOkDlRC; 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 ) cmDListIter_t* _cmDListIterHandleToPtr( cmDListIterH_t h )
{ {
@ -557,6 +627,8 @@ const void* _cmDListIterGet( cmDListIter_t* e, unsigned* recdByteNRef )
return NULL; return NULL;
} }
assert( e->s->r != NULL );
if( recdByteNRef != NULL ) if( recdByteNRef != NULL )
*recdByteNRef = e->s->r->dN; *recdByteNRef = e->s->r->dN;

View File

@ -30,27 +30,60 @@ extern "C" {
typedef void (*cmDListIndexFreeFunc_t)( unsigned indexId, void* arg ); 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. // 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 f, void* farg ); cmDlRC_t cmDListAlloc( cmCtx_t* ctx, cmDListH_t* hp, cmDListCmpFunc_t cmpFunc, void* funcArg );
cmDlRC_t cmDListFree( cmDListH_t* hp ); cmDlRC_t cmDListFree( cmDListH_t* hp );
bool cmDListIsValid( cmDListH_t h ); 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 );
// 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 );
cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t f, void* farg ); // Delete a data record.
cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId ); // '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 ); 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 cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId );
cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp ); cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp );
bool cmDListIterIsValid( cmDListIterH_t iH ); 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 cmDListIterSeekBegin( cmDListIterH_t iH );
cmDlRC_t cmDListIterSeekEnd( 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 ); 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* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef );
const void* cmDListIterNext( 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); const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef);

View File

@ -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(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(cmDListInsert)( cmDListH_t h, const cmTYPE* recd, bool resyncFl );
cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd ); 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 ); 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. // 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 ) 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; cmSFX(_cmDListArg)* a = (cmSFX(_cmDListArg)*)arg;
return a->func(a->funcArg,(const cmTYPE*)v0,(const cmTYPE*)v1); 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; return rc;
} }
cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd ) cmDlRC_t cmSFX(cmDListInsert)( cmDListH_t h, const cmTYPE* recd, bool resyncFl )
{ return cmDListInsert(h,recd,sizeof(recd)); } { return cmDListInsert(h,recd,sizeof(cmTYPE),resyncFl); }
cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd ) cmDlRC_t cmSFX(cmDListDelete)( cmDListH_t h, const cmTYPE* recd, bool resyncFl )
{ return cmDListDelete(h,recd); } { return cmDListDelete(h,recd,resyncFl); }
const cmTYPE* cmSFX(cmDListIterGet)( cmDListIterH_t iH ) const cmTYPE* cmSFX(cmDListIterGet)( cmDListIterH_t iH )