|
|
#include "priv.h"
//*** FDSA -- small/fast DSA routines
// DESCRIPTION
// We attempt to behave as much like an array as possible (semantics
// and performance and to some extent allocation). In particular,
// - indexing (FDSA_GetItemXxx) is done entirely inline; and...
// - ... involves only 1 extra indirection vs. a true array; and...
// - ... knows the data type so sizeof is a constant; and...
// - ... does no range checks (except possibly in DEBUG versions).
// - part of the FDSA is statically alloc'ed, so one can put critical
// items in the static part to ensure that they'll be there even under
// low memory conditions.
// NOTES
// For now we only implement:
// Initialize, Destroy, GetItemPtr, GetItemCount, InsertItem, AppendItem
// FEATURE eventually these come from comctl...
#define DABreak() /*NOTHING*/
// ReAlloc and Free come from inc/heapaloc.h
//*** SDSA_PITEM -- get item the hard way
//
#define SDSA_PITEM(pfdsa, i) \
((void *)(((BYTE *)(pfdsa)->aItem) + ((i) * (pfdsa)->cbItem)))
//*** FDSA_Initialize -- initialize
//
// SECURITY: caller is responsible for aItemStatic having at least (cItemStatice * cbItem) bytes
BOOL WINAPI FDSA_Initialize(int cbItem, int cItemGrow, PFDSA pfdsa, void * aItemStatic, int cItemStatic) { ASSERT(pfdsa != NULL); // WARNING how handle?
if (cItemGrow == 0) cItemGrow = 1;
// for implementation simplicity, cItemStatic must be a multiple of
// cItemGrow. o.w. our 1st grow from static->dynamic is messy and
// probably buggy.
if (cItemStatic % cItemGrow != 0) { AssertMsg(0, TEXT("CItemStatic must be a multiple of cItemGrow")); return FALSE; }
if (aItemStatic != NULL) { // since we're (eventually) in comctl, we can't assume caller's
// buffer was 0'ed
ZeroMemory(aItemStatic, cItemStatic * cbItem); }
if (pfdsa) { pfdsa->cItem = 0; pfdsa->cItemAlloc = cItemStatic; pfdsa->aItem = aItemStatic; pfdsa->fAllocated = FALSE;
pfdsa->cbItem = cbItem; ASSERT(pfdsa->cbItem == cbItem); // bitfield overflow
pfdsa->cItemGrow = cItemGrow; ASSERT(pfdsa->cItemGrow == cItemGrow); // bitfield overflow
}
return TRUE; }
BOOL WINAPI FDSA_Destroy(PFDSA pdsa) { if (pdsa == NULL) // allow NULL for low memory cases
return TRUE;
if (pdsa->fAllocated && pdsa->aItem && !LocalFree(pdsa->aItem)) return FALSE;
return TRUE; }
void* _LocalReAlloc(void* p, UINT uBytes) { if (uBytes) { if (p) { return LocalReAlloc(p, uBytes, LMEM_MOVEABLE | LMEM_ZEROINIT); } else { return LocalAlloc(LPTR, uBytes); } } else { if (p) LocalFree(p); return NULL; } }
//*** FDSA_InsertItem -- insert an item
// ENTRY/EXIT
// index insertion point; index > count (e.g. DA_LAST) means append
// NOTES
// param called 'pdsa' (vs. pfdsa) for easy diff'ing w/ DSA_InsertItem
int WINAPI FDSA_InsertItem(PFDSA pdsa, int index, void FAR* pitem) { ASSERT(pitem);
if (index < 0) { TraceMsg(DM_ERROR, "FDSA: InsertItem: Invalid index: %d", index); DABreak(); return -1; }
if (index > pdsa->cItem) index = pdsa->cItem;
if (pdsa->cItem + 1 > pdsa->cItemAlloc) { void FAR* aItemNew = _LocalReAlloc(pdsa->fAllocated ? pdsa->aItem : NULL, (pdsa->cItemAlloc + pdsa->cItemGrow) * pdsa->cbItem); if (!aItemNew) return -1;
if (!pdsa->fAllocated) { // when we go from static->dynamic, we need to copy
pdsa->fAllocated = TRUE; hmemcpy(aItemNew, pdsa->aItem, pdsa->cItem * pdsa->cbItem); }
pdsa->aItem = aItemNew; pdsa->cItemAlloc += pdsa->cItemGrow; }
if (index < pdsa->cItem) { hmemcpy(SDSA_PITEM(pdsa, index + 1), SDSA_PITEM(pdsa, index), (pdsa->cItem - index) * pdsa->cbItem); } pdsa->cItem++; hmemcpy(SDSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
return index; }
BOOL WINAPI FDSA_DeleteItem(PFDSA pdsa, int index) { ASSERT(pdsa);
if (index < 0 || index >= pdsa->cItem) { TraceMsg(TF_ERROR, "FDSA: DeleteItem: Invalid index: %d", index); DABreak(); return FALSE; }
if (index < pdsa->cItem - 1) { hmemcpy(SDSA_PITEM(pdsa, index), SDSA_PITEM(pdsa, index + 1), (pdsa->cItem - (index + 1)) * pdsa->cbItem); } pdsa->cItem--;
return TRUE; }
|