1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6#ifndef DXTmpl_h
7#define DXTmpl_h
8
9#include <limits.h>
10#include <string.h>
11#include <stdlib.h>
12#include <search.h>
13
14#define DXASSERT_VALID(pObj)
15
16#ifndef PASCAL_INLINE
17#define PASCAL_INLINE WINAPI
18#endif
19
20typedef void *DXLISTPOS;
21typedef DWORD DXLISTHANDLE;
22
23#define DX_BEFORE_START_POSITION ((void*)(INT_PTR)-1)
24
25#ifndef __CRT__NO_INLINE
26__CRT_INLINE WINBOOL DXIsValidAddress(const void *lp,UINT nBytes,WINBOOL bReadWrite) { return (lp!=NULL && !IsBadReadPtr(lp,nBytes) && (!bReadWrite || !IsBadWritePtr((LPVOID)lp,nBytes))); }
27#endif
28
29#ifdef __cplusplus
30
31template<class TYPE>
32inline void DXConstructElements(TYPE *pElements,int nCount) {
33  _ASSERT(nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE));
34  memset((void*)pElements,0,nCount *sizeof(TYPE));
35}
36
37template<class TYPE>
38inline void DXDestructElements(TYPE *pElements,int nCount) {
39  _ASSERT((nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE)));
40  pElements;
41  nCount;
42}
43
44template<class TYPE>
45inline void DXCopyElements(TYPE *pDest,const TYPE *pSrc,int nCount) {
46  _ASSERT((nCount==0 || DXIsValidAddress(pDest,nCount *sizeof(TYPE),TRUE)));
47  _ASSERT((nCount==0 || DXIsValidAddress(pSrc,nCount *sizeof(TYPE),FALSE)));
48  memcpy(pDest,pSrc,nCount *sizeof(TYPE));
49}
50
51template<class TYPE,class ARG_TYPE>
52WINBOOL DXCompareElements(const TYPE *pElement1,const ARG_TYPE *pElement2) {
53  _ASSERT(DXIsValidAddress(pElement1,sizeof(TYPE),FALSE));
54  _ASSERT(DXIsValidAddress(pElement2,sizeof(ARG_TYPE),FALSE));
55  return *pElement1==*pElement2;
56}
57
58template<class ARG_KEY>
59inline UINT DXHashKey(ARG_KEY key) { return ((UINT)(void*)(DWORD)key) >> 4; }
60
61struct CDXPlex {
62  CDXPlex *pNext;
63  UINT nMax;
64  UINT nCur;
65  void *data() { return this+1; }
66  static CDXPlex *PASCAL_INLINE Create(CDXPlex *&pHead,UINT nMax,UINT cbElement) {
67    CDXPlex *p = (CDXPlex*) new BYTE[sizeof(CDXPlex) + nMax *cbElement];
68    if(!p) return NULL;
69    p->nMax = nMax;
70    p->nCur = 0;
71    p->pNext = pHead;
72    pHead = p;
73    return p;
74  }
75  void FreeDataChain() {
76    CDXPlex *p = this;
77    while(p!=NULL) {
78      BYTE *bytes = (BYTE*) p;
79      CDXPlex *pNext = p->pNext;
80      delete [] bytes;
81      p = pNext;
82    }
83  }
84};
85
86template<class TYPE,class ARG_TYPE>
87class CDXArray {
88public:
89  CDXArray();
90  int GetSize() const;
91  int GetUpperBound() const;
92  void SetSize(int nNewSize,int nGrowBy = -1);
93  void FreeExtra();
94  void RemoveAll();
95  TYPE GetAt(int nIndex) const;
96  void SetAt(int nIndex,ARG_TYPE newElement);
97  TYPE &ElementAt(int nIndex);
98  const TYPE *GetData() const;
99  TYPE *GetData();
100  void SetAtGrow(int nIndex,ARG_TYPE newElement);
101  int Add(ARG_TYPE newElement);
102  int Append(const CDXArray &src);
103  void Copy(const CDXArray &src);
104  TYPE operator[](int nIndex) const;
105  TYPE &operator[](int nIndex);
106  void InsertAt(int nIndex,ARG_TYPE newElement,int nCount = 1);
107  void RemoveAt(int nIndex,int nCount = 1);
108  void InsertAt(int nStartIndex,CDXArray *pNewArray);
109  void Sort(int (__cdecl *compare)(const void *elem1,const void *elem2));
110protected:
111  TYPE *m_pData;
112  int m_nSize;
113  int m_nMaxSize;
114  int m_nGrowBy;
115public:
116  ~CDXArray();
117};
118
119template<class TYPE,class ARG_TYPE>
120inline int CDXArray<TYPE,ARG_TYPE>::GetSize() const { return m_nSize; }
121template<class TYPE,class ARG_TYPE>
122inline int CDXArray<TYPE,ARG_TYPE>::GetUpperBound() const { return m_nSize-1; }
123template<class TYPE,class ARG_TYPE>
124inline void CDXArray<TYPE,ARG_TYPE>::RemoveAll() { SetSize(0,-1); }
125template<class TYPE,class ARG_TYPE>
126inline TYPE CDXArray<TYPE,ARG_TYPE>::GetAt(int nIndex) const { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; }
127template<class TYPE,class ARG_TYPE>
128inline void CDXArray<TYPE,ARG_TYPE>::SetAt(int nIndex,ARG_TYPE newElement) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); m_pData[nIndex] = newElement; }
129template<class TYPE,class ARG_TYPE>
130inline TYPE &CDXArray<TYPE,ARG_TYPE>::ElementAt(int nIndex) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; }
131template<class TYPE,class ARG_TYPE>
132inline const TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() const { return (const TYPE*)m_pData; }
133template<class TYPE,class ARG_TYPE>
134inline TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() { return (TYPE*)m_pData; }
135template<class TYPE,class ARG_TYPE>
136inline int CDXArray<TYPE,ARG_TYPE>::Add(ARG_TYPE newElement) {
137  int nIndex = m_nSize;
138  SetAtGrow(nIndex,newElement);
139  return nIndex;
140}
141template<class TYPE,class ARG_TYPE>
142inline TYPE CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) const { return GetAt(nIndex); }
143template<class TYPE,class ARG_TYPE>
144inline TYPE &CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) { return ElementAt(nIndex); }
145template<class TYPE,class ARG_TYPE>
146CDXArray<TYPE,ARG_TYPE>::CDXArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; }
147emplate<class TYPE,class ARG_TYPE>
148CDXArray<TYPE,ARG_TYPE>::~CDXArray() {
149  DXASSERT_VALID(this);
150  if(m_pData!=NULL) {
151    DXDestructElements(m_pData,m_nSize);
152    delete[] (BYTE*)m_pData;
153  }
154}
155
156template<class TYPE,class ARG_TYPE>
157void CDXArray<TYPE,ARG_TYPE>::SetSize(int nNewSize,int nGrowBy) {
158  DXASSERT_VALID(this);
159  _ASSERT(nNewSize >= 0);
160  if(nGrowBy!=-1) m_nGrowBy = nGrowBy;
161  if(nNewSize==0) {
162    if(m_pData!=NULL) {
163      DXDestructElements(m_pData,m_nSize);
164      delete[] (BYTE*)m_pData;
165      m_pData = NULL;
166    }
167    m_nSize = m_nMaxSize = 0;
168  } else if(!m_pData) {
169#ifdef SIZE_T_MAX
170    _ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE));
171#endif
172    m_pData = (TYPE*) new BYTE[nNewSize *sizeof(TYPE)];
173    DXConstructElements(m_pData,nNewSize);
174    m_nSize = m_nMaxSize = nNewSize;
175  } else if(nNewSize <= m_nMaxSize) {
176    if(nNewSize > m_nSize) {
177      DXConstructElements(&m_pData[m_nSize],nNewSize-m_nSize);
178    } else if(m_nSize > nNewSize) {
179      DXDestructElements(&m_pData[nNewSize],m_nSize-nNewSize);
180    }
181    m_nSize = nNewSize;
182  } else {
183    int nGrowBy = m_nGrowBy;
184    if(!nGrowBy) nGrowBy = min(1024,max(4,m_nSize / 8));
185    int nNewMax;
186    if(nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy;
187    else nNewMax = nNewSize;
188    _ASSERT(nNewMax >= m_nMaxSize);
189#ifdef SIZE_T_MAX
190    _ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE));
191#endif
192    TYPE *pNewData = (TYPE*) new BYTE[nNewMax *sizeof(TYPE)];
193
194    if(!pNewData) return;
195    memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE));
196    _ASSERT(nNewSize > m_nSize);
197    DXConstructElements(&pNewData[m_nSize],nNewSize-m_nSize);
198    delete[] (BYTE*)m_pData;
199    m_pData = pNewData;
200    m_nSize = nNewSize;
201    m_nMaxSize = nNewMax;
202  }
203}
204
205template<class TYPE,class ARG_TYPE>
206int CDXArray<TYPE,ARG_TYPE>::Append(const CDXArray &src) {
207  DXASSERT_VALID(this);
208  _ASSERT(this!=&src);
209  int nOldSize = m_nSize;
210  SetSize(m_nSize + src.m_nSize);
211  DXCopyElements(m_pData + nOldSize,src.m_pData,src.m_nSize);
212  return nOldSize;
213}
214
215template<class TYPE,class ARG_TYPE>
216void CDXArray<TYPE,ARG_TYPE>::Copy(const CDXArray &src) {
217  DXASSERT_VALID(this);
218  _ASSERT(this!=&src);
219  SetSize(src.m_nSize);
220  DXCopyElements(m_pData,src.m_pData,src.m_nSize);
221}
222
223template<class TYPE,class ARG_TYPE>
224void CDXArray<TYPE,ARG_TYPE>::FreeExtra() {
225  DXASSERT_VALID(this);
226  if(m_nSize!=m_nMaxSize) {
227#ifdef SIZE_T_MAX
228    _ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE));
229#endif
230    TYPE *pNewData = NULL;
231    if(m_nSize!=0) {
232      pNewData = (TYPE*) new BYTE[m_nSize *sizeof(TYPE)];
233      if(!pNewData) return;
234      memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE));
235    }
236    delete[] (BYTE*)m_pData;
237    m_pData = pNewData;
238    m_nMaxSize = m_nSize;
239  }
240}
241
242template<class TYPE,class ARG_TYPE>
243void CDXArray<TYPE,ARG_TYPE>::SetAtGrow(int nIndex,ARG_TYPE newElement) {
244  DXASSERT_VALID(this);
245  _ASSERT(nIndex >= 0);
246  if(nIndex >= m_nSize) SetSize(nIndex+1,-1);
247  m_pData[nIndex] = newElement;
248}
249
250template<class TYPE,class ARG_TYPE>
251void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nIndex,ARG_TYPE newElement,int nCount) {
252  DXASSERT_VALID(this);
253  _ASSERT(nIndex >= 0);
254  _ASSERT(nCount > 0);
255  if(nIndex >= m_nSize) SetSize(nIndex + nCount,-1);
256  else {
257    int nOldSize = m_nSize;
258    SetSize(m_nSize + nCount,-1);
259    memmove(&m_pData[nIndex+nCount],&m_pData[nIndex],(nOldSize-nIndex) *sizeof(TYPE));
260    DXConstructElements(&m_pData[nIndex],nCount);
261  }
262  _ASSERT(nIndex + nCount <= m_nSize);
263  while(nCount--)
264    m_pData[nIndex++] = newElement;
265}
266
267template<class TYPE,class ARG_TYPE>
268void CDXArray<TYPE,ARG_TYPE>::RemoveAt(int nIndex,int nCount) {
269  DXASSERT_VALID(this);
270  _ASSERT(nIndex >= 0);
271  _ASSERT(nCount >= 0);
272  _ASSERT(nIndex + nCount <= m_nSize);
273  int nMoveCount = m_nSize - (nIndex + nCount);
274  DXDestructElements(&m_pData[nIndex],nCount);
275  if(nMoveCount)
276    memcpy(&m_pData[nIndex],&m_pData[nIndex + nCount],nMoveCount *sizeof(TYPE));
277  m_nSize -= nCount;
278}
279
280template<class TYPE,class ARG_TYPE>
281void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nStartIndex,CDXArray *pNewArray) {
282  DXASSERT_VALID(this);
283  DXASSERT_VALID(pNewArray);
284  _ASSERT(nStartIndex >= 0);
285  if(pNewArray->GetSize() > 0) {
286    InsertAt(nStartIndex,pNewArray->GetAt(0),pNewArray->GetSize());
287    for(int i = 0;i < pNewArray->GetSize();i++)
288      SetAt(nStartIndex + i,pNewArray->GetAt(i));
289  }
290}
291
292template<class TYPE,class ARG_TYPE>
293void CDXArray<TYPE,ARG_TYPE>::Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)) {
294  DXASSERT_VALID(this);
295  _ASSERT(m_pData!=NULL);
296  qsort(m_pData,m_nSize,sizeof(TYPE),compare);
297}
298
299#ifdef _DEBUG
300template<class TYPE,class ARG_TYPE>
301void CDXArray<TYPE,ARG_TYPE>::AssertValid() const {
302  if(!m_pData) {
303    _ASSERT(m_nSize==0);
304    _ASSERT(m_nMaxSize==0);
305  } else {
306    _ASSERT(m_nSize >= 0);
307    _ASSERT(m_nMaxSize >= 0);
308    _ASSERT(m_nSize <= m_nMaxSize);
309    _ASSERT(DXIsValidAddress(m_pData,m_nMaxSize *sizeof(TYPE),TRUE));
310  }
311}
312#endif
313
314template<class TYPE,class ARG_TYPE>
315class CDXList {
316protected:
317  struct CNode {
318    CNode *pNext;
319    CNode *pPrev;
320    TYPE data;
321  };
322public:
323  CDXList(int nBlockSize = 10);
324  int GetCount() const;
325  WINBOOL IsEmpty() const;
326  TYPE &GetHead();
327  TYPE GetHead() const;
328  TYPE &GetTail();
329  TYPE GetTail() const;
330
331  TYPE RemoveHead();
332  TYPE RemoveTail();
333  DXLISTPOS AddHead(ARG_TYPE newElement);
334  DXLISTPOS AddTail(ARG_TYPE newElement);
335  void AddHead(CDXList *pNewList);
336  void AddTail(CDXList *pNewList);
337  void RemoveAll();
338  DXLISTPOS GetHeadPosition() const;
339  DXLISTPOS GetTailPosition() const;
340  TYPE &GetNext(DXLISTPOS &rPosition);
341  TYPE GetNext(DXLISTPOS &rPosition) const;
342  TYPE &GetPrev(DXLISTPOS &rPosition);
343  TYPE GetPrev(DXLISTPOS &rPosition) const;
344  TYPE &GetAt(DXLISTPOS position);
345  TYPE GetAt(DXLISTPOS position) const;
346  void SetAt(DXLISTPOS pos,ARG_TYPE newElement);
347  void RemoveAt(DXLISTPOS position);
348  DXLISTPOS InsertBefore(DXLISTPOS position,ARG_TYPE newElement);
349  DXLISTPOS InsertAfter(DXLISTPOS position,ARG_TYPE newElement);
350  DXLISTPOS Find(ARG_TYPE searchValue,DXLISTPOS startAfter = NULL) const;
351  DXLISTPOS FindIndex(int nIndex) const;
352protected:
353  CNode *m_pNodeHead;
354  CNode *m_pNodeTail;
355  int m_nCount;
356  CNode *m_pNodeFree;
357  struct CDXPlex *m_pBlocks;
358  int m_nBlockSize;
359  CNode *NewNode(CNode *,CNode *);
360  void FreeNode(CNode *);
361public:
362  ~CDXList();
363#ifdef _DEBUG
364  void AssertValid() const;
365#endif
366};
367
368template<class TYPE,class ARG_TYPE>
369inline int CDXList<TYPE,ARG_TYPE>::GetCount() const { return m_nCount; }
370template<class TYPE,class ARG_TYPE>
371inline WINBOOL CDXList<TYPE,ARG_TYPE>::IsEmpty() const { return m_nCount==0; }
372template<class TYPE,class ARG_TYPE>
373inline TYPE &CDXList<TYPE,ARG_TYPE>::GetHead() { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; }
374template<class TYPE,class ARG_TYPE>
375inline TYPE CDXList<TYPE,ARG_TYPE>::GetHead() const { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; }
376template<class TYPE,class ARG_TYPE>
377inline TYPE &CDXList<TYPE,ARG_TYPE>::GetTail() { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; }
378template<class TYPE,class ARG_TYPE>
379inline TYPE CDXList<TYPE,ARG_TYPE>::GetTail() const { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; }
380template<class TYPE,class ARG_TYPE>
381inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetHeadPosition() const { return (DXLISTPOS) m_pNodeHead; }
382template<class TYPE,class ARG_TYPE>
383inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetTailPosition() const { return (DXLISTPOS) m_pNodeTail; }
384template<class TYPE,class ARG_TYPE>
385inline TYPE &CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) {
386  CNode *pNode = (CNode *) rPosition;
387  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
388  rPosition = (DXLISTPOS) pNode->pNext;
389  return pNode->data;
390}
391template<class TYPE,class ARG_TYPE>
392inline TYPE CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) const {
393  CNode *pNode = (CNode *) rPosition;
394  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
395  rPosition = (DXLISTPOS) pNode->pNext;
396  return pNode->data;
397}
398template<class TYPE,class ARG_TYPE>
399inline TYPE &CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) {
400  CNode *pNode = (CNode *) rPosition;
401  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
402  rPosition = (DXLISTPOS) pNode->pPrev;
403  return pNode->data;
404}
405template<class TYPE,class ARG_TYPE>
406inline TYPE CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) const {
407  CNode *pNode = (CNode *) rPosition;
408  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
409  rPosition = (DXLISTPOS) pNode->pPrev;
410  return pNode->data;
411}
412template<class TYPE,class ARG_TYPE>
413inline TYPE &CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) {
414  CNode *pNode = (CNode *) position;
415  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
416  return pNode->data;
417}
418template<class TYPE,class ARG_TYPE>
419inline TYPE CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) const {
420  CNode *pNode = (CNode *) position;
421  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
422  return pNode->data;
423}
424template<class TYPE,class ARG_TYPE>
425inline void CDXList<TYPE,ARG_TYPE>::SetAt(DXLISTPOS pos,ARG_TYPE newElement) {
426  CNode *pNode = (CNode *) pos;
427  _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
428  pNode->data = newElement;
429}
430
431template<class TYPE,class ARG_TYPE>
432CDXList<TYPE,ARG_TYPE>::CDXList(int nBlockSize) {
433  _ASSERT(nBlockSize > 0);
434  m_nCount = 0;
435  m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
436  m_pBlocks = NULL;
437  m_nBlockSize = nBlockSize;
438}
439
440template<class TYPE,class ARG_TYPE>
441void CDXList<TYPE,ARG_TYPE>::RemoveAll() {
442  DXASSERT_VALID(this);
443  CNode *pNode;
444  for(pNode = m_pNodeHead;pNode!=NULL;pNode = pNode->pNext)
445    DXDestructElements(&pNode->data,1);
446  m_nCount = 0;
447  m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
448  m_pBlocks->FreeDataChain();
449  m_pBlocks = NULL;
450}
451
452template<class TYPE,class ARG_TYPE>
453CDXList<TYPE,ARG_TYPE>::~CDXList() {
454  RemoveAll();
455  _ASSERT(m_nCount==0);
456}
457
458template<class TYPE,class ARG_TYPE>
459typename CDXList<TYPE,ARG_TYPE>::CNode *
460CDXList<TYPE,ARG_TYPE>::NewNode(CNode *pPrev,CNode *pNext) {
461  if(!m_pNodeFree) {
462    CDXPlex *pNewBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CNode));
463    CNode *pNode = (CNode *) pNewBlock->data();
464    pNode += m_nBlockSize - 1;
465    for(int i = m_nBlockSize-1;i >= 0;i--,pNode--) {
466      pNode->pNext = m_pNodeFree;
467      m_pNodeFree = pNode;
468    }
469  }
470  _ASSERT(m_pNodeFree!=NULL);
471  CDXList::CNode *pNode = m_pNodeFree;
472  m_pNodeFree = m_pNodeFree->pNext;
473  pNode->pPrev = pPrev;
474  pNode->pNext = pNext;
475  m_nCount++;
476  _ASSERT(m_nCount > 0);
477  DXConstructElements(&pNode->data,1);
478  return pNode;
479}
480
481template<class TYPE,class ARG_TYPE>
482void CDXList<TYPE,ARG_TYPE>::FreeNode(CNode *pNode) {
483  DXDestructElements(&pNode->data,1);
484  pNode->pNext = m_pNodeFree;
485  m_pNodeFree = pNode;
486  m_nCount--;
487  _ASSERT(m_nCount >= 0);
488}
489
490template<class TYPE,class ARG_TYPE>
491DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddHead(ARG_TYPE newElement) {
492  DXASSERT_VALID(this);
493  CNode *pNewNode = NewNode(NULL,m_pNodeHead);
494  pNewNode->data = newElement;
495  if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = pNewNode;
496  else m_pNodeTail = pNewNode;
497  m_pNodeHead = pNewNode;
498  return (DXLISTPOS) pNewNode;
499}
500
501template<class TYPE,class ARG_TYPE>
502DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddTail(ARG_TYPE newElement) {
503  DXASSERT_VALID(this);
504  CNode *pNewNode = NewNode(m_pNodeTail,NULL);
505  pNewNode->data = newElement;
506  if(m_pNodeTail!=NULL) m_pNodeTail->pNext = pNewNode;
507  else m_pNodeHead = pNewNode;
508  m_pNodeTail = pNewNode;
509  return (DXLISTPOS) pNewNode;
510}
511
512template<class TYPE,class ARG_TYPE>
513void CDXList<TYPE,ARG_TYPE>::AddHead(CDXList *pNewList) {
514  DXASSERT_VALID(this);
515  DXASSERT_VALID(pNewList);
516  DXLISTPOS pos = pNewList->GetTailPosition();
517  while(pos!=NULL)
518    AddHead(pNewList->GetPrev(pos));
519}
520
521template<class TYPE,class ARG_TYPE>
522void CDXList<TYPE,ARG_TYPE>::AddTail(CDXList *pNewList) {
523  DXASSERT_VALID(this);
524  DXASSERT_VALID(pNewList);
525  DXLISTPOS pos = pNewList->GetHeadPosition();
526  while(pos!=NULL)
527    AddTail(pNewList->GetNext(pos));
528}
529
530template<class TYPE,class ARG_TYPE>
531TYPE CDXList<TYPE,ARG_TYPE>::RemoveHead() {
532  DXASSERT_VALID(this);
533  _ASSERT(m_pNodeHead!=NULL);
534  _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE));
535  CNode *pOldNode = m_pNodeHead;
536  TYPE returnValue = pOldNode->data;
537  m_pNodeHead = pOldNode->pNext;
538  if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = NULL;
539  else m_pNodeTail = NULL;
540  FreeNode(pOldNode);
541  return returnValue;
542}
543
544template<class TYPE,class ARG_TYPE>
545TYPE CDXList<TYPE,ARG_TYPE>::RemoveTail() {
546  DXASSERT_VALID(this);
547  _ASSERT(m_pNodeTail!=NULL);
548  _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE));
549  CNode *pOldNode = m_pNodeTail;
550  TYPE returnValue = pOldNode->data;
551  m_pNodeTail = pOldNode->pPrev;
552  if(m_pNodeTail!=NULL) m_pNodeTail->pNext = NULL;
553  else m_pNodeHead = NULL;
554  FreeNode(pOldNode);
555  return returnValue;
556}
557
558template<class TYPE,class ARG_TYPE>
559DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertBefore(DXLISTPOS position,ARG_TYPE newElement) {
560  DXASSERT_VALID(this);
561  if(!position) return AddHead(newElement);
562  CNode *pOldNode = (CNode *) position;
563  CNode *pNewNode = NewNode(pOldNode->pPrev,pOldNode);
564  pNewNode->data = newElement;
565  if(pOldNode->pPrev!=NULL) {
566    _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE));
567    pOldNode->pPrev->pNext = pNewNode;
568  } else {
569    _ASSERT(pOldNode==m_pNodeHead);
570    m_pNodeHead = pNewNode;
571  }
572  pOldNode->pPrev = pNewNode;
573  return (DXLISTPOS) pNewNode;
574}
575
576template<class TYPE,class ARG_TYPE>
577DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertAfter(DXLISTPOS position,ARG_TYPE newElement) {
578  DXASSERT_VALID(this);
579  if(!position) return AddTail(newElement);
580  CNode *pOldNode = (CNode *) position;
581  _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE));
582  CNode *pNewNode = NewNode(pOldNode,pOldNode->pNext);
583  pNewNode->data = newElement;
584  if(pOldNode->pNext!=NULL) {
585    _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE));
586    pOldNode->pNext->pPrev = pNewNode;
587  } else {
588    _ASSERT(pOldNode==m_pNodeTail);
589    m_pNodeTail = pNewNode;
590  }
591  pOldNode->pNext = pNewNode;
592  return (DXLISTPOS) pNewNode;
593}
594
595template<class TYPE,class ARG_TYPE>
596void CDXList<TYPE,ARG_TYPE>::RemoveAt(DXLISTPOS position) {
597  DXASSERT_VALID(this);
598  CNode *pOldNode = (CNode *) position;
599  _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE));
600  if(pOldNode==m_pNodeHead) {
601    m_pNodeHead = pOldNode->pNext;
602  } else {
603    _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE));
604    pOldNode->pPrev->pNext = pOldNode->pNext;
605  }
606  if(pOldNode==m_pNodeTail) m_pNodeTail = pOldNode->pPrev;
607  else {
608    _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE));
609    pOldNode->pNext->pPrev = pOldNode->pPrev;
610  }
611  FreeNode(pOldNode);
612}
613
614template<class TYPE,class ARG_TYPE>
615DXLISTPOS CDXList<TYPE,ARG_TYPE>::FindIndex(int nIndex) const {
616  DXASSERT_VALID(this);
617  _ASSERT(nIndex >= 0);
618  if(nIndex >= m_nCount) return NULL;
619  CNode *pNode = m_pNodeHead;
620  while(nIndex--) {
621    _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
622    pNode = pNode->pNext;
623  }
624  return (DXLISTPOS) pNode;
625}
626
627template<class TYPE,class ARG_TYPE>
628DXLISTPOS CDXList<TYPE,ARG_TYPE>::Find(ARG_TYPE searchValue,DXLISTPOS startAfter) const {
629  DXASSERT_VALID(this);
630  CNode *pNode = (CNode *) startAfter;
631  if(!pNode) pNode = m_pNodeHead;
632  else {
633    _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE));
634    pNode = pNode->pNext;
635  }
636  for(;pNode!=NULL;pNode = pNode->pNext)
637    if(DXCompareElements(&pNode->data,&searchValue)) return (DXLISTPOS)pNode;
638  return NULL;
639}
640
641#ifdef _DEBUG
642template<class TYPE,class ARG_TYPE>
643void CDXList<TYPE,ARG_TYPE>::AssertValid() const {
644  if(!m_nCount) {
645    _ASSERT(!m_pNodeHead);
646    _ASSERT(!m_pNodeTail);
647  } else {
648    _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE));
649    _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE));
650  }
651}
652#endif
653
654template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
655class CDXMap {
656protected:
657  struct CAssoc {
658    CAssoc *pNext;
659    UINT nHashValue;
660    KEY key;
661    VALUE value;
662  };
663public:
664  CDXMap(int nBlockSize = 10);
665  int GetCount() const;
666  WINBOOL IsEmpty() const;
667  WINBOOL Lookup(ARG_KEY key,VALUE& rValue) const;
668  VALUE& operator[](ARG_KEY key);
669  void SetAt(ARG_KEY key,ARG_VALUE newValue);
670  WINBOOL RemoveKey(ARG_KEY key);
671  void RemoveAll();
672  DXLISTPOS GetStartPosition() const;
673  void GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const;
674  UINT GetHashTableSize() const;
675  void InitHashTable(UINT hashSize,WINBOOL bAllocNow = TRUE);
676protected:
677  CAssoc **m_pHashTable;
678  UINT m_nHashTableSize;
679  int m_nCount;
680  CAssoc *m_pFreeList;
681  struct CDXPlex *m_pBlocks;
682  int m_nBlockSize;
683  CAssoc *NewAssoc();
684  void FreeAssoc(CAssoc*);
685  CAssoc *GetAssocAt(ARG_KEY,UINT&) const;
686public:
687  ~CDXMap();
688#ifdef _DEBUG
689  void AssertValid() const;
690#endif
691};
692
693template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
694inline int CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetCount() const { return m_nCount; }
695template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
696inline WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::IsEmpty() const { return m_nCount==0; }
697template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
698inline void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::SetAt(ARG_KEY key,ARG_VALUE newValue) { (*this)[key] = newValue; }
699template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
700inline DXLISTPOS CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetStartPosition() const { return (m_nCount==0) ? NULL : DX_BEFORE_START_POSITION; }
701template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
702inline UINT CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetHashTableSize() const { return m_nHashTableSize; }
703
704template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
705CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CDXMap(int nBlockSize) {
706  _ASSERT(nBlockSize > 0);
707  m_pHashTable = NULL;
708  m_nHashTableSize = 17;
709  m_nCount = 0;
710  m_pFreeList = NULL;
711  m_pBlocks = NULL;
712  m_nBlockSize = nBlockSize;
713}
714
715template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
716void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::InitHashTable(UINT nHashSize,WINBOOL bAllocNow) {
717  DXASSERT_VALID(this);
718  _ASSERT(m_nCount==0);
719  _ASSERT(nHashSize > 0);
720  if(m_pHashTable!=NULL) {
721    delete[] m_pHashTable;
722    m_pHashTable = NULL;
723  }
724  if(bAllocNow) {
725    m_pHashTable = new CAssoc *[nHashSize];
726    if(!m_pHashTable) return;
727    memset(m_pHashTable,0,sizeof(CAssoc*) *nHashSize);
728  }
729  m_nHashTableSize = nHashSize;
730}
731
732template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
733void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveAll() {
734  DXASSERT_VALID(this);
735  if(m_pHashTable!=NULL) {
736    for(UINT nHash = 0;nHash < m_nHashTableSize;nHash++) {
737      CAssoc *pAssoc;
738      for(pAssoc = m_pHashTable[nHash]; pAssoc!=NULL;
739	pAssoc = pAssoc->pNext)
740      {
741	DXDestructElements(&pAssoc->value,1);
742	DXDestructElements(&pAssoc->key,1);
743      }
744    }
745  }
746  delete[] m_pHashTable;
747  m_pHashTable = NULL;
748  m_nCount = 0;
749  m_pFreeList = NULL;
750  m_pBlocks->FreeDataChain();
751  m_pBlocks = NULL;
752}
753
754template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
755CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::~CDXMap() {
756  RemoveAll();
757  _ASSERT(m_nCount==0);
758}
759
760template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
761typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc*
762CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::NewAssoc() {
763  if(!m_pFreeList) {
764    CDXPlex *newBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CDXMap::CAssoc));
765    CDXMap::CAssoc *pAssoc = (CDXMap::CAssoc*) newBlock->data();
766    pAssoc += m_nBlockSize - 1;
767    for(int i = m_nBlockSize-1;i >= 0;i--,pAssoc--) {
768      pAssoc->pNext = m_pFreeList;
769      m_pFreeList = pAssoc;
770    }
771  }
772  _ASSERT(m_pFreeList!=NULL);
773  CDXMap::CAssoc *pAssoc = m_pFreeList;
774  m_pFreeList = m_pFreeList->pNext;
775  m_nCount++;
776  _ASSERT(m_nCount > 0);
777  DXConstructElements(&pAssoc->key,1);
778  DXConstructElements(&pAssoc->value,1);
779  return pAssoc;
780}
781
782template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
783void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::FreeAssoc(CAssoc *pAssoc) {
784  DXDestructElements(&pAssoc->value,1);
785  DXDestructElements(&pAssoc->key,1);
786  pAssoc->pNext = m_pFreeList;
787  m_pFreeList = pAssoc;
788  m_nCount--;
789  _ASSERT(m_nCount >= 0);
790}
791
792template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
793typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc*
794CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetAssocAt(ARG_KEY key,UINT& nHash) const {
795  nHash = DXHashKey(key) % m_nHashTableSize;
796  if(!m_pHashTable) return NULL;
797  CAssoc *pAssoc;
798  for(pAssoc = m_pHashTable[nHash];pAssoc!=NULL;pAssoc = pAssoc->pNext) {
799    if(DXCompareElements(&pAssoc->key,&key)) return pAssoc;
800  }
801  return NULL;
802}
803
804template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
805WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::Lookup(ARG_KEY key,VALUE& rValue) const {
806  DXASSERT_VALID(this);
807  UINT nHash;
808  CAssoc *pAssoc = GetAssocAt(key,nHash);
809  if(!pAssoc) return FALSE;
810  rValue = pAssoc->value;
811  return TRUE;
812}
813
814template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
815VALUE& CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::operator[](ARG_KEY key) {
816  DXASSERT_VALID(this);
817  UINT nHash;
818  CAssoc *pAssoc;
819  if(!(pAssoc = GetAssocAt(key,nHash))) {
820    if(!m_pHashTable) InitHashTable(m_nHashTableSize);
821    pAssoc = NewAssoc();
822    pAssoc->nHashValue = nHash;
823    pAssoc->key = key;
824    pAssoc->pNext = m_pHashTable[nHash];
825    m_pHashTable[nHash] = pAssoc;
826  }
827  return pAssoc->value;
828}
829
830template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
831WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveKey(ARG_KEY key) {
832  DXASSERT_VALID(this);
833  if(!m_pHashTable) return FALSE;
834  CAssoc **ppAssocPrev;
835  ppAssocPrev = &m_pHashTable[DXHashKey(key) % m_nHashTableSize];
836  CAssoc *pAssoc;
837  for(pAssoc = *ppAssocPrev;pAssoc!=NULL;pAssoc = pAssoc->pNext) {
838    if(DXCompareElements(&pAssoc->key,&key)) {
839      *ppAssocPrev = pAssoc->pNext;
840      FreeAssoc(pAssoc);
841      return TRUE;
842    }
843    ppAssocPrev = &pAssoc->pNext;
844  }
845  return FALSE;
846}
847
848template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
849void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const {
850  DXASSERT_VALID(this);
851  _ASSERT(m_pHashTable!=NULL);
852  CAssoc *pAssocRet = (CAssoc*)rNextPosition;
853  _ASSERT(pAssocRet!=NULL);
854  if(pAssocRet==(CAssoc*) DX_BEFORE_START_POSITION) {
855    for(UINT nBucket = 0;nBucket < m_nHashTableSize;nBucket++)
856      if((pAssocRet = m_pHashTable[nBucket])!=NULL)
857	break;
858    _ASSERT(pAssocRet!=NULL);
859  }
860  _ASSERT(DXIsValidAddress(pAssocRet,sizeof(CAssoc),TRUE));
861  CAssoc *pAssocNext;
862  if(!(pAssocNext = pAssocRet->pNext)) {
863    for(UINT nBucket = pAssocRet->nHashValue + 1;nBucket < m_nHashTableSize;nBucket++)
864      if((pAssocNext = m_pHashTable[nBucket])!=NULL)
865	break;
866  }
867  rNextPosition = (DXLISTPOS) pAssocNext;
868  rKey = pAssocRet->key;
869  rValue = pAssocRet->value;
870}
871
872#ifdef _DEBUG
873template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE>
874void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::AssertValid() const {
875  _ASSERT(m_nHashTableSize > 0);
876  _ASSERT((m_nCount==0 || m_pHashTable!=NULL));
877}
878#endif
879
880#endif /* __cplusplus */
881
882#endif
883