Mercurial > games > semicongine
diff fuhtark_test/include/winapi/dxtmpl.h @ 1500:91c8c3b7cbf0
add: futhark tests for generating vulkan api
| author | sam <sam@basx.dev> |
|---|---|
| date | Wed, 26 Nov 2025 21:36:48 +0700 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fuhtark_test/include/winapi/dxtmpl.h Wed Nov 26 21:36:48 2025 +0700 @@ -0,0 +1,882 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ +#ifndef DXTmpl_h +#define DXTmpl_h + +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <search.h> + +#define DXASSERT_VALID(pObj) + +#ifndef PASCAL_INLINE +#define PASCAL_INLINE WINAPI +#endif + +typedef void *DXLISTPOS; +typedef DWORD DXLISTHANDLE; + +#define DX_BEFORE_START_POSITION ((void*)-1L) + +#ifndef __CRT__NO_INLINE +__CRT_INLINE WINBOOL DXIsValidAddress(const void *lp,UINT nBytes,WINBOOL bReadWrite) { return (lp!=NULL && !IsBadReadPtr(lp,nBytes) && (!bReadWrite || !IsBadWritePtr((LPVOID)lp,nBytes))); } +#endif + +#ifdef __cplusplus + +template<class TYPE> +inline void DXConstructElements(TYPE *pElements,int nCount) { + _ASSERT(nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE)); + memset((void*)pElements,0,nCount *sizeof(TYPE)); +} + +template<class TYPE> +inline void DXDestructElements(TYPE *pElements,int nCount) { + _ASSERT((nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE))); + pElements; + nCount; +} + +template<class TYPE> +inline void DXCopyElements(TYPE *pDest,const TYPE *pSrc,int nCount) { + _ASSERT((nCount==0 || DXIsValidAddress(pDest,nCount *sizeof(TYPE),TRUE))); + _ASSERT((nCount==0 || DXIsValidAddress(pSrc,nCount *sizeof(TYPE),FALSE))); + memcpy(pDest,pSrc,nCount *sizeof(TYPE)); +} + +template<class TYPE,class ARG_TYPE> +WINBOOL DXCompareElements(const TYPE *pElement1,const ARG_TYPE *pElement2) { + _ASSERT(DXIsValidAddress(pElement1,sizeof(TYPE),FALSE)); + _ASSERT(DXIsValidAddress(pElement2,sizeof(ARG_TYPE),FALSE)); + return *pElement1==*pElement2; +} + +template<class ARG_KEY> +inline UINT DXHashKey(ARG_KEY key) { return ((UINT)(void*)(DWORD)key) >> 4; } + +struct CDXPlex { + CDXPlex *pNext; + UINT nMax; + UINT nCur; + void *data() { return this+1; } + static CDXPlex *PASCAL_INLINE Create(CDXPlex *&pHead,UINT nMax,UINT cbElement) { + CDXPlex *p = (CDXPlex*) new BYTE[sizeof(CDXPlex) + nMax *cbElement]; + if(!p) return NULL; + p->nMax = nMax; + p->nCur = 0; + p->pNext = pHead; + pHead = p; + return p; + } + void FreeDataChain() { + CDXPlex *p = this; + while(p!=NULL) { + BYTE *bytes = (BYTE*) p; + CDXPlex *pNext = p->pNext; + delete [] bytes; + p = pNext; + } + } +}; + +template<class TYPE,class ARG_TYPE> +class CDXArray { +public: + CDXArray(); + int GetSize() const; + int GetUpperBound() const; + void SetSize(int nNewSize,int nGrowBy = -1); + void FreeExtra(); + void RemoveAll(); + TYPE GetAt(int nIndex) const; + void SetAt(int nIndex,ARG_TYPE newElement); + TYPE &ElementAt(int nIndex); + const TYPE *GetData() const; + TYPE *GetData(); + void SetAtGrow(int nIndex,ARG_TYPE newElement); + int Add(ARG_TYPE newElement); + int Append(const CDXArray &src); + void Copy(const CDXArray &src); + TYPE operator[](int nIndex) const; + TYPE &operator[](int nIndex); + void InsertAt(int nIndex,ARG_TYPE newElement,int nCount = 1); + void RemoveAt(int nIndex,int nCount = 1); + void InsertAt(int nStartIndex,CDXArray *pNewArray); + void Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)); +protected: + TYPE *m_pData; + int m_nSize; + int m_nMaxSize; + int m_nGrowBy; +public: + ~CDXArray(); +}; + +template<class TYPE,class ARG_TYPE> +inline int CDXArray<TYPE,ARG_TYPE>::GetSize() const { return m_nSize; } +template<class TYPE,class ARG_TYPE> +inline int CDXArray<TYPE,ARG_TYPE>::GetUpperBound() const { return m_nSize-1; } +template<class TYPE,class ARG_TYPE> +inline void CDXArray<TYPE,ARG_TYPE>::RemoveAll() { SetSize(0,-1); } +template<class TYPE,class ARG_TYPE> +inline TYPE CDXArray<TYPE,ARG_TYPE>::GetAt(int nIndex) const { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } +template<class TYPE,class ARG_TYPE> +inline void CDXArray<TYPE,ARG_TYPE>::SetAt(int nIndex,ARG_TYPE newElement) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); m_pData[nIndex] = newElement; } +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXArray<TYPE,ARG_TYPE>::ElementAt(int nIndex) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } +template<class TYPE,class ARG_TYPE> +inline const TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() const { return (const TYPE*)m_pData; } +template<class TYPE,class ARG_TYPE> +inline TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() { return (TYPE*)m_pData; } +template<class TYPE,class ARG_TYPE> +inline int CDXArray<TYPE,ARG_TYPE>::Add(ARG_TYPE newElement) { + int nIndex = m_nSize; + SetAtGrow(nIndex,newElement); + return nIndex; +} +template<class TYPE,class ARG_TYPE> +inline TYPE CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) const { return GetAt(nIndex); } +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) { return ElementAt(nIndex); } +template<class TYPE,class ARG_TYPE> +CDXArray<TYPE,ARG_TYPE>::CDXArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; } +emplate<class TYPE,class ARG_TYPE> +CDXArray<TYPE,ARG_TYPE>::~CDXArray() { + DXASSERT_VALID(this); + if(m_pData!=NULL) { + DXDestructElements(m_pData,m_nSize); + delete[] (BYTE*)m_pData; + } +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::SetSize(int nNewSize,int nGrowBy) { + DXASSERT_VALID(this); + _ASSERT(nNewSize >= 0); + if(nGrowBy!=-1) m_nGrowBy = nGrowBy; + if(nNewSize==0) { + if(m_pData!=NULL) { + DXDestructElements(m_pData,m_nSize); + delete[] (BYTE*)m_pData; + m_pData = NULL; + } + m_nSize = m_nMaxSize = 0; + } else if(!m_pData) { +#ifdef SIZE_T_MAX + _ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE)); +#endif + m_pData = (TYPE*) new BYTE[nNewSize *sizeof(TYPE)]; + DXConstructElements(m_pData,nNewSize); + m_nSize = m_nMaxSize = nNewSize; + } else if(nNewSize <= m_nMaxSize) { + if(nNewSize > m_nSize) { + DXConstructElements(&m_pData[m_nSize],nNewSize-m_nSize); + } else if(m_nSize > nNewSize) { + DXDestructElements(&m_pData[nNewSize],m_nSize-nNewSize); + } + m_nSize = nNewSize; + } else { + int nGrowBy = m_nGrowBy; + if(!nGrowBy) nGrowBy = min(1024,max(4,m_nSize / 8)); + int nNewMax; + if(nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy; + else nNewMax = nNewSize; + _ASSERT(nNewMax >= m_nMaxSize); +#ifdef SIZE_T_MAX + _ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); +#endif + TYPE *pNewData = (TYPE*) new BYTE[nNewMax *sizeof(TYPE)]; + + if(!pNewData) return; + memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); + _ASSERT(nNewSize > m_nSize); + DXConstructElements(&pNewData[m_nSize],nNewSize-m_nSize); + delete[] (BYTE*)m_pData; + m_pData = pNewData; + m_nSize = nNewSize; + m_nMaxSize = nNewMax; + } +} + +template<class TYPE,class ARG_TYPE> +int CDXArray<TYPE,ARG_TYPE>::Append(const CDXArray &src) { + DXASSERT_VALID(this); + _ASSERT(this!=&src); + int nOldSize = m_nSize; + SetSize(m_nSize + src.m_nSize); + DXCopyElements(m_pData + nOldSize,src.m_pData,src.m_nSize); + return nOldSize; +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::Copy(const CDXArray &src) { + DXASSERT_VALID(this); + _ASSERT(this!=&src); + SetSize(src.m_nSize); + DXCopyElements(m_pData,src.m_pData,src.m_nSize); +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::FreeExtra() { + DXASSERT_VALID(this); + if(m_nSize!=m_nMaxSize) { +#ifdef SIZE_T_MAX + _ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); +#endif + TYPE *pNewData = NULL; + if(m_nSize!=0) { + pNewData = (TYPE*) new BYTE[m_nSize *sizeof(TYPE)]; + if(!pNewData) return; + memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); + } + delete[] (BYTE*)m_pData; + m_pData = pNewData; + m_nMaxSize = m_nSize; + } +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::SetAtGrow(int nIndex,ARG_TYPE newElement) { + DXASSERT_VALID(this); + _ASSERT(nIndex >= 0); + if(nIndex >= m_nSize) SetSize(nIndex+1,-1); + m_pData[nIndex] = newElement; +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nIndex,ARG_TYPE newElement,int nCount) { + DXASSERT_VALID(this); + _ASSERT(nIndex >= 0); + _ASSERT(nCount > 0); + if(nIndex >= m_nSize) SetSize(nIndex + nCount,-1); + else { + int nOldSize = m_nSize; + SetSize(m_nSize + nCount,-1); + memmove(&m_pData[nIndex+nCount],&m_pData[nIndex],(nOldSize-nIndex) *sizeof(TYPE)); + DXConstructElements(&m_pData[nIndex],nCount); + } + _ASSERT(nIndex + nCount <= m_nSize); + while(nCount--) + m_pData[nIndex++] = newElement; +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::RemoveAt(int nIndex,int nCount) { + DXASSERT_VALID(this); + _ASSERT(nIndex >= 0); + _ASSERT(nCount >= 0); + _ASSERT(nIndex + nCount <= m_nSize); + int nMoveCount = m_nSize - (nIndex + nCount); + DXDestructElements(&m_pData[nIndex],nCount); + if(nMoveCount) + memcpy(&m_pData[nIndex],&m_pData[nIndex + nCount],nMoveCount *sizeof(TYPE)); + m_nSize -= nCount; +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nStartIndex,CDXArray *pNewArray) { + DXASSERT_VALID(this); + DXASSERT_VALID(pNewArray); + _ASSERT(nStartIndex >= 0); + if(pNewArray->GetSize() > 0) { + InsertAt(nStartIndex,pNewArray->GetAt(0),pNewArray->GetSize()); + for(int i = 0;i < pNewArray->GetSize();i++) + SetAt(nStartIndex + i,pNewArray->GetAt(i)); + } +} + +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)) { + DXASSERT_VALID(this); + _ASSERT(m_pData!=NULL); + qsort(m_pData,m_nSize,sizeof(TYPE),compare); +} + +#ifdef _DEBUG +template<class TYPE,class ARG_TYPE> +void CDXArray<TYPE,ARG_TYPE>::AssertValid() const { + if(!m_pData) { + _ASSERT(m_nSize==0); + _ASSERT(m_nMaxSize==0); + } else { + _ASSERT(m_nSize >= 0); + _ASSERT(m_nMaxSize >= 0); + _ASSERT(m_nSize <= m_nMaxSize); + _ASSERT(DXIsValidAddress(m_pData,m_nMaxSize *sizeof(TYPE),TRUE)); + } +} +#endif + +template<class TYPE,class ARG_TYPE> +class CDXList { +protected: + struct CNode { + CNode *pNext; + CNode *pPrev; + TYPE data; + }; +public: + CDXList(int nBlockSize = 10); + int GetCount() const; + WINBOOL IsEmpty() const; + TYPE &GetHead(); + TYPE GetHead() const; + TYPE &GetTail(); + TYPE GetTail() const; + + TYPE RemoveHead(); + TYPE RemoveTail(); + DXLISTPOS AddHead(ARG_TYPE newElement); + DXLISTPOS AddTail(ARG_TYPE newElement); + void AddHead(CDXList *pNewList); + void AddTail(CDXList *pNewList); + void RemoveAll(); + DXLISTPOS GetHeadPosition() const; + DXLISTPOS GetTailPosition() const; + TYPE &GetNext(DXLISTPOS &rPosition); + TYPE GetNext(DXLISTPOS &rPosition) const; + TYPE &GetPrev(DXLISTPOS &rPosition); + TYPE GetPrev(DXLISTPOS &rPosition) const; + TYPE &GetAt(DXLISTPOS position); + TYPE GetAt(DXLISTPOS position) const; + void SetAt(DXLISTPOS pos,ARG_TYPE newElement); + void RemoveAt(DXLISTPOS position); + DXLISTPOS InsertBefore(DXLISTPOS position,ARG_TYPE newElement); + DXLISTPOS InsertAfter(DXLISTPOS position,ARG_TYPE newElement); + DXLISTPOS Find(ARG_TYPE searchValue,DXLISTPOS startAfter = NULL) const; + DXLISTPOS FindIndex(int nIndex) const; +protected: + CNode *m_pNodeHead; + CNode *m_pNodeTail; + int m_nCount; + CNode *m_pNodeFree; + struct CDXPlex *m_pBlocks; + int m_nBlockSize; + CNode *NewNode(CNode *,CNode *); + void FreeNode(CNode *); +public: + ~CDXList(); +#ifdef _DEBUG + void AssertValid() const; +#endif +}; + +template<class TYPE,class ARG_TYPE> +inline int CDXList<TYPE,ARG_TYPE>::GetCount() const { return m_nCount; } +template<class TYPE,class ARG_TYPE> +inline WINBOOL CDXList<TYPE,ARG_TYPE>::IsEmpty() const { return m_nCount==0; } +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXList<TYPE,ARG_TYPE>::GetHead() { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } +template<class TYPE,class ARG_TYPE> +inline TYPE CDXList<TYPE,ARG_TYPE>::GetHead() const { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXList<TYPE,ARG_TYPE>::GetTail() { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } +template<class TYPE,class ARG_TYPE> +inline TYPE CDXList<TYPE,ARG_TYPE>::GetTail() const { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } +template<class TYPE,class ARG_TYPE> +inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetHeadPosition() const { return (DXLISTPOS) m_pNodeHead; } +template<class TYPE,class ARG_TYPE> +inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetTailPosition() const { return (DXLISTPOS) m_pNodeTail; } +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) { + CNode *pNode = (CNode *) rPosition; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + rPosition = (DXLISTPOS) pNode->pNext; + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline TYPE CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) const { + CNode *pNode = (CNode *) rPosition; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + rPosition = (DXLISTPOS) pNode->pNext; + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) { + CNode *pNode = (CNode *) rPosition; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + rPosition = (DXLISTPOS) pNode->pPrev; + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline TYPE CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) const { + CNode *pNode = (CNode *) rPosition; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + rPosition = (DXLISTPOS) pNode->pPrev; + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline TYPE &CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) { + CNode *pNode = (CNode *) position; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline TYPE CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) const { + CNode *pNode = (CNode *) position; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + return pNode->data; +} +template<class TYPE,class ARG_TYPE> +inline void CDXList<TYPE,ARG_TYPE>::SetAt(DXLISTPOS pos,ARG_TYPE newElement) { + CNode *pNode = (CNode *) pos; + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + pNode->data = newElement; +} + +template<class TYPE,class ARG_TYPE> +CDXList<TYPE,ARG_TYPE>::CDXList(int nBlockSize) { + _ASSERT(nBlockSize > 0); + m_nCount = 0; + m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; + m_pBlocks = NULL; + m_nBlockSize = nBlockSize; +} + +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::RemoveAll() { + DXASSERT_VALID(this); + CNode *pNode; + for(pNode = m_pNodeHead;pNode!=NULL;pNode = pNode->pNext) + DXDestructElements(&pNode->data,1); + m_nCount = 0; + m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; +} + +template<class TYPE,class ARG_TYPE> +CDXList<TYPE,ARG_TYPE>::~CDXList() { + RemoveAll(); + _ASSERT(m_nCount==0); +} + +template<class TYPE,class ARG_TYPE> +typename CDXList<TYPE,ARG_TYPE>::CNode * +CDXList<TYPE,ARG_TYPE>::NewNode(CNode *pPrev,CNode *pNext) { + if(!m_pNodeFree) { + CDXPlex *pNewBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CNode)); + CNode *pNode = (CNode *) pNewBlock->data(); + pNode += m_nBlockSize - 1; + for(int i = m_nBlockSize-1;i >= 0;i--,pNode--) { + pNode->pNext = m_pNodeFree; + m_pNodeFree = pNode; + } + } + _ASSERT(m_pNodeFree!=NULL); + CDXList::CNode *pNode = m_pNodeFree; + m_pNodeFree = m_pNodeFree->pNext; + pNode->pPrev = pPrev; + pNode->pNext = pNext; + m_nCount++; + _ASSERT(m_nCount > 0); + DXConstructElements(&pNode->data,1); + return pNode; +} + +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::FreeNode(CNode *pNode) { + DXDestructElements(&pNode->data,1); + pNode->pNext = m_pNodeFree; + m_pNodeFree = pNode; + m_nCount--; + _ASSERT(m_nCount >= 0); +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddHead(ARG_TYPE newElement) { + DXASSERT_VALID(this); + CNode *pNewNode = NewNode(NULL,m_pNodeHead); + pNewNode->data = newElement; + if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = pNewNode; + else m_pNodeTail = pNewNode; + m_pNodeHead = pNewNode; + return (DXLISTPOS) pNewNode; +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddTail(ARG_TYPE newElement) { + DXASSERT_VALID(this); + CNode *pNewNode = NewNode(m_pNodeTail,NULL); + pNewNode->data = newElement; + if(m_pNodeTail!=NULL) m_pNodeTail->pNext = pNewNode; + else m_pNodeHead = pNewNode; + m_pNodeTail = pNewNode; + return (DXLISTPOS) pNewNode; +} + +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::AddHead(CDXList *pNewList) { + DXASSERT_VALID(this); + DXASSERT_VALID(pNewList); + DXLISTPOS pos = pNewList->GetTailPosition(); + while(pos!=NULL) + AddHead(pNewList->GetPrev(pos)); +} + +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::AddTail(CDXList *pNewList) { + DXASSERT_VALID(this); + DXASSERT_VALID(pNewList); + DXLISTPOS pos = pNewList->GetHeadPosition(); + while(pos!=NULL) + AddTail(pNewList->GetNext(pos)); +} + +template<class TYPE,class ARG_TYPE> +TYPE CDXList<TYPE,ARG_TYPE>::RemoveHead() { + DXASSERT_VALID(this); + _ASSERT(m_pNodeHead!=NULL); + _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); + CNode *pOldNode = m_pNodeHead; + TYPE returnValue = pOldNode->data; + m_pNodeHead = pOldNode->pNext; + if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = NULL; + else m_pNodeTail = NULL; + FreeNode(pOldNode); + return returnValue; +} + +template<class TYPE,class ARG_TYPE> +TYPE CDXList<TYPE,ARG_TYPE>::RemoveTail() { + DXASSERT_VALID(this); + _ASSERT(m_pNodeTail!=NULL); + _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); + CNode *pOldNode = m_pNodeTail; + TYPE returnValue = pOldNode->data; + m_pNodeTail = pOldNode->pPrev; + if(m_pNodeTail!=NULL) m_pNodeTail->pNext = NULL; + else m_pNodeHead = NULL; + FreeNode(pOldNode); + return returnValue; +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertBefore(DXLISTPOS position,ARG_TYPE newElement) { + DXASSERT_VALID(this); + if(!position) return AddHead(newElement); + CNode *pOldNode = (CNode *) position; + CNode *pNewNode = NewNode(pOldNode->pPrev,pOldNode); + pNewNode->data = newElement; + if(pOldNode->pPrev!=NULL) { + _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); + pOldNode->pPrev->pNext = pNewNode; + } else { + _ASSERT(pOldNode==m_pNodeHead); + m_pNodeHead = pNewNode; + } + pOldNode->pPrev = pNewNode; + return (DXLISTPOS) pNewNode; +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertAfter(DXLISTPOS position,ARG_TYPE newElement) { + DXASSERT_VALID(this); + if(!position) return AddTail(newElement); + CNode *pOldNode = (CNode *) position; + _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); + CNode *pNewNode = NewNode(pOldNode,pOldNode->pNext); + pNewNode->data = newElement; + if(pOldNode->pNext!=NULL) { + _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); + pOldNode->pNext->pPrev = pNewNode; + } else { + _ASSERT(pOldNode==m_pNodeTail); + m_pNodeTail = pNewNode; + } + pOldNode->pNext = pNewNode; + return (DXLISTPOS) pNewNode; +} + +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::RemoveAt(DXLISTPOS position) { + DXASSERT_VALID(this); + CNode *pOldNode = (CNode *) position; + _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); + if(pOldNode==m_pNodeHead) { + m_pNodeHead = pOldNode->pNext; + } else { + _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); + pOldNode->pPrev->pNext = pOldNode->pNext; + } + if(pOldNode==m_pNodeTail) m_pNodeTail = pOldNode->pPrev; + else { + _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); + pOldNode->pNext->pPrev = pOldNode->pPrev; + } + FreeNode(pOldNode); +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::FindIndex(int nIndex) const { + DXASSERT_VALID(this); + _ASSERT(nIndex >= 0); + if(nIndex >= m_nCount) return NULL; + CNode *pNode = m_pNodeHead; + while(nIndex--) { + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + pNode = pNode->pNext; + } + return (DXLISTPOS) pNode; +} + +template<class TYPE,class ARG_TYPE> +DXLISTPOS CDXList<TYPE,ARG_TYPE>::Find(ARG_TYPE searchValue,DXLISTPOS startAfter) const { + DXASSERT_VALID(this); + CNode *pNode = (CNode *) startAfter; + if(!pNode) pNode = m_pNodeHead; + else { + _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); + pNode = pNode->pNext; + } + for(;pNode!=NULL;pNode = pNode->pNext) + if(DXCompareElements(&pNode->data,&searchValue)) return (DXLISTPOS)pNode; + return NULL; +} + +#ifdef _DEBUG +template<class TYPE,class ARG_TYPE> +void CDXList<TYPE,ARG_TYPE>::AssertValid() const { + if(!m_nCount) { + _ASSERT(!m_pNodeHead); + _ASSERT(!m_pNodeTail); + } else { + _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); + _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); + } +} +#endif + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +class CDXMap { +protected: + struct CAssoc { + CAssoc *pNext; + UINT nHashValue; + KEY key; + VALUE value; + }; +public: + CDXMap(int nBlockSize = 10); + int GetCount() const; + WINBOOL IsEmpty() const; + WINBOOL Lookup(ARG_KEY key,VALUE& rValue) const; + VALUE& operator[](ARG_KEY key); + void SetAt(ARG_KEY key,ARG_VALUE newValue); + WINBOOL RemoveKey(ARG_KEY key); + void RemoveAll(); + DXLISTPOS GetStartPosition() const; + void GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const; + UINT GetHashTableSize() const; + void InitHashTable(UINT hashSize,WINBOOL bAllocNow = TRUE); +protected: + CAssoc **m_pHashTable; + UINT m_nHashTableSize; + int m_nCount; + CAssoc *m_pFreeList; + struct CDXPlex *m_pBlocks; + int m_nBlockSize; + CAssoc *NewAssoc(); + void FreeAssoc(CAssoc*); + CAssoc *GetAssocAt(ARG_KEY,UINT&) const; +public: + ~CDXMap(); +#ifdef _DEBUG + void AssertValid() const; +#endif +}; + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +inline int CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetCount() const { return m_nCount; } +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +inline WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::IsEmpty() const { return m_nCount==0; } +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +inline void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::SetAt(ARG_KEY key,ARG_VALUE newValue) { (*this)[key] = newValue; } +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +inline DXLISTPOS CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetStartPosition() const { return (m_nCount==0) ? NULL : DX_BEFORE_START_POSITION; } +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +inline UINT CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetHashTableSize() const { return m_nHashTableSize; } + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CDXMap(int nBlockSize) { + _ASSERT(nBlockSize > 0); + m_pHashTable = NULL; + m_nHashTableSize = 17; + m_nCount = 0; + m_pFreeList = NULL; + m_pBlocks = NULL; + m_nBlockSize = nBlockSize; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::InitHashTable(UINT nHashSize,WINBOOL bAllocNow) { + DXASSERT_VALID(this); + _ASSERT(m_nCount==0); + _ASSERT(nHashSize > 0); + if(m_pHashTable!=NULL) { + delete[] m_pHashTable; + m_pHashTable = NULL; + } + if(bAllocNow) { + m_pHashTable = new CAssoc *[nHashSize]; + if(!m_pHashTable) return; + memset(m_pHashTable,0,sizeof(CAssoc*) *nHashSize); + } + m_nHashTableSize = nHashSize; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveAll() { + DXASSERT_VALID(this); + if(m_pHashTable!=NULL) { + for(UINT nHash = 0;nHash < m_nHashTableSize;nHash++) { + CAssoc *pAssoc; + for(pAssoc = m_pHashTable[nHash]; pAssoc!=NULL; + pAssoc = pAssoc->pNext) + { + DXDestructElements(&pAssoc->value,1); + DXDestructElements(&pAssoc->key,1); + } + } + } + delete[] m_pHashTable; + m_pHashTable = NULL; + m_nCount = 0; + m_pFreeList = NULL; + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::~CDXMap() { + RemoveAll(); + _ASSERT(m_nCount==0); +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* +CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::NewAssoc() { + if(!m_pFreeList) { + CDXPlex *newBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CDXMap::CAssoc)); + CDXMap::CAssoc *pAssoc = (CDXMap::CAssoc*) newBlock->data(); + pAssoc += m_nBlockSize - 1; + for(int i = m_nBlockSize-1;i >= 0;i--,pAssoc--) { + pAssoc->pNext = m_pFreeList; + m_pFreeList = pAssoc; + } + } + _ASSERT(m_pFreeList!=NULL); + CDXMap::CAssoc *pAssoc = m_pFreeList; + m_pFreeList = m_pFreeList->pNext; + m_nCount++; + _ASSERT(m_nCount > 0); + DXConstructElements(&pAssoc->key,1); + DXConstructElements(&pAssoc->value,1); + return pAssoc; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::FreeAssoc(CAssoc *pAssoc) { + DXDestructElements(&pAssoc->value,1); + DXDestructElements(&pAssoc->key,1); + pAssoc->pNext = m_pFreeList; + m_pFreeList = pAssoc; + m_nCount--; + _ASSERT(m_nCount >= 0); +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* +CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetAssocAt(ARG_KEY key,UINT& nHash) const { + nHash = DXHashKey(key) % m_nHashTableSize; + if(!m_pHashTable) return NULL; + CAssoc *pAssoc; + for(pAssoc = m_pHashTable[nHash];pAssoc!=NULL;pAssoc = pAssoc->pNext) { + if(DXCompareElements(&pAssoc->key,&key)) return pAssoc; + } + return NULL; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::Lookup(ARG_KEY key,VALUE& rValue) const { + DXASSERT_VALID(this); + UINT nHash; + CAssoc *pAssoc = GetAssocAt(key,nHash); + if(!pAssoc) return FALSE; + rValue = pAssoc->value; + return TRUE; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +VALUE& CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::operator[](ARG_KEY key) { + DXASSERT_VALID(this); + UINT nHash; + CAssoc *pAssoc; + if(!(pAssoc = GetAssocAt(key,nHash))) { + if(!m_pHashTable) InitHashTable(m_nHashTableSize); + pAssoc = NewAssoc(); + pAssoc->nHashValue = nHash; + pAssoc->key = key; + pAssoc->pNext = m_pHashTable[nHash]; + m_pHashTable[nHash] = pAssoc; + } + return pAssoc->value; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveKey(ARG_KEY key) { + DXASSERT_VALID(this); + if(!m_pHashTable) return FALSE; + CAssoc **ppAssocPrev; + ppAssocPrev = &m_pHashTable[DXHashKey(key) % m_nHashTableSize]; + CAssoc *pAssoc; + for(pAssoc = *ppAssocPrev;pAssoc!=NULL;pAssoc = pAssoc->pNext) { + if(DXCompareElements(&pAssoc->key,&key)) { + *ppAssocPrev = pAssoc->pNext; + FreeAssoc(pAssoc); + return TRUE; + } + ppAssocPrev = &pAssoc->pNext; + } + return FALSE; +} + +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const { + DXASSERT_VALID(this); + _ASSERT(m_pHashTable!=NULL); + CAssoc *pAssocRet = (CAssoc*)rNextPosition; + _ASSERT(pAssocRet!=NULL); + if(pAssocRet==(CAssoc*) DX_BEFORE_START_POSITION) { + for(UINT nBucket = 0;nBucket < m_nHashTableSize;nBucket++) + if((pAssocRet = m_pHashTable[nBucket])!=NULL) + break; + _ASSERT(pAssocRet!=NULL); + } + _ASSERT(DXIsValidAddress(pAssocRet,sizeof(CAssoc),TRUE)); + CAssoc *pAssocNext; + if(!(pAssocNext = pAssocRet->pNext)) { + for(UINT nBucket = pAssocRet->nHashValue + 1;nBucket < m_nHashTableSize;nBucket++) + if((pAssocNext = m_pHashTable[nBucket])!=NULL) + break; + } + rNextPosition = (DXLISTPOS) pAssocNext; + rKey = pAssocRet->key; + rValue = pAssocRet->value; +} + +#ifdef _DEBUG +template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> +void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::AssertValid() const { + _ASSERT(m_nHashTableSize > 0); + _ASSERT((m_nCount==0 || m_pHashTable!=NULL)); +} +#endif + +#endif /* __cplusplus */ + +#endif
