Windows2003-3790/sdktools/mep/browser/mbrmake/list.c

285 lines
6.9 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
// list.c
//
// a VM growable array package
#include "mbrmake.h"
typedef struct _list {
WORD cItems;
} SLIST;
typedef struct _biglist {
WORD cItems;
VA vaNext;
} BLIST;
typedef union _mixlist {
SLIST sml;
BLIST big;
} GLIST;
// this are the two VM lock numbers for the list package
//
#define LIST_LOCK 10
#define LIST_LOCK2 11
// Beware! For the system to work properly this number must
// be small enough that the VM free lists won't overflow
// i.e. C_ITEMS_MAX * sizeof(biggest_thing_stored) <= C_FREE_LIST_MAX
//
#define C_ITEMS_MAX 16
#pragma intrinsic(memcpy)
#define cBlock 1
VA
VaAddList(VA far *pvaList, LPV lpvData, WORD cbData, WORD grp)
// add the given item to the list; create if necessary
// return the virtual address of the most recently added item
//
{
VA vaListNew;
VA vaDirtyOnExit = vaNil;
WORD cbBlock, cItems, cAlloc;
GLIST far *lpList, *lpListNew;
#ifdef SWAP_INFO
iVMGrp = grp;
#endif
#if cBlock != 1
if (cBlock == 0) cBlock = C_ITEMS_MAX;
#endif
top: // for tail recursion...
// current list is empty -- create a new list with one thing in it
if (*pvaList == vaNil) {
if (cBlock == C_ITEMS_MAX) {
*pvaList = VaAllocGrpCb(grp, cbData*cBlock + sizeof(BLIST));
lpList = LpvFromVa(*pvaList, LIST_LOCK);
lpList->big.vaNext = vaNil;
lpList->big.cItems = 1;
memcpy(((LPCH)lpList) + sizeof(BLIST), lpvData, cbData);
if (vaDirtyOnExit) {
DirtyVa(vaDirtyOnExit);
UnlockW(LIST_LOCK+1);
}
DirtyVa(*pvaList);
UnlockW(LIST_LOCK);
return (PBYTE)*pvaList + sizeof(BLIST);
}
else {
*pvaList = VaAllocGrpCb(grp, cbData*cBlock + sizeof(SLIST));
lpList = LpvFromVa(*pvaList, LIST_LOCK);
lpList->sml.cItems = 1;
memcpy(((LPCH)lpList) + sizeof(SLIST), lpvData, cbData);
if (vaDirtyOnExit) {
DirtyVa(vaDirtyOnExit);
UnlockW(LIST_LOCK+1);
}
DirtyVa(*pvaList);
UnlockW(LIST_LOCK);
return (PBYTE)*pvaList + sizeof(SLIST);
}
}
lpList = LpvFromVa(*pvaList, LIST_LOCK);
cItems = lpList->sml.cItems;
// if current list has extension blocks, recursively add to the
// tail of this list
if (cItems >= C_ITEMS_MAX) {
vaDirtyOnExit = *pvaList;
lpList->big.cItems++;
DirtyVa(*pvaList);
LpvFromVa(*pvaList, LIST_LOCK+1); // lock in mem so address stays good
pvaList = &lpList->big.vaNext;
UnlockW(LIST_LOCK);
goto top;
}
cbBlock = cItems * cbData;
cAlloc = cItems % cBlock;
cAlloc = cItems - cAlloc + ( cAlloc ? cBlock : 0 );
// do we need to reallocate? If not do a fast insert
//
if (cItems < cAlloc) {
if (cAlloc >= C_ITEMS_MAX) {
memcpy(((LPCH)lpList) + cbBlock + sizeof(BLIST), lpvData, cbData);
lpList->big.cItems++;
DirtyVa(*pvaList);
UnlockW(LIST_LOCK);
return (PBYTE)*pvaList + cbBlock + sizeof(BLIST);
}
else {
memcpy(((LPCH)lpList) + cbBlock + sizeof(SLIST), lpvData, cbData);
lpList->sml.cItems++;
DirtyVa(*pvaList);
UnlockW(LIST_LOCK);
return (PBYTE)*pvaList + cbBlock + sizeof(SLIST);
}
}
// test if the next block will fit without turning the current list into
// a chained list... allocate a new block & copy the old data
if (cItems + cBlock < C_ITEMS_MAX) {
vaListNew = VaAllocGrpCb(grp, cbBlock + cbData*cBlock + sizeof(SLIST));
lpListNew = LpvFromVa(vaListNew, 0);
memcpy((LPCH)lpListNew, lpList, cbBlock + sizeof(SLIST));
memcpy((LPCH)lpListNew + cbBlock + sizeof(SLIST), lpvData, cbData);
lpListNew->sml.cItems++;
DirtyVa(vaListNew);
FreeGrpVa(grp, *pvaList, cbBlock + sizeof(SLIST));
*pvaList = vaListNew;
if (vaDirtyOnExit) {
DirtyVa(vaDirtyOnExit);
UnlockW(LIST_LOCK+1);
}
UnlockW(LIST_LOCK);
return (PBYTE)vaListNew + cbBlock + sizeof(SLIST);
}
// this is the last item that will go into this block,
// allocate a new block c/w link field & copy the old data
// set the link field to 0 for now
#if cBlock != 1
cBlock = C_ITEMS_MAX - cItems;
#endif
vaListNew = VaAllocGrpCb(grp, cbBlock + cbData*cBlock + sizeof(BLIST));
lpListNew = LpvFromVa(vaListNew, 0);
memcpy(lpListNew + 1 , ((SLIST FAR *)lpList) + 1, cbBlock);
memcpy(((LPCH)lpListNew) + cbBlock + sizeof(BLIST), lpvData, cbData);
lpListNew->big.cItems = lpList->sml.cItems + 1;
lpListNew->big.vaNext = vaNil;
DirtyVa(vaListNew);
FreeGrpVa(grp, *pvaList, cbBlock + sizeof(SLIST));
*pvaList = vaListNew;
if (vaDirtyOnExit) {
DirtyVa(vaDirtyOnExit);
UnlockW(LIST_LOCK+1);
}
UnlockW(LIST_LOCK);
return (PBYTE)vaListNew + cbBlock + sizeof(BLIST);
}
WORD
CItemsList(VA vaList)
// return total number of items in array
//
{
if (vaList == vaNil)
return 0;
#ifdef SWAP_INFO
iVMGrp = grpList;
#endif
return ((SLIST FAR *)LpvFromVa(vaList, 0))->cItems;
}
// to use the following iterator say something like
//
// vaPropList = cSYM.vaPropList;
// while (cprop = CItemsIterate(&vaProps, &vaPropList, cBlock)) {
// gPROP(vaProps);
// for (;--cprop >= 0; cPROP++) {
// cPROP.etc = ;
//
// }
// }
//
//
// The ENM_LIST, ENM_END, ENM_BREAK macros "do the right thing" with
// these lists.
//
WORD
CItemsIterate(VA FAR *vaData, VA FAR *vaNext)
// give number of elements in current block and pointer to next block
//
{
GLIST FAR *lpgList;
WORD cItems, cAlloc;
if (*vaNext == vaNil)
return 0;
#ifdef SWAP_INFO
iVMGrp = grpList;
#endif
#if cBlock != 1
if (cBlock == 0) cBlock = C_ITEMS_MAX;
#endif
lpgList = LpvFromVa(*vaNext, 0);
cItems = lpgList->sml.cItems;
if (cItems >= C_ITEMS_MAX) {
*vaData = (PBYTE)*vaNext + sizeof(BLIST);
*vaNext = lpgList->big.vaNext;
return C_ITEMS_MAX;
}
if (cBlock == 0)
cAlloc = C_ITEMS_MAX;
else {
cAlloc = cItems % cBlock;
cAlloc = cItems - cAlloc + ( cAlloc ? cBlock : 0 );
}
if (cAlloc >= C_ITEMS_MAX)
*vaData = (PBYTE)*vaNext + sizeof(BLIST);
else
*vaData = (PBYTE)*vaNext + sizeof(SLIST);
*vaNext = 0;
return cItems;
}
VOID
FreeList(VA vaList, WORD cbData)
// free up all the memory associated with this list
//
{
(PBYTE)vaList + cbData;
printf("FreeList is currently not working\n");
#if 0
GLIST FAR * lpgList;
VA vaNextList;
if (vaList == vaNil)
return;
top: // tail recursion
lpgList = LpvFromVa(vaList, 0);
if (lpgList->sml.cItems >= C_ITEMS_MAX) {
vaNextList = lpgList->big.vaNext;
FreeVa(vaList, C_ITEMS_MAX * cbData + sizeof(BLIST));
vaList = vaNextList;
goto top; // tail recursion
}
FreeVa(vaList, lpgList->sml.cItems * cbData + sizeof(SLIST));
return;
#endif
}