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