#ifndef __ATLCOLL_H__ #define __ATLCOLL_H__ #pragma once #include "atlbase.h" #include "atlexcept.h" // FIXME: We need to include for placement new, but that would mean everyone using atl // would also need to set the option 'WITH_STL'.. // For now we just copy the definition here, under a guard.. #ifndef _NEW inline void* operator new (size_t size, void* ptr) throw() { return ptr; } inline void operator delete (void* ptr, void* voidptr2) throw() { } #endif struct __POSITION { }; typedef __POSITION* POSITION; namespace ATL { class CAtlPlex { public: CAtlPlex* m_Next; #if (_AFX_PACKING >= 8) DWORD dwReserved[1]; #endif static inline CAtlPlex* Create( _Inout_ CAtlPlex*& Entry, _In_ size_t MaxElements, _In_ size_t ElementSize ) { CAtlPlex* Block; ATLASSERT(MaxElements > 0); ATLASSERT(ElementSize > 0); size_t BufferSize = sizeof(CAtlPlex) + (MaxElements * ElementSize); void *Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize); if (Buffer == NULL) return NULL; Block = static_cast< CAtlPlex* >(Buffer); Block->m_Next = Entry; Entry = Block; return Block; } void* GetData() { return (this + 1); } inline void Destroy() { CAtlPlex* Block; CAtlPlex* Next; Block = this; while (Block != NULL) { Next = Block->m_Next; HeapFree(GetProcessHeap(), 0, Block); Block = Next; } } }; template class CElementTraitsBase { public: typedef const T& INARGTYPE; typedef T& OUTARGTYPE; static void CopyElements( _Out_writes_all_(NumElements) T* Dest, _In_reads_(NumElements) const T* Source, _In_ size_t NumElements) { for (size_t i = 0; i < NumElements; i++) { Dest[i] = Source[i]; } } static void RelocateElements( _Out_writes_all_(NumElements) T* Dest, _In_reads_(NumElements) T* Source, _In_ size_t NumElements) { // A simple memmove works for most of the types. // You'll have to override this for types that have pointers to their // own members. #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif memmove(Dest, Source, NumElements * sizeof(T)); #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif } }; template class CDefaultCompareTraits { public: static bool CompareElements( _In_ const T& Val1, _In_ const T& Val2) { return (Val1 == Val2); } static int CompareElementsOrdered( _In_ const T& Val1, _In_ const T& Val2) { if (Val1 < Val2) { return -1; } else if (Val1 > Val2) { return 1; } return 0; // equal } }; template class CDefaultElementTraits : public CElementTraitsBase, public CDefaultCompareTraits { }; template class CElementTraits : public CDefaultElementTraits { }; template class CHeapPtrElementTraits : public CDefaultElementTraits< CHeapPtr > { public: typedef CHeapPtr& INARGTYPE; typedef T*& OUTARGTYPE; }; template > class CAtlArray { public: typedef typename ETraits::INARGTYPE INARGTYPE; typedef typename ETraits::OUTARGTYPE OUTARGTYPE; private: E* m_pData; size_t m_Size; size_t m_AllocatedSize; size_t m_GrowBy; #pragma push_macro("new") #undef new void CreateItems(E* pData, size_t Size) { for (size_t n = 0; n < Size; ++n) { ::new (pData + n) E; } } #pragma pop_macro("new") void DestructItems(E* pData, size_t Size) { for (size_t n = 0; n < Size; ++n) { pData[n].~E(); } } bool GrowAllocatedData(size_t nNewSize) { if (m_pData) { size_t addSize = m_GrowBy > 0 ? m_GrowBy : m_AllocatedSize / 2; size_t allocSize = m_AllocatedSize + addSize; if (allocSize < nNewSize) allocSize = nNewSize; E* pData = (E*)malloc(nNewSize * sizeof(E)); if (pData == NULL) { return false; } // Copy the objects over (default implementation will just move them without calling anything ETraits::RelocateElements(pData, m_pData, m_Size); free(m_pData); m_pData = pData; m_AllocatedSize = nNewSize; } else { // We need to allocate a new buffer size_t allocSize = m_GrowBy > nNewSize ? m_GrowBy : nNewSize; m_pData = (E*)malloc(allocSize * sizeof(E)); if (m_pData == NULL) { return false; } m_AllocatedSize = allocSize; } return true; } /* The CAtlArray class does not support construction by copy */ private: CAtlArray(_In_ const CAtlArray&); CAtlArray& operator=(_In_ const CAtlArray&); public: CAtlArray(); ~CAtlArray(); size_t Add(INARGTYPE element); size_t Add(); bool SetCount(size_t nNewSize, int nGrowBy = - 1); size_t GetCount() const; E& operator[](size_t ielement); const E& operator[](size_t ielement) const; E& GetAt(size_t iElement); const E& GetAt(size_t iElement) const; E* GetData(); const E* GetData() const; //FIXME: Most of this class is missing! }; // // CAtlArray public methods // template CAtlArray< E, ETraits >::CAtlArray() : m_pData(NULL) , m_Size(0) , m_AllocatedSize(0) , m_GrowBy(0) { } template CAtlArray< E, ETraits >::~CAtlArray() { // Destroy all items SetCount(0, -1); } #pragma push_macro("new") #undef new template size_t CAtlArray::Add(INARGTYPE element) { if (m_Size >= m_AllocatedSize) { if (!GrowAllocatedData(m_Size + 1)) { AtlThrow(E_OUTOFMEMORY); } } ::new (m_pData + m_Size) E(element); m_Size++; return m_Size - 1; } #pragma pop_macro("new") template size_t CAtlArray::Add() { if (!SetCount(m_Size + 1)) { AtlThrow(E_OUTOFMEMORY); } return m_Size - 1; } template bool CAtlArray::SetCount(size_t nNewSize, int nGrowBy /*= -1*/) { if (nGrowBy > -1) { m_GrowBy = (size_t)nGrowBy; } if (nNewSize == m_Size) { // Do nothing } else if (nNewSize == 0) { if (m_pData) { DestructItems(m_pData, m_Size); m_pData = NULL; } m_Size = m_AllocatedSize = NULL; } else if (nNewSize < m_AllocatedSize) { if (nNewSize > m_Size) { CreateItems(m_pData + m_Size, nNewSize - m_Size); } else { DestructItems(m_pData + nNewSize, m_Size - nNewSize); } m_Size = nNewSize; } else { if (!GrowAllocatedData(nNewSize)) { return false; } CreateItems(m_pData + m_Size, nNewSize - m_Size); m_Size = nNewSize; } return true; } template size_t CAtlArray::GetCount() const { return m_Size; } template E& CAtlArray::operator[](size_t iElement) { ATLASSERT(iElement < m_Size); return m_pData[iElement]; } template const E& CAtlArray::operator[](size_t iElement) const { ATLASSERT(iElement < m_Size); return m_pData[iElement]; } template E& CAtlArray::GetAt(size_t iElement) { ATLASSERT(iElement < m_Size); return m_pData[iElement]; } template const E& CAtlArray::GetAt(size_t iElement) const { ATLASSERT(iElement < m_Size); return m_pData[iElement]; } template E* CAtlArray::GetData() { return m_pData; } template const E* CAtlArray::GetData() const { return m_pData; } template > class CAtlList { private: typedef typename ETraits::INARGTYPE INARGTYPE; private: class CNode : public __POSITION { public: CNode* m_Next; CNode* m_Prev; E m_Element; public: CNode(INARGTYPE Element) : m_Element(Element) { } /* The CNode class does not support construction by copy */ private: CNode(_In_ const CNode&); CNode& operator=(_In_ const CNode&); }; private: CAtlPlex* m_Blocks; UINT m_BlockSize; CNode* m_HeadNode; CNode* m_TailNode; CNode* m_FreeNode; size_t m_NumElements; /* The CAtlList class does not support construction by copy */ private: CAtlList(_In_ const CAtlList&); CAtlList& operator=(_In_ const CAtlList&); public: CAtlList(_In_ UINT nBlockSize = 10); ~CAtlList(); size_t GetCount() const; bool IsEmpty() const; POSITION GetHeadPosition() const; POSITION GetTailPosition() const; E& GetNext(_Inout_ POSITION& pos); const E& GetNext(_Inout_ POSITION& pos) const; E& GetPrev(_Inout_ POSITION& pos); const E& GetPrev(_Inout_ POSITION& pos) const; E& GetAt(_In_ POSITION pos); const E& GetAt(_In_ POSITION pos) const; POSITION AddHead(INARGTYPE element); POSITION AddTail(INARGTYPE element); E RemoveHead(); E RemoveTail(); POSITION InsertBefore(_In_ POSITION pos, INARGTYPE element); POSITION InsertAfter(_In_ POSITION pos, INARGTYPE element); void RemoveAll(); void RemoveAt(_In_ POSITION pos); POSITION Find( INARGTYPE element, _In_opt_ POSITION posStartAfter = NULL) const; POSITION FindIndex(_In_ size_t iElement) const; private: CNode* CreateNode( INARGTYPE element, _In_opt_ CNode* pPrev, _In_opt_ CNode* pNext ); void FreeNode( _Inout_ CNode* pNode ); CNode* GetFreeNode( ); }; // // CAtlist public methods // template CAtlList< E, ETraits >::CAtlList(_In_ UINT nBlockSize) : m_Blocks(NULL), m_BlockSize(nBlockSize), m_HeadNode(NULL), m_TailNode(NULL), m_FreeNode(NULL), m_NumElements(0) { ATLASSERT(nBlockSize > 0); } template CAtlList::~CAtlList(void) { RemoveAll(); } template inline size_t CAtlList< E, ETraits >::GetCount() const { return m_NumElements; } template inline bool CAtlList< E, ETraits >::IsEmpty() const { return (m_NumElements == 0); } template inline POSITION CAtlList::GetHeadPosition() const { return (POSITION)m_HeadNode; } template inline POSITION CAtlList::GetTailPosition() const { return (POSITION)m_TailNode; } template inline E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) { CNode* Node = (CNode*)pos; pos = (POSITION)Node->m_Next; return Node->m_Element; } template inline const E& CAtlList< E, ETraits >::GetNext(_Inout_ POSITION& pos) const { CNode* Node = (CNode*)pos; pos = (POSITION)Node->m_Next; return Node->m_Element; } template inline E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) { CNode* Node = (CNode*)pos; pos = (POSITION)Node->m_Prev; return Node->m_Element; } template inline const E& CAtlList< E, ETraits >::GetPrev(_Inout_ POSITION& pos) const { CNode* Node = (CNode*)pos; pos = (POSITION)Node->m_Prev; return Node->m_Element; } template inline E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) { CNode* Node = (CNode*)pos; return Node->m_Element; } template inline const E& CAtlList< E, ETraits >::GetAt(_In_ POSITION pos) const { CNode* Node = (CNode*)pos; return Node->m_Element; } template POSITION CAtlList::AddHead(INARGTYPE element) { CNode* Node = CreateNode(element, NULL, m_HeadNode); if (m_HeadNode) { m_HeadNode->m_Prev = Node; } else { m_TailNode = Node; } m_HeadNode = Node; return (POSITION)Node; } template POSITION CAtlList::AddTail(INARGTYPE element) { CNode* Node = CreateNode(element, m_TailNode, NULL); if (m_TailNode) { m_TailNode->m_Next = Node; } else { m_HeadNode = Node; } m_TailNode = Node; return (POSITION)Node; } template E CAtlList::RemoveHead() { CNode* Node = m_HeadNode; E Element(Node->m_Element); m_HeadNode = Node->m_Next; if (m_HeadNode) { m_HeadNode->m_Prev = NULL; } else { m_TailNode = NULL; } FreeNode(Node); return Element; } template E CAtlList::RemoveTail() { CNode* Node = m_TailNode; E Element(Node->m_Element); m_TailNode = Node->m_Prev; if (m_TailNode) { m_TailNode->m_Next = NULL; } else { m_HeadNode = NULL; } FreeNode(Node); return Element; } template POSITION CAtlList::InsertBefore(_In_ POSITION pos, _In_ INARGTYPE element) { if (pos == NULL) return AddHead(element); CNode* OldNode = (CNode*)pos; CNode* Node = CreateNode(element, OldNode->m_Prev, OldNode); if (OldNode->m_Prev != NULL) { OldNode->m_Prev->m_Next = Node; } else { m_HeadNode = Node; } OldNode->m_Prev = Node; return (POSITION)Node; } template POSITION CAtlList::InsertAfter(_In_ POSITION pos, _In_ INARGTYPE element) { if (pos == NULL) return AddTail(element); CNode* OldNode = (CNode*)pos; CNode* Node = CreateNode(element, OldNode, OldNode->m_Next); if (OldNode->m_Next != NULL) { OldNode->m_Next->m_Prev = Node; } else { m_TailNode = Node; } OldNode->m_Next = Node; return (POSITION)Node; } template void CAtlList::RemoveAll() { while (m_NumElements > 0) { CNode* Node = m_HeadNode; m_HeadNode = m_HeadNode->m_Next; FreeNode(Node); } m_HeadNode = NULL; m_TailNode = NULL; m_FreeNode = NULL; if (m_Blocks) { m_Blocks->Destroy(); m_Blocks = NULL; } } template void CAtlList::RemoveAt(_In_ POSITION pos) { ATLASSERT(pos != NULL); CNode* OldNode = (CNode*)pos; if (OldNode == m_HeadNode) { m_HeadNode = OldNode->m_Next; } else { OldNode->m_Prev->m_Next = OldNode->m_Next; } if (OldNode == m_TailNode) { m_TailNode = OldNode->m_Prev; } else { OldNode->m_Next->m_Prev = OldNode->m_Prev; } FreeNode(OldNode); } template POSITION CAtlList< E, ETraits >::Find( INARGTYPE element, _In_opt_ POSITION posStartAfter) const { CNode* Node = (CNode*)posStartAfter; if (Node == NULL) { Node = m_HeadNode; } else { Node = Node->m_Next; } for (; Node != NULL; Node = Node->m_Next) { if (ETraits::CompareElements(Node->m_Element, element)) return (POSITION)Node; } return NULL; } template POSITION CAtlList< E, ETraits >::FindIndex(_In_ size_t iElement) const { if (iElement >= m_NumElements) return NULL; if (m_HeadNode == NULL) return NULL; CNode* Node = m_HeadNode; for (size_t i = 0; i < iElement; i++) { Node = Node->m_Next; } return (POSITION)Node; } // // CAtlist private methods // template typename CAtlList::CNode* CAtlList::CreateNode( INARGTYPE element, _In_opt_ CNode* Prev, _In_opt_ CNode* Next ) { GetFreeNode(); CNode* NewNode = m_FreeNode; CNode* NextFree = m_FreeNode->m_Next; NewNode = new CNode(element); m_FreeNode = NextFree; NewNode->m_Prev = Prev; NewNode->m_Next = Next; m_NumElements++; return NewNode; } template void CAtlList::FreeNode( _Inout_ CNode* pNode ) { pNode->~CNode(); pNode->m_Next = m_FreeNode; m_FreeNode = pNode; m_NumElements--; if (m_NumElements == 0) { RemoveAll(); } } template typename CAtlList::CNode* CAtlList< E, ETraits>::GetFreeNode() { if (m_FreeNode) { return m_FreeNode; } CAtlPlex* Block = CAtlPlex::Create(m_Blocks, m_BlockSize, sizeof(CNode)); if (Block == NULL) { AtlThrowImp(E_OUTOFMEMORY); } CNode* Node = (CNode*)Block->GetData(); Node += (m_BlockSize - 1); for (int i = m_BlockSize - 1; i >= 0; i--) { Node->m_Next = m_FreeNode; m_FreeNode = Node; Node--; } return m_FreeNode; } template class CHeapPtrList : public CAtlList, CHeapPtrElementTraits > { public: CHeapPtrList(_In_ UINT nBlockSize = 10) : CAtlList, CHeapPtrElementTraits >(nBlockSize) { } private: CHeapPtrList(const CHeapPtrList&); CHeapPtrList& operator=(const CHeapPtrList*); }; } #endif