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 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 private: 498 CNode* CreateNode( 499 INARGTYPE element, 500 _In_opt_ CNode* pPrev, 501 _In_opt_ CNode* pNext 502 ); 503 504 void FreeNode( 505 _Inout_ CNode* pNode 506 ); 507 508 CNode* GetFreeNode( 509 ); 510 511 }; 512 513 514 // 515 // CAtlist public methods 516 // 517 518 template<typename E, class ETraits> 519 CAtlList< E, ETraits >::CAtlList(_In_ UINT nBlockSize) : 520 m_Blocks(NULL), 521 m_BlockSize(nBlockSize), 522 m_HeadNode(NULL), 523 m_TailNode(NULL), 524 m_FreeNode(NULL), 525 m_NumElements(0) 526 { 527 ATLASSERT(nBlockSize > 0); 528 } 529 530 template<typename E, class ETraits> 531 CAtlList<E, ETraits >::~CAtlList(void) 532 { 533 RemoveAll(); 534 } 535 536 template<typename E, class ETraits> 537 inline size_t CAtlList< E, ETraits >::GetCount() const 538 { 539 return m_NumElements; 540 } 541 542 template<typename E, class ETraits> 543 inline bool CAtlList< E, ETraits >::IsEmpty() const 544 { 545 return (m_NumElements == 0); 546 } 547 548 template<typename E, class ETraits> 549 inline POSITION CAtlList<E, ETraits>::GetHeadPosition() const 550 { 551 return (POSITION)m_HeadNode; 552 } 553 554 template<typename E, class ETraits> 555 inline POSITION CAtlList<E, ETraits>::GetTailPosition() const 556 { 557 return (POSITION)m_TailNode; 558 } 559 560 template<typename E, class ETraits> 561 inline E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) 562 { 563 CNode* Node = (CNode*)pos; 564 pos = (POSITION)Node->m_Next; 565 return Node->m_Element; 566 } 567 568 template<typename E, class ETraits> 569 inline const E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) const 570 { 571 CNode* Node = (CNode*)pos; 572 pos = (POSITION)Node->m_Next; 573 return Node->m_Element; 574 } 575 576 template<typename E, class ETraits> 577 inline E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) 578 { 579 CNode* Node = (CNode*)pos; 580 pos = (POSITION)Node->m_Prev; 581 return Node->m_Element; 582 } 583 584 template<typename E, class ETraits> 585 inline const E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) const 586 { 587 CNode* Node = (CNode*)pos; 588 pos = (POSITION)Node->m_Prev; 589 return Node->m_Element; 590 } 591 592 template<typename E, class ETraits> 593 inline E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) 594 { 595 CNode* Node = (CNode*)pos; 596 return Node->m_Element; 597 } 598 599 template<typename E, class ETraits> 600 inline const E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) const 601 { 602 CNode* Node = (CNode*)pos; 603 return Node->m_Element; 604 } 605 606 template<typename E, class ETraits> 607 POSITION CAtlList<E, ETraits>::AddHead(INARGTYPE element) 608 { 609 CNode* Node = CreateNode(element, NULL, m_HeadNode); 610 if (m_HeadNode) 611 { 612 m_HeadNode->m_Prev = Node; 613 } 614 else 615 { 616 m_TailNode = Node; 617 } 618 m_HeadNode = Node; 619 620 return (POSITION)Node; 621 } 622 623 template<typename E, class ETraits> 624 POSITION CAtlList<E, ETraits>::AddTail(INARGTYPE element) 625 { 626 CNode* Node = CreateNode(element, m_TailNode, NULL); 627 if (m_TailNode) 628 { 629 m_TailNode->m_Next = Node; 630 } 631 else 632 { 633 m_HeadNode = Node; 634 } 635 m_TailNode = Node; 636 637 return (POSITION)Node; 638 } 639 640 template<typename E, class ETraits> 641 E CAtlList<E, ETraits>::RemoveHead() 642 { 643 CNode* Node = m_HeadNode; 644 E Element(Node->m_Element); 645 646 m_HeadNode = Node->m_Next; 647 if (m_HeadNode) 648 { 649 m_HeadNode->m_Prev = NULL; 650 } 651 else 652 { 653 m_TailNode = NULL; 654 } 655 FreeNode(Node); 656 657 return Element; 658 } 659 660 template<typename E, class ETraits> 661 E CAtlList<E, ETraits>::RemoveTail() 662 { 663 CNode* Node = m_TailNode; 664 E Element(Node->m_Element); 665 666 m_TailNode = Node->m_Prev; 667 if (m_TailNode) 668 { 669 m_TailNode->m_Next = NULL; 670 } 671 else 672 { 673 m_HeadNode = NULL; 674 } 675 FreeNode(Node); 676 677 return Element; 678 } 679 680 template<typename E, class ETraits> 681 POSITION CAtlList<E, ETraits >::InsertBefore(_In_ POSITION pos, _In_ INARGTYPE element) 682 { 683 if (pos == NULL) 684 return AddHead(element); 685 686 CNode* OldNode = (CNode*)pos; 687 CNode* Node = CreateNode(element, OldNode->m_Prev, OldNode); 688 689 if (OldNode->m_Prev != NULL) 690 { 691 OldNode->m_Prev->m_Next = Node; 692 } 693 else 694 { 695 m_HeadNode = Node; 696 } 697 OldNode->m_Prev = Node; 698 699 return (POSITION)Node; 700 } 701 702 template<typename E, class ETraits> 703 POSITION CAtlList<E, ETraits >::InsertAfter(_In_ POSITION pos, _In_ INARGTYPE element) 704 { 705 if (pos == NULL) 706 return AddTail(element); 707 708 CNode* OldNode = (CNode*)pos; 709 CNode* Node = CreateNode(element, OldNode, OldNode->m_Next); 710 711 if (OldNode->m_Next != NULL) 712 { 713 OldNode->m_Next->m_Prev = Node; 714 } 715 else 716 { 717 m_TailNode = Node; 718 } 719 OldNode->m_Next = Node; 720 721 return (POSITION)Node; 722 } 723 724 template<typename E, class ETraits> 725 void CAtlList<E, ETraits >::RemoveAll() 726 { 727 while (m_NumElements > 0) 728 { 729 CNode* Node = m_HeadNode; 730 m_HeadNode = m_HeadNode->m_Next; 731 FreeNode(Node); 732 } 733 734 m_HeadNode = NULL; 735 m_TailNode = NULL; 736 m_FreeNode = NULL; 737 738 if (m_Blocks) 739 { 740 m_Blocks->Destroy(); 741 m_Blocks = NULL; 742 } 743 } 744 745 template<typename E, class ETraits> 746 void CAtlList<E, ETraits >::RemoveAt(_In_ POSITION pos) 747 { 748 ATLASSERT(pos != NULL); 749 750 CNode* OldNode = (CNode*)pos; 751 if (OldNode == m_HeadNode) 752 { 753 m_HeadNode = OldNode->m_Next; 754 } 755 else 756 { 757 OldNode->m_Prev->m_Next = OldNode->m_Next; 758 } 759 if (OldNode == m_TailNode) 760 { 761 m_TailNode = OldNode->m_Prev; 762 } 763 else 764 { 765 OldNode->m_Next->m_Prev = OldNode->m_Prev; 766 } 767 FreeNode(OldNode); 768 } 769 770 template<typename E, class ETraits> 771 POSITION CAtlList< E, ETraits >::Find( 772 INARGTYPE element, 773 _In_opt_ POSITION posStartAfter) const 774 { 775 CNode* Node = (CNode*)posStartAfter; 776 if (Node == NULL) 777 { 778 Node = m_HeadNode; 779 } 780 else 781 { 782 Node = Node->m_Next; 783 } 784 785 for (; Node != NULL; Node = Node->m_Next) 786 { 787 if (ETraits::CompareElements(Node->m_Element, element)) 788 return (POSITION)Node; 789 } 790 791 return NULL; 792 } 793 794 template<typename E, class ETraits> 795 POSITION CAtlList< E, ETraits >::FindIndex(_In_ size_t iElement) const 796 { 797 if (iElement >= m_NumElements) 798 return NULL; 799 800 if (m_HeadNode == NULL) 801 return NULL; 802 803 CNode* Node = m_HeadNode; 804 for (size_t i = 0; i < iElement; i++) 805 { 806 Node = Node->m_Next; 807 } 808 809 return (POSITION)Node; 810 } 811 812 813 // 814 // CAtlist private methods 815 // 816 817 template<typename E, class ETraits> 818 typename CAtlList<E, ETraits>::CNode* CAtlList<E, ETraits>::CreateNode( 819 INARGTYPE element, 820 _In_opt_ CNode* Prev, 821 _In_opt_ CNode* Next 822 ) 823 { 824 GetFreeNode(); 825 826 CNode* NewNode = m_FreeNode; 827 CNode* NextFree = m_FreeNode->m_Next; 828 829 NewNode = new CNode(element); 830 831 m_FreeNode = NextFree; 832 NewNode->m_Prev = Prev; 833 NewNode->m_Next = Next; 834 m_NumElements++; 835 836 return NewNode; 837 } 838 839 template<typename E, class ETraits> 840 void CAtlList<E, ETraits>::FreeNode( 841 _Inout_ CNode* pNode 842 ) 843 { 844 pNode->~CNode(); 845 pNode->m_Next = m_FreeNode; 846 m_FreeNode = pNode; 847 848 m_NumElements--; 849 if (m_NumElements == 0) 850 { 851 RemoveAll(); 852 } 853 } 854 855 template<typename E, class ETraits> 856 typename CAtlList<E, ETraits>::CNode* CAtlList< E, ETraits>::GetFreeNode() 857 { 858 if (m_FreeNode) 859 { 860 return m_FreeNode; 861 } 862 863 CAtlPlex* Block = CAtlPlex::Create(m_Blocks, m_BlockSize, sizeof(CNode)); 864 if (Block == NULL) 865 { 866 AtlThrowImp(E_OUTOFMEMORY); 867 } 868 869 CNode* Node = (CNode*)Block->GetData(); 870 Node += (m_BlockSize - 1); 871 for (int i = m_BlockSize - 1; i >= 0; i--) 872 { 873 Node->m_Next = m_FreeNode; 874 m_FreeNode = Node; 875 Node--; 876 } 877 878 return m_FreeNode; 879 } 880 881 882 template<typename E, class Allocator = CCRTAllocator > 883 class CHeapPtrList : 884 public CAtlList<CHeapPtr<E, Allocator>, CHeapPtrElementTraits<E, Allocator> > 885 { 886 public: 887 CHeapPtrList(_In_ UINT nBlockSize = 10) : 888 CAtlList<CHeapPtr<E, Allocator>, CHeapPtrElementTraits<E, Allocator> >(nBlockSize) 889 { 890 } 891 892 private: 893 CHeapPtrList(const CHeapPtrList&); 894 CHeapPtrList& operator=(const CHeapPtrList*); 895 }; 896 897 898 } 899 900 #endif