xref: /reactos/sdk/lib/atl/atlcoll.h (revision e5813c46)
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