VAObjectPool.cpp 6.27 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#include "VAObjectPool.h"

#include "VAReferenceableObject.h"
#include "VALog.h"

#include <ITACriticalSection.h>

#include <assert.h>
#include <set>

// Debugging-Messages
#define POOL_DEBUG_MESSAGES 0

// Wiederverwendung von Pool-Objekten unterbinden (nur new/delete)
#define POOL_NO_REUSE 0

// ObjectPool class
class CVAObjectPool : public IVAObjectPool {
public:
	// Konstruktor
	/**
	 * Erzeugt einen Pool mit der angegebenen Anzahl von Objekten.
	 * Der zweite Parameter legt die Vergrerung im Falle eines berlaufes fest.
	 *
	 * \param iInitialSize		Initiale Anzahl Objekte
	 * \param iDelta            Vergrerung wenn keine freien Objekte mehr
	 * \param pFactory			Factory zur Erzeugung der Pool-Objekte
	 * \param bDeleteFactory	bergebene Factory im Destruktor freigeben?
	 */
	CVAObjectPool(int iInitialSize, int iDelta, IVAPoolObjectFactory* pFactory, bool bDeleteFactory);

	// Destruktor
	virtual ~CVAObjectPool();

	// Namen setzen (frs Debugging)
	void SetName(const std::string& sName);

	// Zurcksetzen. Setzt alle Objekte auf unbenutzt. ndert die Pool-Gre nicht.
	void Reset();

	// Anzahl der freien Objekte zurckgeben
	int GetNumFree() const;

	// Anzahl der benutzten Objekte zurckgeben
	int GetNumUsed() const;

	// Anzahl der Objekte (insgesamt) zurckgeben
	int GetSize() const;

	// Anzahl der (freien) Objekte vergrern
	// (Rckgabe: Anzahl der erzeugten Elemente)
	int Grow(int iDelta);

	// Freies Objekt anfordern.
	// (Setzt den Referenzzhler des Objektes auf 1)
	CVAPoolObject* RequestObject();

private:
	// Alias Typen
	typedef std::set<CVAPoolObject*> ObjSet;
	typedef ObjSet::iterator ObjSetIt;
	typedef ObjSet::const_iterator ObjSetCit;

	std::string m_sName;
	int m_iDelta;
	IVAPoolObjectFactory* m_pFactory;
	bool m_bDeleteFactory;

	ITACriticalSection m_csLists;

	ObjSet m_sFree;  // Liste der freien Objekte
	ObjSet m_sUsed;  // Liste der sich in Benutzung befindlichen Objekte

	// Diese Methode darf nur von den Pool-Objekten aufgerufen werden,
	// wenn diese keine weiteren Referenzen mehr haben.
	void ReleaseObject(CVAPoolObject* pObject);

	friend class CVAPoolObject;
};


// -= Implementierung object pool =----------------------------------------------------------------

//! Factory method for ObjectPool interface
IVAObjectPool* IVAObjectPool::Create(int iInitialSize, int iDelta, IVAPoolObjectFactory* pFactory, bool bDeleteFactory) {
	return new CVAObjectPool(iInitialSize, iDelta, pFactory, bDeleteFactory);
}

CVAObjectPool::CVAObjectPool(int iInitialSize, int iDelta, IVAPoolObjectFactory* pFactory, bool bDeleteFactory)
	: m_iDelta(iDelta),
	m_pFactory(pFactory),
	m_bDeleteFactory(bDeleteFactory)
{
	// Objekte vorerzeugen
	Grow(iInitialSize);
}

CVAObjectPool::~CVAObjectPool() {
	ITACriticalSectionLock oLock(m_csLists);

	// Alle Objekte freigeben
	for (ObjSetIt it=m_sFree.begin(); it!=m_sFree.end(); ++it) delete (*it);
	for (ObjSetIt it=m_sUsed.begin(); it!=m_sUsed.end(); ++it) delete (*it);

	if (m_bDeleteFactory) delete m_pFactory;
};

void CVAObjectPool::SetName(const std::string& sName) {
	m_sName = sName;
}

void CVAObjectPool::Reset() {
	// Alle benutzten Objekte zurck in die Freiliste
	for (ObjSetIt it=m_sUsed.begin(); it!=m_sUsed.end(); ++it) {
		(*it)->ResetReferences();
		(*it)->PreRelease();
		m_sFree.insert(*it);
	}
	m_sUsed.clear();
}

