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 | |