6775a0281a3f1ce1e5eaac5d8b623c387503522e
[reactos.git] / sdk / lib / atl / atlcoll.h
1 #ifndef __ATLCOLL_H__
2 #define __ATLCOLL_H__
3
4 #pragma once
5 #include "atlbase.h"
6 #include "atlexcept.h"
7
8 // FIXME: We need to include <new> for placement new, but that would mean everyone using atl
9 // would also need to set the option 'WITH_STL'..
10 // For now we just copy the definition here, under a guard..
11 #ifndef _NEW
12 inline void* operator new (size_t size, void* ptr) throw() { return ptr; }
13 inline void operator delete (void* ptr, void* voidptr2) throw() { }
14 #endif
15
16
17 struct __POSITION
18 {
19 };
20 typedef __POSITION* POSITION;
21
22
23 namespace ATL
24 {
25
26 class CAtlPlex
27 {
28 public:
29 CAtlPlex* m_Next;
30
31 #if (_AFX_PACKING >= 8)
32 DWORD dwReserved[1];
33 #endif
34
35 static inline CAtlPlex* Create(
36 _Inout_ CAtlPlex*& Entry,
37 _In_ size_t MaxElements,
38 _In_ size_t ElementSize
39 )
40 {
41 CAtlPlex* Block;
42
43 ATLASSERT(MaxElements > 0);
44 ATLASSERT(ElementSize > 0);
45
46 size_t BufferSize = sizeof(CAtlPlex) + (MaxElements * ElementSize);
47
48 void *Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
49 if (Buffer == NULL) return NULL;
50
51 Block = static_cast< CAtlPlex* >(Buffer);
52 Block->m_Next = Entry;
53 Entry = Block;
54
55 return Block;
56 }
57
58 void* GetData()
59 {
60 return (this + 1);
61 }
62
63 inline void Destroy()
64 {
65 CAtlPlex* Block;
66 CAtlPlex* Next;
67
68 Block = this;
69 while (Block != NULL)
70 {
71 Next = Block->m_Next;
72 HeapFree(GetProcessHeap(), 0, Block);
73 Block = Next;
74 }
75 }
76 };
77
78
79 template<typename T>
80 class CElementTraitsBase
81 {
82 public:
83 typedef const T& INARGTYPE;
84 typedef T& OUTARGTYPE;
85
86 static void CopyElements(
87 _Out_writes_all_(NumElements) T* Dest,
88 _In_reads_(NumElements) const T* Source,
89 _In_ size_t NumElements)
90 {
91 for (size_t i = 0; i < NumElements; i++)
92 {
93 Dest[i] = Source[i];
94 }
95 }
96
97 static void RelocateElements(
98 _Out_writes_all_(NumElements) T* Dest,
99 _In_reads_(NumElements) T* Source,
100 _In_ size_t NumElements)
101 {
102 // A simple memmove works for most of the types.
103 // You'll have to override this for types that have pointers to their
104 // own members.
105
106 #if defined(__GNUC__) && __GNUC__ >= 8
107 #pragma GCC diagnostic push
108 #pragma GCC diagnostic ignored "-Wclass-memaccess"
109 #endif
110 memmove(Dest, Source, NumElements * sizeof(T));
111 #if defined(__GNUC__) && __GNUC__ >= 8
112 #pragma GCC diagnostic pop
113 #endif
114 }
115 };
116
117 template<typename T>
118 class CDefaultCompareTraits
119 {
120 public:
121 static bool CompareElements(
122 _In_ const T& Val1,
123 _In_ const T& Val2)
124 {
125 return (Val1 == Val2);
126 }
127
128 static int CompareElementsOrdered(
129 _In_ const T& Val1,
130 _In_ const T& Val2)
131 {
132 if (Val1 < Val2)
133 {
134 return -1;
135 }
136 else if (Val1 > Val2)
137 {
138 return 1;
139 }
140
141 return 0; // equal
142 }
143 };
144
145 template<typename T>
146 class CDefaultElementTraits :
147 public CElementTraitsBase<T>,
148 public CDefaultCompareTraits<T>
149 {
150 };
151
152
153 template<typename T>
154 class CElementTraits :
155 public CDefaultElementTraits<T>
156 {
157 };
158
159
160 template<typename E, class ETraits = CElementTraits<E> >
161 class CAtlArray
162 {
163 public:
164 typedef typename ETraits::INARGTYPE INARGTYPE;
165 typedef typename ETraits::OUTARGTYPE OUTARGTYPE;
166
167 private:
168 E* m_pData;
169 size_t m_Size;
170 size_t m_AllocatedSize;
171 size_t m_GrowBy;
172
173
174 #pragma push_macro("new")
175 #undef new
176
177 void CreateItems(E* pData, size_t Size)
178 {
179 for (size_t n = 0; n < Size; ++n)
180 {
181 ::new (pData + n) E;
182 }
183 }
184
185 #pragma pop_macro("new")
186
187 void DestructItems(E* pData, size_t Size)
188 {
189 for (size_t n = 0; n < Size; ++n)
190 {
191 pData[n].~E();
192 }
193 }
194
195 bool GrowAllocatedData(size_t nNewSize)
196 {
197 if (m_pData)
198 {
199 size_t addSize = m_GrowBy > 0 ? m_GrowBy : m_AllocatedSize / 2;
200 size_t allocSize = m_AllocatedSize + addSize;
201 if (allocSize < nNewSize)
202 allocSize = nNewSize;
203
204 E* pData = (E*)malloc(nNewSize * sizeof(E));
205
206 if (pData == NULL)
207 {
208 return false;
209 }
210
211 // Copy the objects over (default implementation will just move them without calling anything
212 ETraits::RelocateElements(pData, m_pData, m_Size);
213
214 free(m_pData);
215 m_pData = pData;
216 m_AllocatedSize = nNewSize;
217 }
218 else
219 {
220 // We need to allocate a new buffer
221 size_t allocSize = m_GrowBy > nNewSize ? m_GrowBy : nNewSize;
222 m_pData = (E*)malloc(allocSize * sizeof(E));
223 if (m_pData == NULL)
224 {
225 return false;
226 }
227 m_AllocatedSize = allocSize;
228 }
229 return true;
230 }
231
232 /* The CAtlArray class does not support construction by copy */
233 private:
234 CAtlArray(_In_ const CAtlArray&);
235 CAtlArray& operator=(_In_ const CAtlArray&);
236
237 public:
238 CAtlArray();
239 ~CAtlArray();
240
241 size_t Add(INARGTYPE element);
242 size_t Add();
243
244 bool SetCount(size_t nNewSize, int nGrowBy = - 1);
245 size_t GetCount() const;
246
247 E& operator[](size_t ielement);
248 const E& operator[](size_t ielement) const;
249
250 E& GetAt(size_t iElement);
251 const E& GetAt(size_t iElement) const;
252
253 //FIXME: Most of this class is missing!
254 };
255
256 //
257 // CAtlArray public methods
258 //
259
260 template<typename E, class ETraits>
261 CAtlArray< E, ETraits >::CAtlArray()
262 : m_pData(NULL)
263 , m_Size(0)
264 , m_AllocatedSize(0)
265 , m_GrowBy(0)
266 {
267 }
268
269 template<typename E, class ETraits>
270 CAtlArray< E, ETraits >::~CAtlArray()
271 {
272 // Destroy all items
273 SetCount(0, -1);
274 }
275
276 #pragma push_macro("new")
277 #undef new
278
279 template<typename E, class ETraits>
280 size_t CAtlArray<E, ETraits>::Add(INARGTYPE element)
281 {
282 if (m_Size >= m_AllocatedSize)
283 {
284 if (!GrowAllocatedData(m_Size + 1))
285 {
286 AtlThrow(E_OUTOFMEMORY);
287 }
288 }
289
290 ::new (m_pData + m_Size) E(element);
291 m_Size++;
292
293 return m_Size - 1;
294 }
295
296 #pragma pop_macro("new")
297
298 template<typename E, class ETraits>
299 size_t CAtlArray<E, ETraits>::Add()
300 {
301 if (!SetCount(m_Size + 1))
302 {
303 AtlThrow(E_OUTOFMEMORY);
304 }
305
306 return m_Size - 1;
307 }
308
309 template<typename E, class ETraits>
310 bool CAtlArray<E, ETraits>::SetCount(size_t nNewSize, int nGrowBy /*= -1*/)
311 {
312
313 if (nGrowBy > -1)
314 {
315 m_GrowBy = (size_t)nGrowBy;
316 }
317
318 if (nNewSize == m_Size)
319 {
320 // Do nothing
321 }
322 else if (nNewSize == 0)
323 {
324 if (m_pData)
325 {
326 DestructItems(m_pData, m_Size);
327 m_pData = NULL;
328 }
329 m_Size = m_AllocatedSize = NULL;
330 }
331 else if (nNewSize < m_AllocatedSize)
332 {
333 if (nNewSize > m_Size)
334 {
335 CreateItems(m_pData + m_Size, nNewSize - m_Size);
336 }
337 else
338 {
339 DestructItems(m_pData + nNewSize, m_Size - nNewSize);
340 }
341 m_Size = nNewSize;
342 }
343 else
344 {
345 if (!GrowAllocatedData(nNewSize))
346 {
347 return false;
348 }
349
350 CreateItems(m_pData + m_Size, nNewSize - m_Size);
351 m_Size = nNewSize;
352 }
353
354 return true;
355 }
356
357 template<typename E, class ETraits>
358 size_t CAtlArray<E, ETraits>::GetCount() const
359 {
360 return m_Size;
361 }
362
363 template<typename E, class ETraits>
364 E& CAtlArray<E, ETraits>::operator[](size_t iElement)
365 {
366 ATLASSERT(iElement < m_Size);
367
368 return m_pData[iElement];
369 }
370
371 template<typename E, class ETraits>
372 const E& CAtlArray<E, ETraits>::operator[](size_t iElement) const
373 {
374 ATLASSERT(iElement < m_Size);
375
376 return m_pData[iElement];
377 }
378
379 template<typename E, class ETraits>
380 E& CAtlArray<E, ETraits>::GetAt(size_t iElement)
381 {
382 ATLASSERT(iElement < m_Size);
383
384 return m_pData[iElement];
385 }
386
387 template<typename E, class ETraits>
388 const E& CAtlArray<E, ETraits>::GetAt(size_t iElement) const
389 {
390 ATLASSERT(iElement < m_Size);
391
392 return m_pData[iElement];
393 }
394
395
396
397 template<typename E, class ETraits = CElementTraits<E> >
398 class CAtlList
399 {
400 private:
401 typedef typename ETraits::INARGTYPE INARGTYPE;
402
403 private:
404 class CNode : public __POSITION
405 {
406 public:
407 CNode* m_Next;
408 CNode* m_Prev;
409 E m_Element;
410
411 public:
412 CNode(INARGTYPE Element) :
413 m_Element(Element)
414 {
415 }
416
417 /* The CNode class does not support construction by copy */
418 private:
419 CNode(_In_ const CNode&);
420 CNode& operator=(_In_ const CNode&);
421 };
422
423 private:
424 CAtlPlex* m_Blocks;
425 UINT m_BlockSize;
426 CNode* m_HeadNode;
427 CNode* m_TailNode;
428 CNode* m_FreeNode;
429 size_t m_NumElements;
430
431 /* The CAtlList class does not support construction by copy */
432 private:
433 CAtlList(_In_ const CAtlList&);
434 CAtlList& operator=(_In_ const CAtlList&);
435
436 public:
437 CAtlList(_In_ UINT nBlockSize = 10);
438 ~CAtlList();
439
440 size_t GetCount() const;
441 bool IsEmpty() const;
442
443 POSITION GetHeadPosition() const;
444 POSITION GetTailPosition() const;
445
446 E& GetNext(_Inout_ POSITION& pos);
447 const E& GetNext(_Inout_ POSITION& pos) const;
448 E& GetPrev(_Inout_ POSITION& pos);
449 const E& GetPrev(_Inout_ POSITION& pos) const;
450
451 E& GetAt(_In_ POSITION pos);
452 const E& GetAt(_In_ POSITION pos) const;
453
454 POSITION AddHead(INARGTYPE element);
455 POSITION AddTail(INARGTYPE element);
456
457 E RemoveHead();
458 E RemoveTail();
459
460 POSITION InsertBefore(_In_ POSITION pos, INARGTYPE element);
461 POSITION InsertAfter(_In_ POSITION pos, INARGTYPE element);
462
463 void RemoveAll();
464 void RemoveAt(_In_ POSITION pos);
465
466 POSITION Find(
467 INARGTYPE element,
468 _In_opt_ POSITION posStartAfter = NULL) const;
469 POSITION FindIndex(_In_ size_t iElement) const;
470
471 private:
472 CNode* CreateNode(
473 INARGTYPE element,
474 _In_opt_ CNode* pPrev,
475 _In_opt_ CNode* pNext
476 );
477
478 void FreeNode(
479 _Inout_ CNode* pNode
480 );
481
482 CNode* GetFreeNode(
483 );
484
485 };
486
487
488 //
489 // CAtlist public methods
490 //
491
492 template<typename E, class ETraits>
493 CAtlList< E, ETraits >::CAtlList(_In_ UINT nBlockSize) :
494 m_Blocks(NULL),
495 m_BlockSize(nBlockSize),
496 m_HeadNode(NULL),
497 m_TailNode(NULL),
498 m_FreeNode(NULL),
499 m_NumElements(0)
500 {
501 ATLASSERT(nBlockSize > 0);
502 }
503
504 template<typename E, class ETraits>
505 CAtlList<E, ETraits >::~CAtlList(void)
506 {
507 RemoveAll();
508 }
509
510 template<typename E, class ETraits>
511 inline size_t CAtlList< E, ETraits >::GetCount() const
512 {
513 return m_NumElements;
514 }
515
516 template<typename E, class ETraits>
517 inline bool CAtlList< E, ETraits >::IsEmpty() const
518 {
519 return (m_NumElements == 0);
520 }
521
522 template<typename E, class ETraits>
523 inline POSITION CAtlList<E, ETraits>::GetHeadPosition() const
524 {
525 return (POSITION)m_HeadNode;
526 }
527
528 template<typename E, class ETraits>
529 inline POSITION CAtlList<E, ETraits>::GetTailPosition() const
530 {
531 return (POSITION)m_TailNode;
532 }
533
534 template<typename E, class ETraits>
535 inline E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos)
536 {
537 CNode* Node = (CNode*)pos;
538 pos = (POSITION)Node->m_Next;
539 return Node->m_Element;
540 }
541
542 template<typename E, class ETraits>
543 inline const E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) const
544 {
545 CNode* Node = (CNode*)pos;
546 pos = (POSITION)Node->m_Next;
547 return Node->m_Element;
548 }
549
550 template<typename E, class ETraits>
551 inline E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos)
552 {
553 CNode* Node = (CNode*)pos;
554 pos = (POSITION)Node->m_Prev;
555 return Node->m_Element;
556 }
557
558 template<typename E, class ETraits>
559 inline const E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) const
560 {
561 CNode* Node = (CNode*)pos;
562 pos = (POSITION)Node->m_Prev;
563 return Node->m_Element;
564 }
565
566 template<typename E, class ETraits>
567 inline E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos)
568 {
569 CNode* Node = (CNode*)pos;
570 return Node->m_Element;
571 }
572
573 template<typename E, class ETraits>
574 inline const E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) const
575 {
576 CNode* Node = (CNode*)pos;
577 return Node->m_Element;
578 }
579
580 template<typename E, class ETraits>
581 POSITION CAtlList<E, ETraits>::AddHead(INARGTYPE element)
582 {
583 CNode* Node = CreateNode(element, NULL, m_HeadNode);
584 if (m_HeadNode)
585 {
586 m_HeadNode->m_Prev = Node;
587 }
588 else
589 {
590 m_TailNode = Node;
591 }
592 m_HeadNode = Node;
593
594 return (POSITION)Node;
595 }
596
597 template<typename E, class ETraits>
598 POSITION CAtlList<E, ETraits>::AddTail(INARGTYPE element)
599 {
600 CNode* Node = CreateNode(element, m_TailNode, NULL);
601 if (m_TailNode)
602 {
603 m_TailNode->m_Next = Node;
604 }
605 else
606 {
607 m_HeadNode = Node;
608 }
609 m_TailNode = Node;
610
611 return (POSITION)Node;
612 }
613
614 template<typename E, class ETraits>
615 E CAtlList<E, ETraits>::RemoveHead()
616 {
617 CNode* Node = m_HeadNode;
618 E Element(Node->m_Element);
619
620 m_HeadNode = Node->m_Next;
621 if (m_HeadNode)
622 {
623 m_HeadNode->m_Prev = NULL;
624 }
625 else
626 {
627 m_TailNode = NULL;
628 }
629 FreeNode(Node);
630
631 return Element;
632 }
633
634 template<typename E, class ETraits>
635 E CAtlList<E, ETraits>::RemoveTail()
636 {
637 CNode* Node = m_TailNode;
638 E Element(Node->m_Element);
639
640 m_TailNode = Node->m_Prev;
641 if (m_TailNode)
642 {
643 m_TailNode->m_Next = NULL;
644 }
645 else
646 {
647 m_HeadNode = NULL;
648 }
649 FreeNode(Node);
650
651 return Element;
652 }
653
654 template<typename E, class ETraits>
655 POSITION CAtlList<E, ETraits >::InsertBefore(_In_ POSITION pos, _In_ INARGTYPE element)
656 {
657 if (pos == NULL)
658 return AddHead(element);
659
660 CNode* OldNode = (CNode*)pos;
661 CNode* Node = CreateNode(element, OldNode->m_Prev, OldNode);
662
663 if (OldNode->m_Prev != NULL)
664 {
665 OldNode->m_Prev->m_Next = Node;
666 }
667 else
668 {
669 m_HeadNode = Node;
670 }
671 OldNode->m_Prev = Node;
672
673 return (POSITION)Node;
674 }
675
676 template<typename E, class ETraits>
677 POSITION CAtlList<E, ETraits >::InsertAfter(_In_ POSITION pos, _In_ INARGTYPE element)
678 {
679 if (pos == NULL)
680 return AddTail(element);
681
682 CNode* OldNode = (CNode*)pos;
683 CNode* Node = CreateNode(element, OldNode, OldNode->m_Next);
684
685 if (OldNode->m_Next != NULL)
686 {
687 OldNode->m_Next->m_Prev = Node;
688 }
689 else
690 {
691 m_TailNode = Node;
692 }
693 OldNode->m_Next = Node;
694
695 return (POSITION)Node;
696 }
697
698 template<typename E, class ETraits>
699 void CAtlList<E, ETraits >::RemoveAll()
700 {
701 while (m_NumElements > 0)
702 {
703 CNode* Node = m_HeadNode;
704 m_HeadNode = m_HeadNode->m_Next;
705 FreeNode(Node);
706 }
707
708 m_HeadNode = NULL;
709 m_TailNode = NULL;
710 m_FreeNode = NULL;
711
712 if (m_Blocks)
713 {
714 m_Blocks->Destroy();
715 m_Blocks = NULL;
716 }
717 }
718
719 template<typename E, class ETraits>
720 void CAtlList<E, ETraits >::RemoveAt(_In_ POSITION pos)
721 {
722 ATLASSERT(pos != NULL);
723
724 CNode* OldNode = (CNode*)pos;
725 if (OldNode == m_HeadNode)
726 {
727 m_HeadNode = OldNode->m_Next;
728 }
729 else
730 {
731 OldNode->m_Prev->m_Next = OldNode->m_Next;
732 }
733 if (OldNode == m_TailNode)
734 {
735 m_TailNode = OldNode->m_Prev;
736 }
737 else
738 {
739 OldNode->m_Next->m_Prev = OldNode->m_Prev;
740 }
741 FreeNode(OldNode);
742 }
743
744 template<typename E, class ETraits>
745 POSITION CAtlList< E, ETraits >::Find(
746 INARGTYPE element,
747 _In_opt_ POSITION posStartAfter) const
748 {
749 CNode* Node = (CNode*)posStartAfter;
750 if (Node == NULL)
751 {
752 Node = m_HeadNode;
753 }
754 else
755 {
756 Node = Node->m_Next;
757 }
758
759 for (; Node != NULL; Node = Node->m_Next)
760 {
761 if (ETraits::CompareElements(Node->m_Element, element))
762 return (POSITION)Node;
763 }
764
765 return NULL;
766 }
767
768 template<typename E, class ETraits>
769 POSITION CAtlList< E, ETraits >::FindIndex(_In_ size_t iElement) const
770 {
771 if (iElement >= m_NumElements)
772 return NULL;
773
774 if (m_HeadNode == NULL)
775 return NULL;
776
777 CNode* Node = m_HeadNode;
778 for (size_t i = 0; i < iElement; i++)
779 {
780 Node = Node->m_Next;
781 }
782
783 return (POSITION)Node;
784 }
785
786
787 //
788 // CAtlist private methods
789 //
790
791 template<typename E, class ETraits>
792 typename CAtlList<E, ETraits>::CNode* CAtlList<E, ETraits>::CreateNode(
793 INARGTYPE element,
794 _In_opt_ CNode* Prev,
795 _In_opt_ CNode* Next
796 )
797 {
798 GetFreeNode();
799
800 CNode* NewNode = m_FreeNode;
801 CNode* NextFree = m_FreeNode->m_Next;
802
803 NewNode = new CNode(element);
804
805 m_FreeNode = NextFree;
806 NewNode->m_Prev = Prev;
807 NewNode->m_Next = Next;
808 m_NumElements++;
809
810 return NewNode;
811 }
812
813 template<typename E, class ETraits>
814 void CAtlList<E, ETraits>::FreeNode(
815 _Inout_ CNode* pNode
816 )
817 {
818 pNode->~CNode();
819 pNode->m_Next = m_FreeNode;
820 m_FreeNode = pNode;
821
822 m_NumElements--;
823 if (m_NumElements == 0)
824 {
825 RemoveAll();
826 }
827 }
828
829 template<typename E, class ETraits>
830 typename CAtlList<E, ETraits>::CNode* CAtlList< E, ETraits>::GetFreeNode()
831 {
832 if (m_FreeNode)
833 {
834 return m_FreeNode;
835 }
836
837 CAtlPlex* Block = CAtlPlex::Create(m_Blocks, m_BlockSize, sizeof(CNode));
838 if (Block == NULL)
839 {
840 AtlThrowImp(E_OUTOFMEMORY);
841 }
842
843 CNode* Node = (CNode*)Block->GetData();
844 Node += (m_BlockSize - 1);
845 for (int i = m_BlockSize - 1; i >= 0; i--)
846 {
847 Node->m_Next = m_FreeNode;
848 m_FreeNode = Node;
849 Node--;
850 }
851
852 return m_FreeNode;
853 }
854
855 }
856
857 #endif