int CVAObjectPool::GetNumFree() const {
	return (int) m_sFree.size(); 
}

int CVAObjectPool::GetNumUsed() const {
	return (int) m_sUsed.size(); 
}

int CVAObjectPool::GetSize() const { 
	return (int) (m_sFree.size() + m_sUsed.size()); 
}

int CVAObjectPool::Grow(int iDelta) {
	ITACriticalSectionLock oLock(m_csLists);

	for (int i=0; i<iDelta; i++) {
		CVAPoolObject* pObject = m_pFactory->CreatePoolObject();
		assert( pObject != nullptr );

		pObject->m_pParentPool = this;

		m_sFree.insert(pObject);
	}

	if( POOL_DEBUG_MESSAGES )
	{
		VA_VERBOSE( "VAObjectPool:" + m_sName, "Growing pool by " << iDelta << ".");
	}

	return iDelta;
}

CVAPoolObject* CVAObjectPool::RequestObject() {

#if (POOL_NO_REUSE==1)

	// Direkte Implementierung mit new-operator (keine Wiederverwendung). Nur zum Debuggen.
	CVAPoolObject* pObject = m_pFactory->CreatePoolObject();
	pObject->pParentPool = this;
	pObject->AddReference();
	pObject->PreRequest();

#else

	// Lock auf Listen erzwingen
	ITACriticalSectionLock oLock(m_csLists);

	// Standard-Implementierung (mit Wiederverwendung)
	if (m_sFree.empty()) Grow(m_iDelta);

	assert( !m_sFree.empty() );
	CVAPoolObject* pObject = *(m_sFree.begin());
	pObject->AddReference();

	m_sFree.erase(pObject);
	m_sUsed.insert(pObject);

	pObject->PreRequest();

#endif // POOL_NO_REUSE

#if (POOL_DEBUG_MESSAGES==1)
	VA_DEBUG_PRINTF("[CVAObjectPool \"%s\" 0x%08Xh] Requested object 0x%08Xh (%d free, %d used, %d total)\n", m_sName.c_str(), this, pObject, GetNumFree(), GetNumUsed(), GetSize());
#endif

	return pObject;
}

void CVAObjectPool::ReleaseObject(CVAPoolObject* pObject) {
	// Wichtig: ReleaseObjekt wird von den PoolObjekten aufrufen, wenn diese KEINE Referenzen mehr haben!
	assert( pObject->GetNumReferences() == 0 );

	pObject->PreRelease();

#if (POOL_NO_REUSE==1)

	// Direkte Implementierung mit delete-operator (keine Wiederverwendung). Nur zum Debuggen.
	delete pObject;

#else

	// Lock auf Listen erzwingen
	ITACriticalSectionLock oLock(m_csLists);

	// Standard-Implementierung (mit Wiederverwendung)

	// Keine Referenzen mehr => Objekt wieder freigeben

	// Sicherheitscheck: Rckgabe = Anzahl gelschter Objekte
	int nDeleted = (int) m_sUsed.erase(pObject);
	// TODO: Wichtig. Referenz-Management fr Container beim Reset handhaben
	// assert( nDeleted == 1 );
	m_sFree.insert(pObject);
#endif // POOL_NO_REUSE

#if (POOL_DEBUG_MESSAGES==1)
	VA_DEBUG_PRINTF("[CVAObjectPool \"%s\" 0x%08Xh] Released object 0x%08Xh (%d free, %d used, %d total)\n", m_sName.c_str(), this, pObject, GetNumFree(), GetNumUsed(), GetSize());
#endif
}

// -= Implementierung pool objects =------------------------------------------------------------

CVAPoolObject::CVAPoolObject()
: m_pParentPool(nullptr)
{

}

CVAPoolObject::~CVAPoolObject() {

}

234
235
236
237
int CVAPoolObject::RemoveReference() const
{
	const int iNumReferences = GetNumReferences();
	assert( iNumReferences >= 1 );
Jonas Stienen's avatar
Jonas Stienen committed
238
239
240
241
242

	int iRefs = CVAReferenceableObject::RemoveReference();
	if ((iRefs == 0) && m_pParentPool) m_pParentPool->ReleaseObject( const_cast<CVAPoolObject*>(this) );
	return iRefs;
}