mirror of
https://bitbucket.org/cosmicvoids/vide_public.git
synced 2025-07-05 07:41:11 +00:00
Added missing libsw library
This commit is contained in:
parent
dd5e51c09c
commit
9dff8cfb5a
57 changed files with 13454 additions and 0 deletions
237
external/libsdf/libsw/dll.c
vendored
Normal file
237
external/libsdf/libsw/dll.c
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
/* DLL: doubly linked lists.
|
||||
|
||||
Support:
|
||||
insertion either before or after a given element (Above, Below).
|
||||
deletion.
|
||||
traversal in either direction. (Up, Down)
|
||||
|
||||
Use a vertical metaphor for mnemonics. You can grow the data
|
||||
structure up, down, or outward from the middle. It makes
|
||||
absolutely no difference.
|
||||
|
||||
The implementation uses two 'sentinels'. The one above the topmost
|
||||
element is called 'Sup' and the one below the lowest element is
|
||||
called 'Inf'. These are good places to start and end 'for' loops, e.g.,
|
||||
|
||||
for(p=DllTop(dll); p!=DllInf(dll); p = DllDown(dll, p))...
|
||||
|
||||
or
|
||||
|
||||
for(p=DllBottom(dll); p!=DllSup(dll); p = DllUp(dll, p))...
|
||||
|
||||
Space for 'user' data of size 'sz' is allocated with each element.
|
||||
This is ideal if you want to allocate associate a fixed size object
|
||||
with each list element. If you want more flexibility, there's
|
||||
nothing stopping you from making that fixed size object a void*
|
||||
that points to something else.
|
||||
|
||||
*/
|
||||
|
||||
#include "chn.h"
|
||||
#include "dll.h"
|
||||
#include "Malloc.h"
|
||||
|
||||
/* Initializing is a two step process because we have to do some
|
||||
funny stuff to get a chain allocating chunks just slightly bigger than
|
||||
what the user asks for. The resulting chain can be ChnTerminated
|
||||
at the caller's leisure. */
|
||||
void DllCreateChn(Chn *chn, int sz, int n){
|
||||
n+=2;
|
||||
if( sz > sizeof(int) )
|
||||
sz -= sizeof(int);
|
||||
ChnInit(chn, sizeof(Dll_elmt)+sz, n, Realloc_f);
|
||||
}
|
||||
|
||||
void DllCreate(Dll *dll, Chn *chn){
|
||||
dll->chn = chn;
|
||||
dll->Sup.down = &dll->Inf;
|
||||
dll->Sup.up = NULL;
|
||||
dll->Inf.down = NULL;
|
||||
dll->Inf.up = &dll->Sup;
|
||||
dll->length = 0;
|
||||
}
|
||||
|
||||
/* Terminate a dll */
|
||||
void DllTerminate(Dll *dll){
|
||||
/* Hmmm. There's really nothing to do since the user is now
|
||||
empowered to free the chain. We can't even do a FreeAll because
|
||||
there might be other stuff (other DLL's?) using the chain. */
|
||||
}
|
||||
|
||||
/* Insert closer to the Top */
|
||||
Dll_elmt *DllInsertAbove(Dll *dll, Dll_elmt *down){
|
||||
Dll_elmt *new = ChnAlloc(dll->chn);
|
||||
Dll_elmt *up = down->up;
|
||||
|
||||
if( new == NULL ){
|
||||
Shout("ChnAlloc returns null in DllInsertAbove\n");
|
||||
return NULL;
|
||||
}
|
||||
dll->length++;
|
||||
new->up = up;
|
||||
new->down = down;
|
||||
down->up = new;
|
||||
up->down = new;
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Insert closer to the bottom */
|
||||
Dll_elmt *DllInsertBelow(Dll *dll, Dll_elmt *up){
|
||||
Dll_elmt *new = ChnAlloc(dll->chn);
|
||||
Dll_elmt *down = up->down;
|
||||
|
||||
if( new == NULL ){
|
||||
Shout("ChnAlloc returns null in DllInsertBelow\n");
|
||||
return NULL;
|
||||
}
|
||||
dll->length++;
|
||||
new->up = up;
|
||||
new->down = down;
|
||||
down->up = new;
|
||||
up->down = new;
|
||||
return new;
|
||||
}
|
||||
|
||||
/* These two should be inlined, with __inline__ ... */
|
||||
/* Insert at the bottom */
|
||||
Dll_elmt *DllInsertAtBottom(Dll *dll){
|
||||
return DllInsertAbove(dll, &(dll->Inf));
|
||||
}
|
||||
|
||||
/* Insert at the top */
|
||||
Dll_elmt *DllInsertAtTop(Dll *dll){
|
||||
return DllInsertBelow(dll, &(dll->Sup));
|
||||
}
|
||||
|
||||
/* These three are VERY similar, but they are useful for traversals iin
|
||||
different directions. Otherwise the caller needs to save the 'up' or
|
||||
'down' element */
|
||||
/* Delete an entry. Return nothing. */
|
||||
void DllDelete(Dll *dll, Dll_elmt *old){
|
||||
Dll_elmt *up = old->up;
|
||||
Dll_elmt *down = old->down;
|
||||
|
||||
dll->length--;
|
||||
up->down = down;
|
||||
down->up = up;
|
||||
ChnFree(dll->chn, old);
|
||||
}
|
||||
|
||||
/* Delete an entry. Return the entry that used to be above it. */
|
||||
Dll_elmt *DllDeleteUp(Dll *dll, Dll_elmt *old){
|
||||
Dll_elmt *up = old->up;
|
||||
Dll_elmt *down = old->down;
|
||||
|
||||
dll->length--;
|
||||
up->down = down;
|
||||
down->up = up;
|
||||
ChnFree(dll->chn, old);
|
||||
return up;
|
||||
}
|
||||
|
||||
/* Delete an entry. Return the entry that used to be below it. */
|
||||
Dll_elmt *DllDeleteDown(Dll *dll, Dll_elmt *old){
|
||||
Dll_elmt *up = old->up;
|
||||
Dll_elmt *down = old->down;
|
||||
|
||||
dll->length--;
|
||||
up->down = down;
|
||||
down->up = up;
|
||||
ChnFree(dll->chn, old);
|
||||
return down;
|
||||
}
|
||||
|
||||
/* The next two have two plausible returns: the item directly above or
|
||||
below the original position of the mover. Rather than confuse
|
||||
things, I won't return either, and leave it up to the caller to keep
|
||||
track of whatever he wants. */
|
||||
|
||||
/* Extract the 'mover' and place it immediately below 'up'.
|
||||
Like DllDelete, followed by DllInsertBelow, but preserve the
|
||||
data in the object. */
|
||||
void DllMoveBelow(Dll *dll, Dll_elmt *mover, Dll_elmt *up){
|
||||
Dll_elmt *down;
|
||||
/* Extract the mover */
|
||||
mover->down->up = mover->up;
|
||||
mover->up->down = mover->down;
|
||||
/* Now insert it below up */
|
||||
down = up->down;
|
||||
mover->up = up;
|
||||
mover->down = down;
|
||||
down->up = mover;
|
||||
up->down = mover;
|
||||
}
|
||||
|
||||
/* Extract the 'mover' and place it immediately above 'down'.
|
||||
Like DllDelete, followed by DllInsertAbove, but preserve the
|
||||
data in the object. */
|
||||
void DllMoveAbove(Dll *dll, Dll_elmt *mover, Dll_elmt *down){
|
||||
Dll_elmt *up;
|
||||
/* Extract the mover */
|
||||
mover->down->up = mover->up;
|
||||
mover->up->down = mover->down;
|
||||
/* Now insert it above down */
|
||||
up = down->up;
|
||||
mover->up = up;
|
||||
mover->down = down;
|
||||
down->up = mover;
|
||||
up->down = mover;
|
||||
}
|
||||
|
||||
/* These should be inlined... */
|
||||
/* Move to bottom */
|
||||
void DllMoveToBottom(Dll *dll, Dll_elmt *mover){
|
||||
DllMoveAbove(dll, mover, &(dll->Inf));
|
||||
}
|
||||
|
||||
/* Move to top */
|
||||
void DllMoveToTop(Dll *dll, Dll_elmt *mover){
|
||||
DllMoveBelow(dll, mover, &(dll->Sup));
|
||||
}
|
||||
|
||||
/* These are generally 'inlined' with appropriate #defines in dll.h.
|
||||
They're simple enough to allow use of the pre-processor instead of
|
||||
__inline__. */
|
||||
#undef DllLength
|
||||
int DllLength(Dll *dll){
|
||||
return dll->length;
|
||||
}
|
||||
|
||||
#undef DllSup
|
||||
Dll_elmt *DllSup(Dll *dll){
|
||||
return &dll->Sup;
|
||||
}
|
||||
|
||||
#undef DllInf
|
||||
Dll_elmt *DllInf(Dll *dll){
|
||||
return &dll->Inf;
|
||||
}
|
||||
|
||||
/* The highest 'real' element */
|
||||
#undef DllTop
|
||||
Dll_elmt *DllTop(Dll *dll){
|
||||
return dll->Sup.down;
|
||||
}
|
||||
|
||||
/* The lowest 'real' element */
|
||||
#undef DllBottom
|
||||
Dll_elmt *DllBottom(Dll *dll){
|
||||
return dll->Inf.up;
|
||||
}
|
||||
|
||||
#undef DllData
|
||||
void *DllData(Dll_elmt *elmt){
|
||||
return &elmt->stuff;
|
||||
}
|
||||
|
||||
#undef DllUp
|
||||
Dll_elmt *DllUp(Dll_elmt *elmt){
|
||||
return elmt->up;
|
||||
}
|
||||
|
||||
#undef DllDown
|
||||
Dll_elmt *DllDown(Dll_elmt *elmt){
|
||||
return elmt->down;
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue