171 lines
4.7 KiB
C
171 lines
4.7 KiB
C
|
#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
|
||
|
|
||
|
// BUGBUG 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
|
||
|
|
||
|
BOOL WINAPI FDSA_Initialize(int cbItem, int cItemGrow,
|
||
|
PFDSA pfdsa, void * aItemStatic, int cItemStatic)
|
||
|
{
|
||
|
ASSERT(pfdsa != NULL); // BUGBUG 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--;
|
||
|
|
||
|
#if 0
|
||
|
// BUGBUG: this doesn't work yet for FDsA
|
||
|
if (pdsa->cItemAlloc - pdsa->cItem > pdsa->cItemGrow)
|
||
|
{
|
||
|
void FAR* aItemNew = ReAlloc(pdsa->aItem,
|
||
|
(pdsa->cItemAlloc - pdsa->cItemGrow) * pdsa->cbItem);
|
||
|
|
||
|
ASSERT(aItemNew);
|
||
|
pdsa->aItem = aItemNew;
|
||
|
pdsa->cItemAlloc -= pdsa->cItemGrow;
|
||
|
}
|
||
|
#endif
|
||
|
return TRUE;
|
||
|
}
|
||
|
|