xref: /reactos/sdk/lib/atl/atlcoll.h (revision 9cfd8dd9)
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) noexcept { return ptr; }
13 inline void operator delete (void* ptr, void* voidptr2) noexcept { }
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 T, class Allocator = CCRTAllocator>
161 class CHeapPtrElementTraits :
162     public CDefaultElementTraits< CHeapPtr<T, Allocator> >
163 {
164 public:
165     typedef CHeapPtr<T, Allocator>& INARGTYPE;
166     typedef T*& OUTARGTYPE;
167 };
168 
169 
170 
171 template<typename E, class ETraits = CElementTraits<E> >
172 class CAtlArray
173 {
174 public:
175     typedef typename ETraits::INARGTYPE INARGTYPE;
176     typedef typename ETraits::OUTARGTYPE OUTARGTYPE;
177 
178 private:
179     E* m_pData;
180     size_t m_Size;
181     size_t m_AllocatedSize;
182     size_t m_GrowBy;
183 
184 
185 #pragma push_macro("new")
186 #undef new
187 
188     void CreateItems(E* pData, size_t Size)
189     {
190         for (size_t n = 0; n < Size; ++n)
191         {
192             ::new (pData + n) E;
193         }
194     }
195 
196 #pragma pop_macro("new")
197 
198     void DestructItems(E* pData, size_t Size)
199     {
200         for (size_t n = 0; n < Size; ++n)
201         {
202             pData[n].~E();
203         }
204     }
205 
206     bool GrowAllocatedData(size_t nNewSize)
207     {
208         if (m_pData)
209         {
210             size_t addSize = m_GrowBy > 0 ? m_GrowBy : m_AllocatedSize / 2;
211             size_t allocSize = m_AllocatedSize + addSize;
212             if (allocSize < nNewSize)
213                 allocSize = nNewSize;
214 
215             E* pData = (E*)malloc(nNewSize * sizeof(E));
216 
217             if (pData == NULL)
218             {
219                 return false;
220             }
221 
222             // Copy the objects over (default implementation will just move them without calling anything
223             ETraits::RelocateElements(pData, m_pData, m_Size);
224 
225             free(m_pData);
226             m_pData = pData;
227             m_AllocatedSize = nNewSize;
228         }
229         else
230         {
231             // We need to allocate a new buffer
232             size_t allocSize = m_GrowBy > nNewSize ? m_GrowBy : nNewSize;
233             m_pData = (E*)malloc(allocSize * sizeof(E));
234             if (m_pData == NULL)
235             {
236                 return false;
237             }
238             m_AllocatedSize = allocSize;
239         }
240         return true;
241     }
242 
243     /* The CAtlArray class does not support construction by copy */
244 private:
245     CAtlArray(_In_ const CAtlArray&);
246     CAtlArray& operator=(_In_ const CAtlArray&);
247 
248 public:
249     CAtlArray();
250     ~CAtlArray();
251 
252     size_t Add(INARGTYPE element);
253     size_t Add();
254 
255     bool SetCount(size_t nNewSize, int nGrowBy = - 1);
256     size_t GetCount() const;
257 
258     E& operator[](size_t ielement);
259     const E& operator[](size_t ielement) const;
260 
261     E& GetAt(size_t iElement);
262     const E& GetAt(size_t iElement) const;
263 
264     E* GetData();
265     const E* GetData() const;
266 
267 
268     //FIXME: Most of this class is missing!
269 };
270 
271 //
272 // CAtlArray public methods
273 //
274 
275 template<typename E, class ETraits>
276 CAtlArray< E, ETraits >::CAtlArray()
277     : m_pData(NULL)
278     , m_Size(0)
279     , m_AllocatedSize(0)
280     , m_GrowBy(0)
281 {
282 }
283 
284 template<typename E, class ETraits>
285 CAtlArray< E, ETraits >::~CAtlArray()
286 {
287     // Destroy all items
288     SetCount(0, -1);
289 }
290 
291 #pragma push_macro("new")
292 #undef new
293 
294 template<typename E, class ETraits>
295 size_t CAtlArray<E, ETraits>::Add(INARGTYPE element)
296 {
297     if (m_Size >= m_AllocatedSize)
298     {
299         if (!GrowAllocatedData(m_Size + 1))
300         {
301             AtlThrow(E_OUTOFMEMORY);
302         }
303     }
304 
305     ::new (m_pData + m_Size) E(element);
306     m_Size++;
307 
308     return m_Size - 1;
309 }
310 
311 #pragma pop_macro("new")
312 
313 template<typename E, class ETraits>
314 size_t CAtlArray<E, ETraits>::Add()
315 {
316     if (!SetCount(m_Size + 1))
317     {
318         AtlThrow(E_OUTOFMEMORY);
319     }
320 
321     return m_Size - 1;
322 }
323 
324 template<typename E, class ETraits>
325 bool CAtlArray<E, ETraits>::SetCount(size_t nNewSize, int nGrowBy /*= -1*/)
326 {
327 
328     if (nGrowBy > -1)
329     {
330         m_GrowBy = (size_t)nGrowBy;
331     }
332 
333     if (nNewSize == m_Size)
334     {
335         // Do nothing
336     }
337     else if (nNewSize == 0)
338     {
339         if (m_pData)
340         {
341             DestructItems(m_pData, m_Size);
342             m_pData = NULL;
343         }
344         m_Size = m_AllocatedSize = NULL;
345     }
346     else if (nNewSize < m_AllocatedSize)
347     {
348         if (nNewSize > m_Size)
349         {
350             CreateItems(m_pData + m_Size, nNewSize - m_Size);
351         }
352         else
353         {
354             DestructItems(m_pData + nNewSize, m_Size - nNewSize);
355         }
356         m_Size = nNewSize;
357     }
358     else
359     {
360         if (!GrowAllocatedData(nNewSize))
361         {
362             return false;
363         }
364 
365         CreateItems(m_pData + m_Size, nNewSize - m_Size);
366         m_Size = nNewSize;
367     }
368 
369     return true;
370 }
371 
372 template<typename E, class ETraits>
373 size_t CAtlArray<E, ETraits>::GetCount() const
374 {
375     return m_Size;
376 }
377 
378 template<typename E, class ETraits>
379 E& CAtlArray<E, ETraits>::operator[](size_t iElement)
380 {
381     ATLASSERT(iElement < m_Size);
382 
383     return m_pData[iElement];
384 }
385 
386 template<typename E, class ETraits>
387 const E& CAtlArray<E, ETraits>::operator[](size_t iElement) const
388 {
389     ATLASSERT(iElement < m_Size);
390 
391     return m_pData[iElement];
392 }
393 
394 template<typename E, class ETraits>
395 E& CAtlArray<E, ETraits>::GetAt(size_t iElement)
396 {
397     ATLASSERT(iElement < m_Size);
398 
399     return m_pData[iElement];
400 }
401 
402 template<typename E, class ETraits>
403 const E& CAtlArray<E, ETraits>::GetAt(size_t iElement) const
404 {
405     ATLASSERT(iElement < m_Size);
406 
407     return m_pData[iElement];
408 }
409 
410 template<typename E, class ETraits>
411 E* CAtlArray<E, ETraits>::GetData()
412 {
413     return m_pData;
414 }
415 
416 template<typename E, class ETraits>
417 const E* CAtlArray<E, ETraits>::GetData() const
418 {
419     return m_pData;
420 }
421 
422 
423 template<typename E, class ETraits = CElementTraits<E> >
424 class CAtlList
425 {
426 private:
427     typedef typename ETraits::INARGTYPE INARGTYPE;
428 
429 private:
430     class CNode :  public __POSITION
431     {
432     public:
433         CNode* m_Next;
434         CNode* m_Prev;
435         E m_Element;
436 
437     public:
438         CNode(INARGTYPE Element) :
439             m_Element(Element)
440         {
441         }
442 
443     /* The CNode class does not support construction by copy */
444     private:
445         CNode(_In_ const CNode&);
446         CNode& operator=(_In_ const CNode&);
447     };
448 
449 private:
450     CAtlPlex* m_Blocks;
451     UINT m_BlockSize;
452     CNode* m_HeadNode;
453     CNode* m_TailNode;
454     CNode* m_FreeNode;
455     size_t m_NumElements;
456 
457 /* The CAtlList class does not support construction by copy */
458 private:
459     CAtlList(_In_ const CAtlList&);
460     CAtlList& operator=(_In_ const CAtlList&);
461 
462 public:
463     CAtlList(_In_ UINT nBlockSize = 10);
464     ~CAtlList();
465 
466     size_t GetCount() const;
467     bool IsEmpty() const;
468 
469     POSITION GetHeadPosition() const;
470     POSITION GetTailPosition() const;
471 
472     E& GetNext(_Inout_ POSITION& pos);
473     const E& GetNext(_Inout_ POSITION& pos) const;
474     E& GetPrev(_Inout_ POSITION& pos);
475     const E& GetPrev(_Inout_ POSITION& pos) const;
476 
477     E& GetAt(_In_ POSITION pos);
478     const E& GetAt(_In_ POSITION pos) const;
479 
480     POSITION AddHead(INARGTYPE element);
481     POSITION AddTail(INARGTYPE element);
482 
483     E RemoveHead();
484     E RemoveTail();
485 
486     POSITION InsertBefore(_In_ POSITION pos, INARGTYPE element);
487     POSITION InsertAfter(_In_ POSITION pos, INARGTYPE element);
488 
489     void RemoveAll();
490     void RemoveAt(_In_ POSITION pos);
491 
492     POSITION Find(
493         INARGTYPE element,
494         _In_opt_ POSITION posStartAfter = NULL) const;
495     POSITION FindIndex(_In_ size_t iElement) const;
496 
497     void SwapElements(POSITION pos1, POSITION pos2);
498 
499 private:
500     CNode* CreateNode(
501         INARGTYPE element,
502         _In_opt_ CNode* pPrev,
503         _In_opt_ CNode* pNext
504         );
505 
506     void FreeNode(
507         _Inout_ CNode* pNode
508         );
509 
510     CNode* GetFreeNode(
511         );
512 
513 };
514 
515 
516 //
517 // CAtlist public methods
518 //
519 
520 template<typename E, class ETraits>
521 CAtlList< E, ETraits >::CAtlList(_In_ UINT nBlockSize) :
522     m_Blocks(NULL),
523     m_BlockSize(nBlockSize),
524     m_HeadNode(NULL),
525     m_TailNode(NULL),
526     m_FreeNode(NULL),
527     m_NumElements(0)
528 {
529     ATLASSERT(nBlockSize > 0);
530 }
531 
532 template<typename E, class ETraits>
533 CAtlList<E, ETraits >::~CAtlList(void)
534 {
535     RemoveAll();
536 }
537 
538 template<typename E, class ETraits>
539 inline size_t CAtlList< E, ETraits >::GetCount() const
540 {
541     return m_NumElements;
542 }
543 
544 template<typename E, class ETraits>
545 inline bool CAtlList< E, ETraits >::IsEmpty() const
546 {
547     return (m_NumElements == 0);
548 }
549 
550 template<typename E, class ETraits>
551 inline POSITION CAtlList<E, ETraits>::GetHeadPosition() const
552 {
553     return (POSITION)m_HeadNode;
554 }
555 
556 template<typename E, class ETraits>
557 inline POSITION CAtlList<E, ETraits>::GetTailPosition() const
558 {
559     return (POSITION)m_TailNode;
560 }
561 
562 template<typename E, class ETraits>
563 inline E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos)
564 {
565     CNode* Node = (CNode*)pos;
566     pos = (POSITION)Node->m_Next;
567     return Node->m_Element;
568 }
569 
570 template<typename E, class ETraits>
571 inline const E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) const
572 {
573     CNode* Node = (CNode*)pos;
574     pos = (POSITION)Node->m_Next;
575     return Node->m_Element;
576 }
577 
578 template<typename E, class ETraits>
579 inline E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos)
580 {
581     CNode* Node = (CNode*)pos;
582     pos = (POSITION)Node->m_Prev;
583     return Node->m_Element;
584 }
585 
586 template<typename E, class ETraits>
587 inline const E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) const
588 {
589     CNode* Node = (CNode*)pos;
590     pos = (POSITION)Node->m_Prev;
591     return Node->m_Element;
592 }
593 
594 template<typename E, class ETraits>
595 inline E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos)
596 {
597     CNode* Node = (CNode*)pos;
598     return Node->m_Element;
599 }
600 
601 template<typename E, class ETraits>
602 inline const E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) const
603 {
604     CNode* Node = (CNode*)pos;
605     return Node->m_Element;
606 }
607 
608 template<typename E, class ETraits>
609 POSITION CAtlList<E, ETraits>::AddHead(INARGTYPE element)
610 {
611     CNode* Node = CreateNode(element, NULL, m_HeadNode);
612     if (m_HeadNode)
613     {
614         m_HeadNode->m_Prev = Node;
615     }
616     else
617     {
618         m_TailNode = Node;
619     }
620     m_HeadNode = Node;
621 
622     return (POSITION)Node;
623 }
624 
625 template<typename E, class ETraits>
626 POSITION CAtlList<E, ETraits>::AddTail(INARGTYPE element)
627 {
628     CNode* Node = CreateNode(element, m_TailNode, NULL);
629     if (m_TailNode)
630     {
631         m_TailNode->m_Next = Node;
632     }
633     else
634     {
635         m_HeadNode = Node;
636     }
637     m_TailNode = Node;
638 
639     return (POSITION)Node;
640 }
641 
642 template<typename E, class ETraits>
643 E CAtlList<E, ETraits>::RemoveHead()
644 {
645     CNode* Node = m_HeadNode;
646     E Element(Node->m_Element);
647 
648     m_HeadNode = Node->m_Next;
649     if (m_HeadNode)
650     {
651         m_HeadNode->m_Prev = NULL;
652     }
653     else
654     {
655         m_TailNode = NULL;
656     }
657     FreeNode(Node);
658 
659     return Element;
660 }
661 
662 template<typename E, class ETraits>
663 E CAtlList<E, ETraits>::RemoveTail()
664 {
665     CNode* Node = m_TailNode;
666     E Element(Node->m_Element);
667 
668     m_TailNode = Node->m_Prev;
669     if (m_TailNode)
670     {
671         m_TailNode->m_Next = NULL;
672     }
673     else
674     {
675         m_HeadNode = NULL;
676     }
677     FreeNode(Node);
678 
679     return Element;
680 }
681 
682 template<typename E, class ETraits>
683 POSITION CAtlList<E, ETraits >::InsertBefore(_In_ POSITION pos, _In_ INARGTYPE element)
684 {
685     if (pos == NULL)
686         return AddHead(element);
687 
688     CNode* OldNode = (CNode*)pos;
689     CNode* Node = CreateNode(element, OldNode->m_Prev, OldNode);
690 
691     if (OldNode->m_Prev != NULL)
692     {
693         OldNode->m_Prev->m_Next = Node;
694     }
695     else
696     {
697         m_HeadNode = Node;
698     }
699     OldNode->m_Prev = Node;
700 
701     return (POSITION)Node;
702 }
703 
704 template<typename E, class ETraits>
705 POSITION CAtlList<E, ETraits >::InsertAfter(_In_ POSITION pos, _In_ INARGTYPE element)
706 {
707     if (pos == NULL)
708         return AddTail(element);
709 
710     CNode* OldNode = (CNode*)pos;
711     CNode* Node = CreateNode(element, OldNode, OldNode->m_Next);
712 
713     if (OldNode->m_Next != NULL)
714     {
715         OldNode->m_Next->m_Prev = Node;
716     }
717     else
718     {
719         m_TailNode = Node;
720     }
721     OldNode->m_Next = Node;
722 
723     return (POSITION)Node;
724 }
725 
726 template<typename E, class ETraits>
727 void CAtlList<E, ETraits >::RemoveAll()
728 {
729     while (m_NumElements > 0)
730     {
731         CNode* Node = m_HeadNode;
732         m_HeadNode = m_HeadNode->m_Next;
733         FreeNode(Node);
734     }
735 
736     m_HeadNode = NULL;
737     m_TailNode = NULL;
738     m_FreeNode = NULL;
739 
740     if (m_Blocks)
741     {
742         m_Blocks->Destroy();
743         m_Blocks = NULL;
744     }
745 }
746 
747 template<typename E, class ETraits>
748 void CAtlList<E, ETraits >::RemoveAt(_In_ POSITION pos)
749 {
750     ATLASSERT(pos != NULL);
751 
752     CNode* OldNode = (CNode*)pos;
753     if (OldNode == m_HeadNode)
754     {
755         m_HeadNode = OldNode->m_Next;
756     }
757     else
758     {
759         OldNode->m_Prev->m_Next = OldNode->m_Next;
760     }
761     if (OldNode == m_TailNode)
762     {
763         m_TailNode = OldNode->m_Prev;
764     }
765     else
766     {
767         OldNode->m_Next->m_Prev = OldNode->m_Prev;
768     }
769     FreeNode(OldNode);
770 }
771 
772 template<typename E, class ETraits>
773 POSITION CAtlList< E, ETraits >::Find(
774     INARGTYPE element,
775     _In_opt_ POSITION posStartAfter) const
776 {
777     CNode* Node = (CNode*)posStartAfter;
778     if (Node == NULL)
779     {
780         Node = m_HeadNode;
781     }
782     else
783     {
784         Node = Node->m_Next;
785     }
786 
787     for (; Node != NULL; Node = Node->m_Next)
788     {
789         if (ETraits::CompareElements(Node->m_Element, element))
790             return (POSITION)Node;
791     }
792 
793     return NULL;
794 }
795 
796 template<typename E, class ETraits>
797 POSITION CAtlList< E, ETraits >::FindIndex(_In_ size_t iElement) const
798 {
799     if (iElement >= m_NumElements)
800         return NULL;
801 
802     if (m_HeadNode == NULL)
803         return NULL;
804 
805     CNode* Node = m_HeadNode;
806     for (size_t i = 0; i < iElement; i++)
807     {
808         Node = Node->m_Next;
809     }
810 
811     return (POSITION)Node;
812 }
813 
814 template<typename E, class ETraits>
815 void CAtlList< E, ETraits >::SwapElements(POSITION pos1, POSITION pos2)
816 {
817     if (pos1 == pos2)
818         return;
819 
820 
821     CNode *node1 = (CNode *)pos1;
822     CNode *node2 = (CNode *)pos2;
823 
824     CNode *tmp = node1->m_Prev;
825     node1->m_Prev = node2->m_Prev;
826     node2->m_Prev = tmp;
827 
828     if (node1->m_Prev)
829         node1->m_Prev->m_Next = node1;
830     else
831         m_HeadNode = node1;
832 
833     if (node2->m_Prev)
834         node2->m_Prev->m_Next = node2;
835     else
836         m_HeadNode = node2;
837 
838     tmp = node1->m_Next;
839     node1->m_Next = node2->m_Next;
840     node2->m_Next = tmp;
841 
842     if (node1->m_Next)
843         node1->m_Next->m_Prev = node1;
844     else
845         m_TailNode = node1;
846 
847     if (node2->m_Next)
848         node2->m_Next->m_Prev = node2;
849     else
850         m_TailNode = node2;
851 }
852 
853 
854 //
855 // CAtlist private methods
856 //
857 
858 template<typename E, class ETraits>
859 typename CAtlList<E, ETraits>::CNode* CAtlList<E, ETraits>::CreateNode(
860     INARGTYPE element,
861     _In_opt_ CNode* Prev,
862     _In_opt_ CNode* Next
863     )
864 {
865     GetFreeNode();
866 
867     CNode* NewNode = m_FreeNode;
868     CNode* NextFree = m_FreeNode->m_Next;
869 
870     NewNode = new CNode(element);
871 
872     m_FreeNode = NextFree;
873     NewNode->m_Prev = Prev;
874     NewNode->m_Next = Next;
875     m_NumElements++;
876 
877     return NewNode;
878 }
879 
880 template<typename E, class ETraits>
881 void CAtlList<E, ETraits>::FreeNode(
882     _Inout_ CNode* pNode
883     )
884 {
885     pNode->~CNode();
886     pNode->m_Next = m_FreeNode;
887     m_FreeNode = pNode;
888 
889     m_NumElements--;
890     if (m_NumElements == 0)
891     {
892         RemoveAll();
893     }
894 }
895 
896 template<typename E, class ETraits>
897 typename CAtlList<E, ETraits>::CNode* CAtlList< E, ETraits>::GetFreeNode()
898 {
899     if (m_FreeNode)
900     {
901         return m_FreeNode;
902     }
903 
904     CAtlPlex* Block = CAtlPlex::Create(m_Blocks, m_BlockSize, sizeof(CNode));
905     if (Block == NULL)
906     {
907         AtlThrowImp(E_OUTOFMEMORY);
908     }
909 
910     CNode* Node = (CNode*)Block->GetData();
911     Node += (m_BlockSize - 1);
912     for (int i = m_BlockSize - 1; i >= 0; i--)
913     {
914         Node->m_Next = m_FreeNode;
915         m_FreeNode = Node;
916         Node--;
917     }
918 
919     return m_FreeNode;
920 }
921 
922 
923 template<typename E, class Allocator = CCRTAllocator >
924 class CHeapPtrList :
925     public CAtlList<CHeapPtr<E, Allocator>, CHeapPtrElementTraits<E, Allocator> >
926 {
927 public:
928     CHeapPtrList(_In_ UINT nBlockSize = 10) :
929         CAtlList<CHeapPtr<E, Allocator>, CHeapPtrElementTraits<E, Allocator> >(nBlockSize)
930     {
931     }
932 
933 private:
934     CHeapPtrList(const CHeapPtrList&);
935     CHeapPtrList& operator=(const CHeapPtrList*);
936 };
937 
938 
939 }
940 
941 #endif
942