| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | |
| 6 | #ifndef _MEMORYPOOL_ |
| 7 | #define _MEMORYPOOL_ |
| 8 | |
| 9 | #include "daccess.h" |
| 10 | #include "contract.h" |
| 11 | |
| 12 | // |
| 13 | // A MemoryPool is an allocator for a fixed size elements. |
| 14 | // Allocating and freeing elements from the pool is very cheap compared |
| 15 | // to a general allocator like new. However, a MemoryPool is slightly |
| 16 | // more greedy - it preallocates a bunch of elements at a time, and NEVER |
| 17 | // RELEASES MEMORY FROM THE POOL ONCE IT IS ALLOCATED, (unless you call |
| 18 | // FreeAllElements.) |
| 19 | // |
| 20 | // It also has several additional features: |
| 21 | // * you can free the entire pool of objects cheaply. |
| 22 | // * you can test an object to see if it's an element of the pool. |
| 23 | // |
| 24 | |
| 25 | class MemoryPool |
| 26 | { |
| 27 | public: |
| 28 | |
| 29 | #ifndef DACCESS_COMPILE |
| 30 | MemoryPool(SIZE_T elementSize, SIZE_T initGrowth = 20, SIZE_T initCount = 0); |
| 31 | #else |
| 32 | MemoryPool() {} |
| 33 | #endif |
| 34 | ~MemoryPool() DAC_EMPTY(); |
| 35 | |
| 36 | BOOL IsElement(void *element); |
| 37 | BOOL IsAllocatedElement(void *element); |
| 38 | void *AllocateElement(); |
| 39 | void *AllocateElementNoThrow(); |
| 40 | void FreeElement(void *element); |
| 41 | void FreeAllElements(); |
| 42 | size_t GetSize(); |
| 43 | private: |
| 44 | |
| 45 | struct Element |
| 46 | { |
| 47 | Element *next; |
| 48 | #if _DEBUG |
| 49 | int deadBeef; |
| 50 | #endif |
| 51 | }; |
| 52 | |
| 53 | struct Block |
| 54 | { |
| 55 | Block *next; |
| 56 | Element *elementsEnd; |
| 57 | #ifdef _MSC_VER |
| 58 | #pragma warning(push) |
| 59 | #pragma warning(disable:4200) |
| 60 | #endif |
| 61 | Element elements[0]; |
| 62 | #ifdef _MSC_VER |
| 63 | #pragma warning(pop) |
| 64 | #endif |
| 65 | }; |
| 66 | |
| 67 | SIZE_T m_elementSize; |
| 68 | SIZE_T m_growCount; |
| 69 | Block *m_blocks; |
| 70 | Element *m_freeList; |
| 71 | |
| 72 | BOOL AddBlock(SIZE_T elementCount); |
| 73 | void DeadBeef(Element *element); |
| 74 | |
| 75 | public: |
| 76 | |
| 77 | // |
| 78 | // NOTE: You can currently only iterate the elements |
| 79 | // if none have been freed. |
| 80 | // |
| 81 | |
| 82 | class Iterator |
| 83 | { |
| 84 | private: |
| 85 | Block *m_next; |
| 86 | BYTE *m_e, *m_eEnd; |
| 87 | BYTE *m_end; |
| 88 | SIZE_T m_size; |
| 89 | |
| 90 | public: |
| 91 | Iterator(MemoryPool *pool); |
| 92 | |
| 93 | BOOL Next(); |
| 94 | |
| 95 | void *GetElement() {LIMITED_METHOD_CONTRACT; return (void *) (m_e-m_size); } |
| 96 | }; |
| 97 | |
| 98 | friend class Iterator; |
| 99 | }; |
| 100 | |
| 101 | class MemoryPoolElementHolder |
| 102 | { |
| 103 | protected: |
| 104 | MemoryPool* m_pool; |
| 105 | void* m_element; |
| 106 | BOOL bRelease; |
| 107 | public: |
| 108 | void SuppressRelease() |
| 109 | { |
| 110 | LIMITED_METHOD_CONTRACT; |
| 111 | _ASSERTE(bRelease); |
| 112 | bRelease=false; |
| 113 | } |
| 114 | void Release() |
| 115 | { |
| 116 | LIMITED_METHOD_CONTRACT; |
| 117 | _ASSERTE(bRelease); |
| 118 | m_pool->FreeElement(m_element); |
| 119 | bRelease=false; |
| 120 | } |
| 121 | MemoryPoolElementHolder(MemoryPool* pool, void* element) |
| 122 | { |
| 123 | LIMITED_METHOD_CONTRACT; |
| 124 | m_pool=pool; |
| 125 | m_element=element; |
| 126 | bRelease=true; |
| 127 | } |
| 128 | |
| 129 | ~MemoryPoolElementHolder() |
| 130 | { |
| 131 | LIMITED_METHOD_CONTRACT; |
| 132 | if (bRelease) |
| 133 | Release(); |
| 134 | } |
| 135 | |
| 136 | operator void* () |
| 137 | { |
| 138 | LIMITED_METHOD_CONTRACT; |
| 139 | return m_element; |
| 140 | } |
| 141 | }; |
| 142 | |
| 143 | #endif // _MEMORYPOOL_ |
| 144 | |