summaryrefslogtreecommitdiff
path: root/src/inc/memorypool.h
blob: 9ea524f1f26faf6e3a82d5234135ef5aeb8646be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.


#ifndef _MEMORYPOOL_
#define _MEMORYPOOL_

#include "daccess.h"
#include "contract.h"

//
// A MemoryPool is an allocator for a fixed size elements.
// Allocating and freeing elements from the pool is very cheap compared
// to a general allocator like new.  However, a MemoryPool is slightly
// more greedy - it preallocates a bunch of elements at a time, and NEVER
// RELEASES MEMORY FROM THE POOL ONCE IT IS ALLOCATED, (unless you call
// FreeAllElements.)
//
// It also has several additional features:
//	* you can free the entire pool of objects cheaply.
//	* you can test an object to see if it's an element of the pool.	
//

class MemoryPool
{
  public:

#ifndef DACCESS_COMPILE
	MemoryPool(SIZE_T elementSize, SIZE_T initGrowth = 20, SIZE_T initCount = 0);
#else
        MemoryPool() {}
#endif
	~MemoryPool() DAC_EMPTY();

	BOOL IsElement(void *element);
	BOOL IsAllocatedElement(void *element);
	void *AllocateElement();
	void *AllocateElementNoThrow();
	void FreeElement(void *element);
	void FreeAllElements();
        size_t GetSize();
  private:

	struct Element
	{
		Element *next;
#if _DEBUG
		int		deadBeef;
#endif
	};

	struct Block
	{
		Block	*next;
		Element *elementsEnd;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4200)
#endif
		Element elements[0];
#ifdef _MSC_VER
#pragma warning(pop)
#endif
	};

	SIZE_T m_elementSize;
	SIZE_T m_growCount;
	Block *m_blocks;
	Element *m_freeList;

	BOOL AddBlock(SIZE_T elementCount);
	void DeadBeef(Element *element);

 public:

	//
	// NOTE: You can currently only iterate the elements
	// if none have been freed.
	//

	class Iterator
    {
	private:
		Block	*m_next;
		BYTE	*m_e, *m_eEnd;
		BYTE	*m_end;
		SIZE_T	m_size;

	public:
		Iterator(MemoryPool *pool);

		BOOL Next();

		void *GetElement() {LIMITED_METHOD_CONTRACT;  return (void *) (m_e-m_size); }
	};

	friend class Iterator;
};

class MemoryPoolElementHolder
{
    protected:
        MemoryPool* m_pool;
        void* m_element;
        BOOL bRelease;
    public:
    void SuppressRelease()
    {
        LIMITED_METHOD_CONTRACT;
        _ASSERTE(bRelease);
        bRelease=false;
    }
    void Release()
    {
        LIMITED_METHOD_CONTRACT;
        _ASSERTE(bRelease);
        m_pool->FreeElement(m_element);
        bRelease=false;
    }
    MemoryPoolElementHolder(MemoryPool* pool, void* element)
    {
        LIMITED_METHOD_CONTRACT;
        m_pool=pool;
        m_element=element;
        bRelease=true;
    }

    ~MemoryPoolElementHolder()
    {
        LIMITED_METHOD_CONTRACT;
        if (bRelease)
            Release();
    }
    
    operator void* ()
    {
        LIMITED_METHOD_CONTRACT;
        return m_element;
    }
};

#endif // _MEMORYPOOL_