windows-nt/Source/XPSP1/NT/public/internal/windows/inc/duser/duibtreelookup.h

353 lines
8.9 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* BTreeLookup
*/
/*
* Stores data and associated key and uses a binary search for quick lookup
* Used if gets are much more frequent than gets
*
* Keys are compared as pointers. If fKeyIsWStr is true, Keys are dereferenced
* as WCHAR* and compared
*/
#ifndef DUI_BASE_BTREELOOKUP_H_INCLUDED
#define DUI_BASE_BTREELOOKUP_H_INCLUDED
#pragma once
namespace DirectUI
{
template <typename D> class BTreeLookup
{
typedef struct
{
void* pKey;
D tData;
} ENTRY, *PENTRY;
typedef void (*PBTENUMCALLBACK)(void* pKey, D tData);
public:
static HRESULT Create(bool fKeyIsWStr, OUT BTreeLookup<D>** ppBTree);
virtual ~BTreeLookup();
void Destroy() { HDelete< BTreeLookup<D> >(this); }
D* GetItem(void* pKey); // Pointer to Value (NULL if doesn't exist, internal copy returned)
HRESULT SetItem(void* pKey, D* ptData); // Setup Key/Value map, creates new is doesn't exist (via indirection)
HRESULT SetItem(void* pKey, D tData); // Setup Key/Value map, creates new is doesn't exist
void Remove(void* pKey); // Removes Key/Value map, ok if Key doesn't exist
void Enum(PBTENUMCALLBACK pfnCallback); // Callback with every item in map
static int __cdecl ENTRYCompare(const void* pA, const void* pB);
static int __cdecl WStrENTRYCompare(const void* pA, const void* pB);
BTreeLookup() { }
void Initialize(bool fKeyIsWStr);
private:
UINT _uListSize;
PENTRY _pList;
bool _fKeyIsWStr;
};
template <typename D> HRESULT BTreeLookup<D>::Create(bool fKeyIsWStr, OUT BTreeLookup<D>** ppBTree)
{
*ppBTree = NULL;
// Instantiate
BTreeLookup<D>* pbt = HNew< BTreeLookup<D> >();
if (!pbt)
return E_OUTOFMEMORY;
pbt->Initialize(fKeyIsWStr);
*ppBTree = pbt;
return S_OK;
}
template <typename D> void BTreeLookup<D>::Initialize(bool fKeyIsWStr)
{
_uListSize = 0;
_pList = NULL;
_fKeyIsWStr = fKeyIsWStr;
}
template <typename D> BTreeLookup<D>::~BTreeLookup()
{
if (_pList)
HFree(_pList);
}
template <typename D> D* BTreeLookup<D>::GetItem(void* pKey)
{
DUIAssert(_fKeyIsWStr ? pKey != NULL : true, "pKey may not be NULL");
//PENTRY pEntry = NULL;
if (_pList)
{
//ENTRY eKey = { pKey }; // Create ENTRY key, populate key field
//pEntry = (PENTRY)bsearch(&eKey, _pList, _uListSize, sizeof(ENTRY), ENTRYCompare);
PENTRY pEntry;
int uPv;
int uLo = 0;
int uHi = _uListSize - 1;
while (uLo <= uHi)
{
uPv = (uHi + uLo) / 2;
pEntry = _pList + uPv;
// Locate
if (!_fKeyIsWStr)
{
// Key is numeric
if ((UINT_PTR)pKey == (UINT_PTR)pEntry->pKey)
return &(pEntry->tData);
if ((UINT_PTR)pKey < (UINT_PTR)pEntry->pKey)
uHi = uPv - 1;
else
uLo = uPv + 1;
}
else
{
// Key is pointer to a wide string
int cmp = _wcsicmp((LPCWSTR)pKey, (LPCWSTR)pEntry->pKey);
if (!cmp)
return &(pEntry->tData);
if (cmp < 0)
uHi = uPv - 1;
else
uLo = uPv + 1;
}
}
}
//return pEntry ? &(pEntry->tData) : NULL;
return NULL;
}
template <typename D> HRESULT BTreeLookup<D>::SetItem(void* pKey, D tData)
{
D* pData = GetItem(pKey); // Find current entry (if exits)
if (pData)
{
// Entry found and have pointer to data of entry
*pData = tData;
}
else
{
// Entry not found, allocate room for new entry, store, and sort
// New size
UINT uNewSize = _uListSize + 1;
if (_pList)
{
DUIAssert(uNewSize > 1, "Tracked list size and actual size differ");
PENTRY pNewList = (PENTRY)HReAlloc(_pList, sizeof(ENTRY) * uNewSize);
if (!pNewList)
return E_OUTOFMEMORY;
_pList = pNewList;
}
else
{
DUIAssert(uNewSize == 1, "Tracked list size and actual list size differ");
_pList = (PENTRY)HAlloc(sizeof(ENTRY));
if (!_pList)
return E_OUTOFMEMORY;
}
// Update size
_uListSize = uNewSize;
// Store
_pList[_uListSize - 1].pKey = pKey;
_pList[_uListSize - 1].tData = tData;
// Sort
qsort(_pList, _uListSize, sizeof(ENTRY), !_fKeyIsWStr ? ENTRYCompare : WStrENTRYCompare);
}
return S_OK;
}
template <typename D> HRESULT BTreeLookup<D>::SetItem(void* pKey, D* ptData)
{
D* pData = GetItem(pKey); // Find current entry (if exits)
if (pData)
{
// Entry found and have pointer to data of entry
*pData = *ptData;
}
else
{
// Entry not found, allocate room for new entry, store, and sort
// New size
UINT uNewSize = _uListSize + 1;
if (_pList)
{
DUIAssert(uNewSize > 1, "Tracked list size and actual list size differ");
PENTRY pNewList = (PENTRY)HReAlloc(_pList, sizeof(ENTRY) * uNewSize);
if (!pNewList)
return E_OUTOFMEMORY;
_pList = pNewList;
}
else
{
DUIAssert(uNewSize == 1, "Tracked list size and actual list size differ");
_pList = (PENTRY)HAlloc(sizeof(ENTRY));
if (!_pList)
return E_OUTOFMEMORY;
}
// Update size
_uListSize = uNewSize;
// Store
_pList[_uListSize - 1].pKey = pKey;
_pList[_uListSize - 1].tData = *ptData;
// Sort
qsort(_pList, _uListSize, sizeof(ENTRY), !_fKeyIsWStr ? ENTRYCompare : WStrENTRYCompare);
}
return S_OK;
}
// Returns success even if key isn't found
template <typename D> void BTreeLookup<D>::Remove(void* pKey)
{
// Validate parameters
DUIAssert(_fKeyIsWStr ? pKey != NULL : true, "Invalid parameter: pKey == NULL");
if (_pList)
{
// Search for ENTRY with key
//ENTRY eKey = { pKey };
//PENTRY pEntry = (PENTRY)bsearch(&eKey, _pList, _uListSize, sizeof(ENTRY), ENTRYCompare);
PENTRY pEntry = NULL;
int uPv;
int uLo = 0;
int uHi = _uListSize - 1;
while (uLo <= uHi)
{
uPv = (uHi + uLo) / 2;
pEntry = _pList + uPv;
// Locate
if (!_fKeyIsWStr)
{
// Key is numeric
if ((UINT_PTR)pKey == (UINT_PTR)pEntry->pKey)
break;
if ((UINT_PTR)pKey < (UINT_PTR)pEntry->pKey)
uHi = uPv - 1;
else
uLo = uPv + 1;
}
else
{
// Key is pointer to a wide string
int cmp = _wcsicmp((LPCWSTR)pKey, (LPCWSTR)pEntry->pKey);
if (!cmp)
break;
if (cmp < 0)
uHi = uPv - 1;
else
uLo = uPv + 1;
}
pEntry = NULL;
}
if (pEntry)
{
UINT uIndex = (UINT)(((UINT_PTR)pEntry - (UINT_PTR)_pList) / sizeof(ENTRY));
DUIAssert(uIndex < _uListSize, "Index out of bounds");
// ENTRY found, move all entries after this entry down
MoveMemory(pEntry, pEntry + 1, (_uListSize - uIndex - 1) * sizeof(ENTRY));
// One less entry
UINT uNewSize = _uListSize - 1;
// Trim allocation
if (uNewSize == 0)
{
HFree(_pList);
_pList = NULL;
}
else
{
PENTRY pNewList = (PENTRY)HReAlloc(_pList, uNewSize * sizeof(ENTRY));
// List is becoming smaller, if re-allocation failed, keep previous and continue
if (pNewList)
_pList = pNewList;
}
// Update size
_uListSize = uNewSize;
}
}
}
template <typename D> void BTreeLookup<D>::Enum(PBTENUMCALLBACK pfnCallback)
{
if (_pList)
{
for (UINT i = 0; i < _uListSize; i++)
pfnCallback(_pList[i].pKey, _pList[i].tData);
}
}
template <typename D> int __cdecl BTreeLookup<D>::ENTRYCompare(const void* pA, const void* pB)
{
PENTRY pEA = (PENTRY)pA;
PENTRY pEB = (PENTRY)pB;
if ((UINT_PTR)pEA->pKey == (UINT_PTR)pEB->pKey)
return 0;
else if ((UINT_PTR)pEA->pKey < (UINT_PTR)pEB->pKey)
return -1;
else
return 1;
}
template <typename D> int __cdecl BTreeLookup<D>::WStrENTRYCompare(const void* pA, const void* pB)
{
PENTRY pEA = (PENTRY)pA;
PENTRY pEB = (PENTRY)pB;
// Ignore case
return _wcsicmp((LPCWSTR)pEA->pKey, (LPCWSTR)pEB->pKey);
}
} // namespace DirectUI
#endif // DUI_BASE_BTREELOOKUP_H_INCLUDED