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