forked from nushoin/RTree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MemoryTest.cpp
256 lines (196 loc) · 7.22 KB
/
MemoryTest.cpp
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#include <stdio.h>
#include <memory.h>
#ifdef WIN32
#include <crtdbg.h>
#endif //WIN32
#include "RTree.h"
//
// MemoryTest.cpp
//
// This demonstrates a use of RTree
//
// Use CRT Debug facility to dump memory leaks on app exit
#ifdef WIN32
// These two are for MSVS 2005 security consciousness until safe std lib funcs are available
#pragma warning(disable : 4996) // Deprecated functions
#define _CRT_SECURE_NO_DEPRECATE // Allow old unsecure standard library functions, Disable some 'warning C4996 - function was deprecated'
// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef _DEBUG
#define SET_CRT_DEBUG_FIELD(a) \
_CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define CLEAR_CRT_DEBUG_FIELD(a) \
_CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define SET_CRT_DEBUG_FIELD(a) ((void) 0)
#define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif
#endif //WIN32
//
// Get a random float b/n two values
// The returned value is >= min && < max (exclusive of max)
// Note this is a low precision random value since it is generated from an int.
//
static float RandFloat(float a_min, float a_max)
{
const float ooMax = 1.0f / (float)RAND_MAX;
float retValue = ( (float)rand() * ooMax * (a_max - a_min) + a_min);
ASSERT(retValue >= a_min && retValue < a_max); // Paranoid check
return retValue;
}
/// Simplify handling of 3 dimensional coordinate
struct Vec3
{
/// Default constructor
Vec3() {}
/// Construct from three elements
Vec3(float a_x, float a_y, float a_z)
{
v[0] = a_x;
v[1] = a_y;
v[2] = a_z;
}
/// Add two vectors and return result
Vec3 operator+ (const Vec3& a_other) const
{
return Vec3(v[0] + a_other.v[0],
v[1] + a_other.v[1],
v[2] + a_other.v[2]);
}
float v[3]; ///< 3 float components for axes or dimensions
};
static bool BoxesIntersect(const Vec3& a_boxMinA, const Vec3& a_boxMaxA,
const Vec3& a_boxMinB, const Vec3& a_boxMaxB)
{
for(int axis=0; axis<3; ++axis)
{
if(a_boxMinA.v[axis] > a_boxMaxB.v[axis] ||
a_boxMaxA.v[axis] < a_boxMinB.v[axis])
{
return false;
}
}
return true;
}
/// A user type to test with, instead of a simple type such as an 'int'
struct SomeThing
{
SomeThing()
{
++s_outstandingAllocs;
}
~SomeThing()
{
--s_outstandingAllocs;
}
int m_creationCounter; ///< Just a number for identifying within test program
Vec3 m_min, m_max; ///< Minimal bounding rect, values must be known and constant in order to remove from RTree
static int s_outstandingAllocs; ///< Count how many outstanding objects remain
};
/// Init static
int SomeThing::s_outstandingAllocs = 0;
/// A callback function to obtain query results in this implementation
bool QueryResultCallback(SomeThing* a_data, void* a_context)
{
printf("search found %d\n", a_data->m_creationCounter);
return true;
}
int main(int argc, char* argv[])
{
const int NUM_OBJECTS = 40; // Number of objects in test set, must be > FRAC_OBJECTS for this test
const int FRAC_OBJECTS = 4;
const float MAX_WORLDSIZE = 10.0f;
const float FRAC_WORLDSIZE = MAX_WORLDSIZE / 2;
// typedef the RTree useage just for conveniance with iteration
typedef RTree<SomeThing*, float, 3> SomeThingTree;
ASSERT( NUM_OBJECTS > FRAC_OBJECTS );
int index; // general purpose counter, declared here because MSVC 6 is not ansi compliant with 'for' loops.
SomeThing* thingArray[NUM_OBJECTS * 2]; // Store objects in another container to test with, sized larger than we need
memset(thingArray, 0, sizeof(thingArray)); // Nullify array, size is known here
// Create intance of RTree
SomeThingTree tree;
// Add some nodes
int counter = 0;
for( index = 0; index < NUM_OBJECTS; ++index )
{
SomeThing* newThing = new SomeThing;
newThing->m_creationCounter = counter++;
newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE));
Vec3 extent = Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE));
newThing->m_max = newThing->m_min + extent;
thingArray[counter-1] = newThing;
tree.Insert(newThing->m_min.v, newThing->m_max.v, newThing);
printf("inserting %d\n", newThing->m_creationCounter);
}
printf("tree count = %d\n", tree.Count());
int numToDelete = NUM_OBJECTS / FRAC_OBJECTS;
int numToStep = FRAC_OBJECTS;
// Delete some nodes
for( index = 0; index < NUM_OBJECTS; index += numToStep )
{
SomeThing* curThing = thingArray[index];
if(curThing)
{
tree.Remove(curThing->m_min.v, curThing->m_max.v, curThing);
printf("removing %d\n", curThing->m_creationCounter);
delete curThing;
thingArray[index] = NULL;
}
}
printf("tree count = %d\n", tree.Count());
// Add some more nodes
for( index = 0; index < numToDelete; ++index )
{
SomeThing* newThing = new SomeThing;
newThing->m_creationCounter = counter++;
newThing->m_min = Vec3(RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE), RandFloat(-MAX_WORLDSIZE, MAX_WORLDSIZE));
Vec3 extent = Vec3(RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE), RandFloat(0, FRAC_WORLDSIZE));
newThing->m_max = newThing->m_min + extent;
thingArray[counter-1] = newThing;
tree.Insert(newThing->m_min.v, newThing->m_max.v, newThing);
printf("inserting %d\n", newThing->m_creationCounter);
}
printf("tree count = %d\n", tree.Count());
Vec3 searchMin(0,0,0);
Vec3 searchMax(FRAC_WORLDSIZE, FRAC_WORLDSIZE, FRAC_WORLDSIZE);
tree.Search(searchMin.v, searchMax.v, &QueryResultCallback, NULL);
// NOTE: Even better than just dumping text, it would be nice to render the
// tree contents and search result for visualization.
// List values. Iterator is NOT delete safe
SomeThingTree::Iterator it;
for( tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it) )
{
SomeThing* curThing = tree.GetAt(it);
if(BoxesIntersect(searchMin, searchMax, curThing->m_min, curThing->m_max))
{
printf("brute found %d\n", curThing->m_creationCounter);
}
}
// Delete our nodes, NOTE, we are NOT deleting the tree nodes, just our data
// of course the tree will now contain invalid pointers that must not be used any more.
for( tree.GetFirst(it); !tree.IsNull(it); tree.GetNext(it) )
{
SomeThing* removeElem = tree.GetAt(it);
if(removeElem)
{
printf("deleting %d\n", removeElem->m_creationCounter);
delete removeElem;
}
}
// Remove all contents (This would have happened automatically during destructor)
tree.RemoveAll();
if(SomeThing::s_outstandingAllocs > 0)
{
printf("Memory leak!\n");
printf("s_outstandingAllocs = %d\n", SomeThing::s_outstandingAllocs);
}
else
{
printf("No memory leaks detected by app\n");
}
#ifdef WIN32
// Use CRT Debug facility to dump memory leaks on app exit
SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
#endif //WIN32
return 0;
}