... | ... |
@@ -4,18 +4,19 @@ |
4 | 4 |
#include <vector> |
5 | 5 |
|
6 | 6 |
// should only ever use this when copying a default constructed bucket |
7 |
-AtomBucket& AtomBucket::operator=(const AtomBucket& other) |
|
7 |
+// in the vector of buckets used in the allocator |
|
8 |
+/*AtomBucket& AtomBucket::operator=(const AtomBucket& other) |
|
8 | 9 |
{ |
9 |
- GAPS_ASSERT(!other.mFull); |
|
10 |
+ GAPS_ASSERT(other.mSize == 0); |
|
10 | 11 |
GAPS_ASSERT(other.mPrev == NULL); |
11 | 12 |
GAPS_ASSERT(other.mNext == NULL); |
12 | 13 |
GAPS_ASSERT(other.mOverflow == NULL); |
13 | 14 |
|
14 |
- mFull = false; |
|
15 |
+ mSize = 0; |
|
15 | 16 |
mPrev = NULL; |
16 | 17 |
mNext = NULL; |
17 | 18 |
mOverflow = NULL; |
18 |
-} |
|
19 |
+}*/ |
|
19 | 20 |
|
20 | 21 |
/////////////////////// ALLOCATOR FOR OVERFLOW BUCKETS ///////////////////////// |
21 | 22 |
|
... | ... |
@@ -130,61 +131,114 @@ bool AtomNeighborhood::hasRight() |
130 | 131 |
// cases are fast |
131 | 132 |
|
132 | 133 |
AtomBucket::AtomBucket() |
133 |
- : mFull(false), mOverflow(NULL), mPrev(NULL), mNext(NULL) |
|
134 |
+ : mSize(0), mOverflow(NULL), mPrev(NULL), mNext(NULL) |
|
134 | 135 |
{} |
135 | 136 |
|
136 | 137 |
unsigned AtomBucket::size() const |
137 | 138 |
{ |
138 |
- unsigned thisSize = mFull ? 1 : 0; |
|
139 |
- return mOverflow == NULL ? thisSize : thisSize + mOverflow->size(); |
|
139 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
140 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
141 |
+ |
|
142 |
+ return mOverflow == NULL ? mSize : mSize + mOverflow->size(); |
|
140 | 143 |
} |
141 | 144 |
|
142 | 145 |
bool AtomBucket::isEmpty() const |
143 | 146 |
{ |
144 |
- return !mFull; |
|
147 |
+ return mSize == 0; |
|
145 | 148 |
} |
146 | 149 |
|
147 | 150 |
bool AtomBucket::contains(uint64_t pos) const |
148 | 151 |
{ |
149 |
- if (mOverflow != NULL && pos > mBucket.pos) |
|
152 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
153 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
154 |
+ GAPS_ASSERT(pos > 0); |
|
155 |
+ |
|
156 |
+ if (mOverflow != NULL && !mOverflow->isEmpty() && pos > mBucket[1].pos) |
|
150 | 157 |
{ |
151 | 158 |
return mOverflow->contains(pos); |
152 | 159 |
} |
153 | 160 |
else |
154 | 161 |
{ |
155 |
- return mFull ? pos == mBucket.pos : false; |
|
162 |
+ switch (mSize) |
|
163 |
+ { |
|
164 |
+ case 0: |
|
165 |
+ return false; |
|
166 |
+ case 1: |
|
167 |
+ return mBucket[0].pos == pos; |
|
168 |
+ case 2: |
|
169 |
+ return mBucket[0].pos == pos || mBucket[1].pos == pos; |
|
170 |
+ } |
|
156 | 171 |
} |
157 | 172 |
} |
158 | 173 |
|
159 | 174 |
Atom* AtomBucket::operator[](unsigned index) |
160 | 175 |
{ |
161 |
- return index == 0 ? &mBucket : mOverflow->operator[](index - 1); |
|
176 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
177 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
178 |
+ GAPS_ASSERT(index < size()); |
|
179 |
+ |
|
180 |
+ if (index > 1) // must be overflowed |
|
181 |
+ { |
|
182 |
+ return mOverflow->operator[](index - 2); |
|
183 |
+ } |
|
184 |
+ return &(mBucket[index]); |
|
162 | 185 |
} |
163 | 186 |
|
164 | 187 |
void AtomBucket::insert(uint64_t pos, float mass) |
165 | 188 |
{ |
166 |
- if (!mFull) |
|
189 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
190 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
191 |
+ GAPS_ASSERT(pos > 0); |
|
192 |
+ |
|
193 |
+ if (mSize == 0) |
|
167 | 194 |
{ |
168 |
- mBucket = Atom(pos, mass); |
|
169 |
- mFull = true; |
|
195 |
+ mBucket[0] = Atom(pos, mass); |
|
196 |
+ ++mSize; |
|
197 |
+ } |
|
198 |
+ else if (mSize == 1) |
|
199 |
+ { |
|
200 |
+ if (pos < mBucket[0].pos) |
|
201 |
+ { |
|
202 |
+ mBucket[1] = mBucket[0]; |
|
203 |
+ mBucket[0] = Atom(pos, mass); |
|
204 |
+ } |
|
205 |
+ else |
|
206 |
+ { |
|
207 |
+ mBucket[1] = Atom(pos, mass); |
|
208 |
+ } |
|
209 |
+ ++mSize; |
|
170 | 210 |
} |
171 | 211 |
else |
172 | 212 |
{ |
213 |
+ // check if we need to allocate the overflow bucket |
|
173 | 214 |
if (mOverflow == NULL) |
174 | 215 |
{ |
175 | 216 |
mOverflow = createAtomBucket(); |
176 | 217 |
mOverflow->mPrev = this; |
177 | 218 |
mOverflow->mNext = mNext; |
178 | 219 |
} |
179 |
- |
|
180 |
- if (pos < mBucket.pos) |
|
220 |
+ else if (mOverflow->isEmpty()) |
|
181 | 221 |
{ |
182 |
- mOverflow->insert(mBucket.pos, mBucket.mass); |
|
183 |
- mBucket = Atom(pos, mass); |
|
222 |
+ mOverflow->mPrev = this; |
|
223 |
+ mOverflow->mNext = mNext; |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ // push correct atom into overflow bucket |
|
227 |
+ if (pos > mBucket[1].pos) |
|
228 |
+ { |
|
229 |
+ return mOverflow->insert(pos, mass); |
|
230 |
+ } |
|
231 |
+ mOverflow->insert(mBucket[1].pos, mBucket[1].mass); |
|
232 |
+ |
|
233 |
+ // if inserting in this bucket, find correct position |
|
234 |
+ if (pos < mBucket[0].pos) |
|
235 |
+ { |
|
236 |
+ mBucket[1] = mBucket[0]; |
|
237 |
+ mBucket[0] = Atom(pos, mass); |
|
184 | 238 |
} |
185 | 239 |
else |
186 | 240 |
{ |
187 |
- mOverflow->insert(pos, mass); |
|
241 |
+ mBucket[1] = Atom(pos, mass); |
|
188 | 242 |
} |
189 | 243 |
} |
190 | 244 |
} |
... | ... |
@@ -192,55 +246,100 @@ void AtomBucket::insert(uint64_t pos, float mass) |
192 | 246 |
// assumes pos is contained in this chain |
193 | 247 |
void AtomBucket::erase(uint64_t pos) |
194 | 248 |
{ |
249 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
250 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
251 |
+ GAPS_ASSERT(pos > 0); |
|
252 |
+ GAPS_ASSERT(mSize > 0); |
|
195 | 253 |
GAPS_ASSERT(contains(pos)); |
196 |
- if (mBucket.pos == pos) |
|
254 |
+ |
|
255 |
+ if (mSize == 1) |
|
197 | 256 |
{ |
257 |
+ connectAdjacent(); |
|
258 |
+ mSize = 0; |
|
259 |
+ } |
|
260 |
+ else if (mSize == 2) |
|
261 |
+ { |
|
262 |
+ // check if this position is in overflow bucket |
|
263 |
+ if (pos > mBucket[1].pos) |
|
264 |
+ { |
|
265 |
+ return mOverflow->erase(pos); |
|
266 |
+ } |
|
267 |
+ |
|
268 |
+ // shift top position down if needed |
|
269 |
+ if (mBucket[0].pos == pos) |
|
270 |
+ { |
|
271 |
+ mBucket[0] = mBucket[1]; |
|
272 |
+ } |
|
273 |
+ |
|
274 |
+ // pull first atom from overflow if it's there |
|
198 | 275 |
if (mOverflow != NULL && !mOverflow->isEmpty()) |
199 | 276 |
{ |
200 |
- mBucket = *(mOverflow->front()); |
|
277 |
+ mBucket[1] = *(mOverflow->front()); |
|
201 | 278 |
mOverflow->eraseFront(); |
202 | 279 |
} |
203 |
- else |
|
280 |
+ else // just delete atom at last position |
|
204 | 281 |
{ |
205 |
- mFull = false; |
|
206 |
- connectAdjacent(); |
|
282 |
+ --mSize; |
|
207 | 283 |
} |
208 | 284 |
} |
209 |
- else |
|
210 |
- { |
|
211 |
- mOverflow->erase(pos); |
|
212 |
- } |
|
213 | 285 |
} |
214 | 286 |
|
215 | 287 |
void AtomBucket::eraseFront() |
216 | 288 |
{ |
217 |
- if (mOverflow != NULL && !mOverflow->isEmpty()) |
|
289 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
290 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
291 |
+ |
|
292 |
+ GAPS_ASSERT(mSize > 0); |
|
293 |
+ |
|
294 |
+ if (mSize == 1) |
|
218 | 295 |
{ |
219 |
- mBucket = *(mOverflow->front()); |
|
220 |
- mOverflow->eraseFront(); |
|
296 |
+ connectAdjacent(); |
|
297 |
+ mSize = 0; |
|
221 | 298 |
} |
222 |
- else |
|
299 |
+ else if (mSize == 2) |
|
223 | 300 |
{ |
224 |
- mFull = false; |
|
225 |
- connectAdjacent(); |
|
301 |
+ mBucket[0] = mBucket[1]; |
|
302 |
+ |
|
303 |
+ // pull first atom from overflow if it's there |
|
304 |
+ if (mOverflow != NULL && !mOverflow->isEmpty()) |
|
305 |
+ { |
|
306 |
+ mBucket[1] = *(mOverflow->front()); |
|
307 |
+ mOverflow->eraseFront(); |
|
308 |
+ } |
|
309 |
+ else |
|
310 |
+ { |
|
311 |
+ --mSize; |
|
312 |
+ } |
|
226 | 313 |
} |
227 | 314 |
} |
228 | 315 |
|
229 | 316 |
AtomNeighborhood AtomBucket::getNeighbors(unsigned index) |
230 | 317 |
{ |
318 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
319 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
320 |
+ GAPS_ASSERT(index < size()); |
|
321 |
+ |
|
231 | 322 |
return AtomNeighborhood(getLeft(index), this->operator[](index), getRight(index)); |
232 | 323 |
} |
233 | 324 |
|
234 | 325 |
AtomNeighborhood AtomBucket::getRightNeighbor(unsigned index) |
235 | 326 |
{ |
327 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
328 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
329 |
+ GAPS_ASSERT(index < size()); |
|
330 |
+ |
|
236 | 331 |
return AtomNeighborhood(NULL, this->operator[](index), getRight(index)); |
237 | 332 |
} |
238 | 333 |
|
239 |
-// needs to propogate through overflow |
|
334 |
+// needs to propogate through overflow so that the last overflow will know |
|
335 |
+// where the next bucket is |
|
240 | 336 |
void AtomBucket::setRightAdjacentBucket(AtomBucket *bucket) |
241 | 337 |
{ |
338 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
339 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
340 |
+ |
|
242 | 341 |
mNext = bucket; |
243 |
- if (mOverflow != NULL) |
|
342 |
+ if (mOverflow != NULL && !mOverflow->isEmpty()) |
|
244 | 343 |
{ |
245 | 344 |
mOverflow->setRightAdjacentBucket(bucket); |
246 | 345 |
} |
... | ... |
@@ -248,12 +347,20 @@ void AtomBucket::setRightAdjacentBucket(AtomBucket *bucket) |
248 | 347 |
|
249 | 348 |
void AtomBucket::setLeftAdjacentBucket(AtomBucket *bucket) |
250 | 349 |
{ |
350 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
351 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
352 |
+ GAPS_ASSERT(bucket == NULL || !bucket->isEmpty()); |
|
353 |
+ |
|
251 | 354 |
mPrev = bucket; |
252 | 355 |
} |
253 | 356 |
|
254 | 357 |
void AtomBucket::connectAdjacent() |
255 | 358 |
{ |
256 |
- if (mNext != NULL) |
|
359 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
360 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
361 |
+ |
|
362 |
+ // be careful when connecting overflow buckets |
|
363 |
+ if (mNext != NULL && (mPrev == NULL || mPrev->mOverflow != this)) |
|
257 | 364 |
{ |
258 | 365 |
mNext->setLeftAdjacentBucket(mPrev); |
259 | 366 |
} |
... | ... |
@@ -261,61 +368,87 @@ void AtomBucket::connectAdjacent() |
261 | 368 |
{ |
262 | 369 |
mPrev->setRightAdjacentBucket(mNext); |
263 | 370 |
} |
371 |
+ |
|
372 |
+ mNext = NULL; |
|
373 |
+ mPrev = NULL; |
|
264 | 374 |
} |
265 | 375 |
|
266 | 376 |
Atom* AtomBucket::front() |
267 | 377 |
{ |
268 |
- return &mBucket; |
|
378 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
379 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
380 |
+ GAPS_ASSERT(mSize > 0); |
|
381 |
+ GAPS_ASSERT(mBucket[0].pos > 0); |
|
382 |
+ |
|
383 |
+ return &(mBucket[0]); |
|
269 | 384 |
} |
270 | 385 |
|
271 | 386 |
Atom* AtomBucket::back() |
272 | 387 |
{ |
388 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
389 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
390 |
+ GAPS_ASSERT(mSize > 0); |
|
391 |
+ |
|
273 | 392 |
if (mOverflow == NULL || (mOverflow != NULL && mOverflow->isEmpty())) |
274 | 393 |
{ |
275 |
- return &mBucket; |
|
394 |
+ return &(mBucket[mSize - 1]); |
|
276 | 395 |
} |
277 | 396 |
return mOverflow->back(); |
278 | 397 |
} |
279 | 398 |
|
280 | 399 |
Atom* AtomBucket::getLeft(unsigned index) |
281 | 400 |
{ |
401 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
402 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
403 |
+ GAPS_ASSERT(mSize > 0); |
|
404 |
+ GAPS_ASSERT(index < size()); |
|
405 |
+ |
|
282 | 406 |
if (index == 0) |
283 | 407 |
{ |
284 |
- return mPrev != NULL ? mPrev->back() : NULL; |
|
408 |
+ GAPS_ASSERT(mPrev == NULL || mPrev->mOverflow != this); |
|
409 |
+ return mPrev != NULL ? mPrev->back() : NULL; // mPrev can't be overflow here |
|
285 | 410 |
} |
286 |
- else if (index == 1) |
|
411 |
+ else if (index < 3) |
|
287 | 412 |
{ |
288 |
- return &mBucket; |
|
413 |
+ return &(mBucket[index - 1]); |
|
289 | 414 |
} |
290 | 415 |
else |
291 | 416 |
{ |
292 |
- return mOverflow->getLeft(index - 1); |
|
417 |
+ GAPS_ASSERT(mOverflow != NULL); |
|
418 |
+ return mOverflow->getLeft(index - 2); |
|
293 | 419 |
} |
294 | 420 |
} |
295 | 421 |
|
296 | 422 |
Atom* AtomBucket::getRight(unsigned index) |
297 | 423 |
{ |
298 |
- if (index == 0) |
|
424 |
+ GAPS_ASSERT(mPrev == NULL || !mPrev->isEmpty()); |
|
425 |
+ GAPS_ASSERT(mNext == NULL || !mNext->isEmpty()); |
|
426 |
+ GAPS_ASSERT(mSize > 0); |
|
427 |
+ GAPS_ASSERT(index < size()); |
|
428 |
+ |
|
429 |
+ if (index == mSize - 1) // this is last atom in bucket |
|
299 | 430 |
{ |
300 | 431 |
if (mOverflow != NULL && !mOverflow->isEmpty()) |
301 | 432 |
{ |
302 | 433 |
return mOverflow->front(); |
303 | 434 |
} |
304 |
- else |
|
305 |
- { |
|
306 |
- return mNext != NULL ? mNext->front() : NULL; |
|
307 |
- } |
|
435 |
+ return mNext != NULL ? mNext->front() : NULL; |
|
436 |
+ } |
|
437 |
+ else if (index == 0) |
|
438 |
+ { |
|
439 |
+ GAPS_ASSERT(mBucket[1].pos > 0); |
|
440 |
+ return &(mBucket[1]); |
|
308 | 441 |
} |
309 |
- else // must be overflowed |
|
442 |
+ else |
|
310 | 443 |
{ |
311 |
- return mOverflow->getRight(index - 1); |
|
444 |
+ mOverflow->getRight(index - 2); |
|
312 | 445 |
} |
313 | 446 |
} |
314 | 447 |
|
315 | 448 |
Archive& operator<<(Archive &ar, AtomBucket &b) |
316 | 449 |
{ |
317 | 450 |
bool hasOverflow = (b.mOverflow != NULL); |
318 |
- ar << b.mBucket << b.mFull << hasOverflow; |
|
451 |
+ ar << b.mBucket[0] << b.mBucket[1] << b.mSize << hasOverflow; |
|
319 | 452 |
|
320 | 453 |
if (hasOverflow) |
321 | 454 |
{ |
... | ... |
@@ -327,11 +460,11 @@ Archive& operator<<(Archive &ar, AtomBucket &b) |
327 | 460 |
Archive& operator>>(Archive& ar, AtomBucket &b) |
328 | 461 |
{ |
329 | 462 |
bool hasOverflow = false; |
330 |
- ar >> b.mBucket >> b.mFull >> hasOverflow; |
|
463 |
+ ar >> b.mBucket[0] >> b.mBucket[1] >> b.mSize >> hasOverflow; |
|
331 | 464 |
|
332 | 465 |
if (hasOverflow) |
333 | 466 |
{ |
334 |
- b.mOverflow = new AtomBucket(); |
|
467 |
+ b.mOverflow = createAtomBucket(); |
|
335 | 468 |
ar >> *b.mOverflow; |
336 | 469 |
} |
337 | 470 |
return ar; |
... | ... |
@@ -420,23 +553,25 @@ void AtomHashMap::insert(uint64_t pos, float mass) |
420 | 553 |
if (mHashMap[index].isEmpty()) |
421 | 554 |
{ |
422 | 555 |
mHashMap[index].insert(pos, mass); |
556 |
+ GAPS_ASSERT(mHashMap[index].contains(pos)); |
|
423 | 557 |
std::set<unsigned>::iterator it = mFullBuckets.insert(index).first; |
424 | 558 |
if (it != mFullBuckets.begin()) |
425 | 559 |
{ |
426 | 560 |
--it; |
427 |
- mHashMap[*it].setRightAdjacentBucket(&mHashMap[index]); |
|
428 | 561 |
mHashMap[index].setLeftAdjacentBucket(&mHashMap[*it]); |
562 |
+ mHashMap[*it].setRightAdjacentBucket(&mHashMap[index]); |
|
429 | 563 |
++it; |
430 | 564 |
} |
431 | 565 |
if (++it != mFullBuckets.end()) |
432 | 566 |
{ |
433 |
- mHashMap[*it].setLeftAdjacentBucket(&mHashMap[index]); |
|
434 | 567 |
mHashMap[index].setRightAdjacentBucket(&mHashMap[*it]); |
568 |
+ mHashMap[*it].setLeftAdjacentBucket(&mHashMap[index]); |
|
435 | 569 |
} |
436 | 570 |
} |
437 | 571 |
else |
438 | 572 |
{ |
439 | 573 |
mHashMap[index].insert(pos, mass); |
574 |
+ GAPS_ASSERT(mHashMap[index].contains(pos)); |
|
440 | 575 |
} |
441 | 576 |
GAPS_ASSERT(mHashMap[index].contains(pos)); |
442 | 577 |
|
... | ... |
@@ -55,9 +55,6 @@ public: |
55 | 55 |
void setRightAdjacentBucket(AtomBucket *bucket); |
56 | 56 |
void setLeftAdjacentBucket(AtomBucket *bucket); |
57 | 57 |
|
58 |
- AtomBucket& operator=(const AtomBucket& other); |
|
59 |
- |
|
60 |
- unsigned getIndex(uint64_t pos); |
|
61 | 58 |
Atom* getLeft(unsigned index); |
62 | 59 |
Atom* getRight(unsigned index); |
63 | 60 |
|
... | ... |
@@ -65,8 +62,8 @@ public: |
65 | 62 |
private: |
66 | 63 |
#endif |
67 | 64 |
|
68 |
- Atom mBucket; |
|
69 |
- bool mFull; |
|
65 |
+ Atom mBucket[2]; |
|
66 |
+ uint32_t mSize; |
|
70 | 67 |
|
71 | 68 |
AtomBucket *mOverflow; |
72 | 69 |
AtomBucket *mPrev; |
... | ... |
@@ -76,6 +73,8 @@ private: |
76 | 73 |
void connectAdjacent(); |
77 | 74 |
|
78 | 75 |
Atom* back(); |
76 |
+ |
|
77 |
+ AtomBucket& operator=(const AtomBucket& other); // prevent copies |
|
79 | 78 |
|
80 | 79 |
friend Archive& operator<<(Archive& ar, AtomBucket &b); |
81 | 80 |
friend Archive& operator>>(Archive& ar, AtomBucket &b); |
... | ... |
@@ -1 +1,655 @@ |
1 |
-// TODO |
|
2 | 1 |
\ No newline at end of file |
2 |
+#include "catch.h" |
|
3 |
+#include "../AtomicDomain.h" |
|
4 |
+#include "../GapsPrint.h" |
|
5 |
+ |
|
6 |
+// used to create aligned buckets for testing |
|
7 |
+AtomBucket* getAlignedBucket() |
|
8 |
+{ |
|
9 |
+ return new AtomBucket(); |
|
10 |
+} |
|
11 |
+ |
|
12 |
+TEST_CASE("AtomBucket") |
|
13 |
+{ |
|
14 |
+ GapsRng::setSeed(12345); |
|
15 |
+ |
|
16 |
+ SECTION("Properties of Default Constructed Buckets") |
|
17 |
+ { |
|
18 |
+ AtomBucket *bucket = getAlignedBucket(); |
|
19 |
+ REQUIRE(bucket->isEmpty()); |
|
20 |
+ REQUIRE(bucket->size() == 0); |
|
21 |
+ REQUIRE(!bucket->contains(1)); |
|
22 |
+ |
|
23 |
+ // verify internal state |
|
24 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
25 |
+ REQUIRE(bucket->mOverflow == NULL); |
|
26 |
+ #endif |
|
27 |
+ } |
|
28 |
+ |
|
29 |
+ SECTION("Insert") |
|
30 |
+ { |
|
31 |
+ AtomBucket *bucket = getAlignedBucket(); |
|
32 |
+ |
|
33 |
+ // insert first atom |
|
34 |
+ bucket->insert(1, 1.f); |
|
35 |
+ |
|
36 |
+ REQUIRE(!bucket->isEmpty()); |
|
37 |
+ REQUIRE(bucket->size() == 1); |
|
38 |
+ |
|
39 |
+ REQUIRE(bucket->contains(1)); |
|
40 |
+ REQUIRE(!bucket->contains(2)); |
|
41 |
+ REQUIRE(!bucket->contains(3)); |
|
42 |
+ |
|
43 |
+ REQUIRE(bucket->front()->pos == 1); |
|
44 |
+ REQUIRE(bucket->front()->mass == 1.f); |
|
45 |
+ REQUIRE((*bucket)[0]->pos == 1); |
|
46 |
+ REQUIRE((*bucket)[0]->mass == 1.f); |
|
47 |
+ |
|
48 |
+ // insert second atom |
|
49 |
+ bucket->insert(3, 3.f); |
|
50 |
+ |
|
51 |
+ REQUIRE(!bucket->isEmpty()); |
|
52 |
+ REQUIRE(bucket->size() == 2); |
|
53 |
+ |
|
54 |
+ REQUIRE(bucket->contains(1)); |
|
55 |
+ REQUIRE(!bucket->contains(2)); |
|
56 |
+ REQUIRE(bucket->contains(3)); |
|
57 |
+ |
|
58 |
+ REQUIRE(bucket->front()->pos == 1); |
|
59 |
+ REQUIRE(bucket->front()->mass == 1.f); |
|
60 |
+ REQUIRE((*bucket)[0]->pos == 1); |
|
61 |
+ REQUIRE((*bucket)[0]->mass == 1.f); |
|
62 |
+ REQUIRE((*bucket)[1]->pos == 3); |
|
63 |
+ REQUIRE((*bucket)[1]->mass == 3.f); |
|
64 |
+ |
|
65 |
+ // insert third atom |
|
66 |
+ bucket->insert(2, 2.f); |
|
67 |
+ |
|
68 |
+ REQUIRE(!bucket->isEmpty()); |
|
69 |
+ REQUIRE(bucket->size() == 3); |
|
70 |
+ |
|
71 |
+ REQUIRE(bucket->contains(1)); |
|
72 |
+ REQUIRE(bucket->contains(2)); |
|
73 |
+ REQUIRE(bucket->contains(3)); |
|
74 |
+ |
|
75 |
+ REQUIRE(bucket->front()->pos == 1); |
|
76 |
+ REQUIRE(bucket->front()->mass == 1.f); |
|
77 |
+ REQUIRE((*bucket)[0]->pos == 1); |
|
78 |
+ REQUIRE((*bucket)[0]->mass == 1.f); |
|
79 |
+ REQUIRE((*bucket)[1]->pos == 2); |
|
80 |
+ REQUIRE((*bucket)[1]->mass == 2.f); |
|
81 |
+ REQUIRE((*bucket)[2]->pos == 3); |
|
82 |
+ REQUIRE((*bucket)[2]->mass == 3.f); |
|
83 |
+ |
|
84 |
+ // verify internal state |
|
85 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
86 |
+ REQUIRE(bucket->mOverflow == NULL); |
|
87 |
+ REQUIRE(bucket->back()->pos == 3); |
|
88 |
+ REQUIRE(bucket->back()->mass == 3.f); |
|
89 |
+ REQUIRE(bucket->getLeft(1)->pos == 1); |
|
90 |
+ REQUIRE(bucket->getLeft(1)->mass == 1.f); |
|
91 |
+ REQUIRE(bucket->getRight(1)->pos == 3); |
|
92 |
+ REQUIRE(bucket->getRight(1)->mass == 3.f); |
|
93 |
+ #endif |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ SECTION("Erase") |
|
97 |
+ { |
|
98 |
+ AtomBucket *bucket = getAlignedBucket(); |
|
99 |
+ |
|
100 |
+ // erase one atom |
|
101 |
+ bucket->insert(1, 1.f); |
|
102 |
+ bucket->erase(1); |
|
103 |
+ REQUIRE(bucket->isEmpty()); |
|
104 |
+ REQUIRE(bucket->size() == 0); |
|
105 |
+ REQUIRE(!bucket->contains(1)); |
|
106 |
+ |
|
107 |
+ // erase two atoms |
|
108 |
+ bucket->insert(1, 1.f); |
|
109 |
+ bucket->insert(3, 3.f); |
|
110 |
+ |
|
111 |
+ bucket->erase(1); |
|
112 |
+ REQUIRE(!bucket->isEmpty()); |
|
113 |
+ REQUIRE(bucket->size() == 1); |
|
114 |
+ REQUIRE(!bucket->contains(1)); |
|
115 |
+ REQUIRE(bucket->contains(3)); |
|
116 |
+ REQUIRE(bucket->front()->pos == 3); |
|
117 |
+ REQUIRE((*bucket)[0]->pos == 3); |
|
118 |
+ bucket->insert(1, 1.f); |
|
119 |
+ |
|
120 |
+ bucket->erase(3); |
|
121 |
+ REQUIRE(!bucket->isEmpty()); |
|
122 |
+ REQUIRE(bucket->size() == 1); |
|
123 |
+ REQUIRE(bucket->contains(1)); |
|
124 |
+ REQUIRE(!bucket->contains(3)); |
|
125 |
+ REQUIRE(bucket->front()->pos == 1); |
|
126 |
+ REQUIRE((*bucket)[0]->pos == 1); |
|
127 |
+ bucket->insert(3, 3.f); |
|
128 |
+ |
|
129 |
+ bucket->erase(1); |
|
130 |
+ bucket->erase(3); |
|
131 |
+ REQUIRE(bucket->isEmpty()); |
|
132 |
+ REQUIRE(bucket->size() == 0); |
|
133 |
+ REQUIRE(!bucket->contains(1)); |
|
134 |
+ REQUIRE(!bucket->contains(3)); |
|
135 |
+ |
|
136 |
+ // erase three atoms |
|
137 |
+ bucket->insert(1, 1.f); |
|
138 |
+ bucket->insert(3, 3.f); |
|
139 |
+ bucket->insert(2, 2.f); |
|
140 |
+ |
|
141 |
+ bucket->erase(2); |
|
142 |
+ REQUIRE(!bucket->isEmpty()); |
|
143 |
+ REQUIRE(bucket->size() == 2); |
|
144 |
+ REQUIRE(!bucket->contains(2)); |
|
145 |
+ REQUIRE(bucket->contains(1)); |
|
146 |
+ REQUIRE(bucket->contains(3)); |
|
147 |
+ REQUIRE(bucket->front()->pos == 1); |
|
148 |
+ REQUIRE((*bucket)[0]->pos == 1); |
|
149 |
+ REQUIRE((*bucket)[1]->pos == 3); |
|
150 |
+ bucket->insert(2, 2.f); |
|
151 |
+ |
|
152 |
+ bucket->erase(1); |
|
153 |
+ bucket->erase(2); |
|
154 |
+ REQUIRE(!bucket->isEmpty()); |
|
155 |
+ REQUIRE(bucket->size() == 1); |
|
156 |
+ REQUIRE(!bucket->contains(1)); |
|
157 |
+ REQUIRE(!bucket->contains(2)); |
|
158 |
+ REQUIRE(bucket->contains(3)); |
|
159 |
+ REQUIRE(bucket->front()->pos == 3); |
|
160 |
+ REQUIRE((*bucket)[0]->pos == 3); |
|
161 |
+ bucket->insert(1, 1.f); |
|
162 |
+ bucket->insert(2, 2.f); |
|
163 |
+ |
|
164 |
+ bucket->erase(1); |
|
165 |
+ bucket->erase(2); |
|
166 |
+ bucket->erase(3); |
|
167 |
+ REQUIRE(bucket->isEmpty()); |
|
168 |
+ REQUIRE(bucket->size() == 0); |
|
169 |
+ REQUIRE(!bucket->contains(1)); |
|
170 |
+ REQUIRE(!bucket->contains(2)); |
|
171 |
+ REQUIRE(!bucket->contains(3)); |
|
172 |
+ |
|
173 |
+ // verify internal state |
|
174 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
175 |
+ REQUIRE(bucket->mOverflow == NULL); |
|
176 |
+ #endif |
|
177 |
+ } |
|
178 |
+ |
|
179 |
+ SECTION("Handling Overflow") |
|
180 |
+ { |
|
181 |
+ AtomBucket *bucket = getAlignedBucket(); |
|
182 |
+ |
|
183 |
+ // insert 1-100 at indices 0-99 (cant use 0 for position) |
|
184 |
+ for (unsigned i = 100; i > 0; --i) |
|
185 |
+ { |
|
186 |
+ bucket->insert(i, static_cast<float>(i)); |
|
187 |
+ } |
|
188 |
+ |
|
189 |
+ REQUIRE(!bucket->isEmpty()); |
|
190 |
+ REQUIRE(bucket->size() == 100); |
|
191 |
+ REQUIRE(bucket->contains(100)); |
|
192 |
+ REQUIRE(!bucket->contains(101)); |
|
193 |
+ REQUIRE(bucket->front()->pos == 1); |
|
194 |
+ |
|
195 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
196 |
+ for (unsigned i = 1; i < 99; ++i) |
|
197 |
+ { |
|
198 |
+ REQUIRE((*bucket)[i]->pos == i + 1); |
|
199 |
+ REQUIRE(bucket->contains(i + 1)); |
|
200 |
+ REQUIRE(bucket->getLeft(i)->pos == i); |
|
201 |
+ REQUIRE(bucket->getRight(i)->pos == i + 2); |
|
202 |
+ } |
|
203 |
+ |
|
204 |
+ REQUIRE(bucket->mOverflow != NULL); |
|
205 |
+ REQUIRE(boost::alignment::is_aligned(64, bucket->mOverflow)); |
|
206 |
+ REQUIRE(bucket->back()->pos == 100); |
|
207 |
+ #endif |
|
208 |
+ } |
|
209 |
+ |
|
210 |
+ SECTION("Special Overflow Case") |
|
211 |
+ { |
|
212 |
+ AtomBucket *bucket6 = getAlignedBucket(); |
|
213 |
+ bucket6->insert(1, 1.f); |
|
214 |
+ bucket6->insert(2, 2.f); |
|
215 |
+ bucket6->insert(3, 3.f); |
|
216 |
+ bucket6->insert(4, 4.f); |
|
217 |
+ bucket6->insert(5, 5.f); |
|
218 |
+ bucket6->insert(6, 6.f); |
|
219 |
+ bucket6->insert(7, 7.f); |
|
220 |
+ |
|
221 |
+ REQUIRE(bucket6->size() == 7); |
|
222 |
+ bucket6->erase(7); |
|
223 |
+ REQUIRE(bucket6->size() == 6); |
|
224 |
+ bucket6->erase(6); |
|
225 |
+ REQUIRE(bucket6->size() == 5); |
|
226 |
+ } |
|
227 |
+ |
|
228 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
229 |
+ SECTION("Traversing Adjacent Blocks") |
|
230 |
+ { |
|
231 |
+ // create buckets |
|
232 |
+ AtomBucket *first = getAlignedBucket(); |
|
233 |
+ AtomBucket *second = getAlignedBucket(); |
|
234 |
+ AtomBucket *third = getAlignedBucket(); |
|
235 |
+ |
|
236 |
+ // set up order |
|
237 |
+ first->setRightAdjacentBucket(second); |
|
238 |
+ second->setRightAdjacentBucket(third); |
|
239 |
+ |
|
240 |
+ third->setLeftAdjacentBucket(second); |
|
241 |
+ second->setLeftAdjacentBucket(first); |
|
242 |
+ |
|
243 |
+ // insert into all buckets |
|
244 |
+ for (unsigned i = 10; i <= 19; ++i) |
|
245 |
+ { |
|
246 |
+ first->insert(i, static_cast<float>(i)); |
|
247 |
+ } |
|
248 |
+ for (unsigned i = 20; i <= 29; ++i) |
|
249 |
+ { |
|
250 |
+ second->insert(i, static_cast<float>(i)); |
|
251 |
+ } |
|
252 |
+ for (unsigned i = 30; i <= 39; ++i) |
|
253 |
+ { |
|
254 |
+ third->insert(i, static_cast<float>(i)); |
|
255 |
+ } |
|
256 |
+ |
|
257 |
+ // check properties |
|
258 |
+ REQUIRE(!first->isEmpty()); |
|
259 |
+ REQUIRE(!second->isEmpty()); |
|
260 |
+ REQUIRE(!third->isEmpty()); |
|
261 |
+ REQUIRE(first->size() == 10); |
|
262 |
+ REQUIRE(second->size() == 10); |
|
263 |
+ REQUIRE(third->size() == 10); |
|
264 |
+ |
|
265 |
+ // get neighbors across boundaries |
|
266 |
+ REQUIRE(first->getRight(9)->pos == 20); |
|
267 |
+ REQUIRE(second->getRight(9)->pos == 30); |
|
268 |
+ |
|
269 |
+ REQUIRE(second->getLeft(0)->pos == 19); |
|
270 |
+ REQUIRE(third->getLeft(0)->pos == 29); |
|
271 |
+ |
|
272 |
+ // delete middle, get neighbors again |
|
273 |
+ second->connectAdjacent(); |
|
274 |
+ REQUIRE(first->getRight(9)->pos == 30); |
|
275 |
+ REQUIRE(third->getLeft(0)->pos == 19); |
|
276 |
+ } |
|
277 |
+ #endif |
|
278 |
+ |
|
279 |
+ SECTION("Querying Neighborhood") |
|
280 |
+ { |
|
281 |
+ // create buckets |
|
282 |
+ AtomBucket *first = getAlignedBucket(); |
|
283 |
+ AtomBucket *second = getAlignedBucket(); |
|
284 |
+ AtomBucket *third = getAlignedBucket(); |
|
285 |
+ |
|
286 |
+ // insert into all buckets |
|
287 |
+ for (unsigned i = 10; i <= 19; ++i) |
|
288 |
+ { |
|
289 |
+ first->insert(i, static_cast<float>(i)); |
|
290 |
+ } |
|
291 |
+ for (unsigned i = 20; i <= 29; ++i) |
|
292 |
+ { |
|
293 |
+ second->insert(i, static_cast<float>(i)); |
|
294 |
+ } |
|
295 |
+ for (unsigned i = 30; i <= 39; ++i) |
|
296 |
+ { |
|
297 |
+ third->insert(i, static_cast<float>(i)); |
|
298 |
+ } |
|
299 |
+ |
|
300 |
+ // set up order |
|
301 |
+ first->setRightAdjacentBucket(second); |
|
302 |
+ second->setRightAdjacentBucket(third); |
|
303 |
+ |
|
304 |
+ third->setLeftAdjacentBucket(second); |
|
305 |
+ second->setLeftAdjacentBucket(first); |
|
306 |
+ |
|
307 |
+ // get neighbors of border atoms |
|
308 |
+ REQUIRE(first->getNeighbors(9).left->pos == 18); |
|
309 |
+ REQUIRE(first->getNeighbors(9).center->pos == 19); |
|
310 |
+ REQUIRE(first->getNeighbors(9).right->pos == 20); |
|
311 |
+ REQUIRE(first->getRightNeighbor(9).center->pos == 19); |
|
312 |
+ REQUIRE(first->getRightNeighbor(9).right->pos == 20); |
|
313 |
+ |
|
314 |
+ REQUIRE(second->getNeighbors(9).left->pos == 28); |
|
315 |
+ REQUIRE(second->getNeighbors(9).center->pos == 29); |
|
316 |
+ REQUIRE(second->getNeighbors(9).right->pos == 30); |
|
317 |
+ REQUIRE(second->getRightNeighbor(9).center->pos == 29); |
|
318 |
+ REQUIRE(second->getRightNeighbor(9).right->pos == 30); |
|
319 |
+ |
|
320 |
+ REQUIRE(second->getNeighbors(0).left->pos == 19); |
|
321 |
+ REQUIRE(second->getNeighbors(0).center->pos == 20); |
|
322 |
+ REQUIRE(second->getNeighbors(0).right->pos == 21); |
|
323 |
+ REQUIRE(second->getRightNeighbor(0).center->pos == 20); |
|
324 |
+ REQUIRE(second->getRightNeighbor(0).right->pos == 21); |
|
325 |
+ |
|
326 |
+ REQUIRE(third->getNeighbors(0).left->pos == 29); |
|
327 |
+ REQUIRE(third->getNeighbors(0).center->pos == 30); |
|
328 |
+ REQUIRE(third->getNeighbors(0).right->pos == 31); |
|
329 |
+ REQUIRE(third->getRightNeighbor(0).center->pos == 30); |
|
330 |
+ REQUIRE(third->getRightNeighbor(0).right->pos == 31); |
|
331 |
+ |
|
332 |
+ // get neighbors of edge atoms (they shouldn't be there) |
|
333 |
+ AtomNeighborhood hood1 = first->getNeighbors(0); |
|
334 |
+ REQUIRE(!hood1.hasLeft()); |
|
335 |
+ REQUIRE(hood1.hasRight()); |
|
336 |
+ |
|
337 |
+ AtomNeighborhood hood3 = third->getNeighbors(9); |
|
338 |
+ REQUIRE(hood3.hasLeft()); |
|
339 |
+ REQUIRE(!hood3.hasRight()); |
|
340 |
+ |
|
341 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
342 |
+ // delete middle, get neighbors again |
|
343 |
+ second->connectAdjacent(); |
|
344 |
+ REQUIRE(first->getNeighbors(9).left->pos == 18); |
|
345 |
+ REQUIRE(first->getNeighbors(9).center->pos == 19); |
|
346 |
+ REQUIRE(first->getNeighbors(9).right->pos == 30); |
|
347 |
+ REQUIRE(first->getRightNeighbor(9).center->pos == 19); |
|
348 |
+ REQUIRE(first->getRightNeighbor(9).right->pos == 30); |
|
349 |
+ |
|
350 |
+ REQUIRE(third->getNeighbors(0).left->pos == 19); |
|
351 |
+ REQUIRE(third->getNeighbors(0).center->pos == 30); |
|
352 |
+ REQUIRE(third->getNeighbors(0).right->pos == 31); |
|
353 |
+ REQUIRE(third->getRightNeighbor(0).center->pos == 30); |
|
354 |
+ REQUIRE(third->getRightNeighbor(0).right->pos == 31); |
|
355 |
+ #endif |
|
356 |
+ } |
|
357 |
+} |
|
358 |
+ |
|
359 |
+TEST_CASE("AtomHashMap") |
|
360 |
+{ |
|
361 |
+ SECTION("Default Construction") |
|
362 |
+ { |
|
363 |
+ AtomHashMap map(100); |
|
364 |
+ REQUIRE(map.size() == 0); |
|
365 |
+ } |
|
366 |
+ |
|
367 |
+ SECTION("Length Calculation and Hashing") |
|
368 |
+ { |
|
369 |
+ // nice size |
|
370 |
+ AtomHashMap map(100); |
|
371 |
+ map.setTotalLength(1000); |
|
372 |
+ |
|
373 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
374 |
+ REQUIRE(map.mTotalLength == 1000); |
|
375 |
+ REQUIRE(map.mBucketLength == 10); |
|
376 |
+ |
|
377 |
+ REQUIRE(map.hash(1) == 0); |
|
378 |
+ REQUIRE(map.hash(9) == 0); |
|
379 |
+ REQUIRE(map.hash(10) == 1); |
|
380 |
+ REQUIRE(map.hash(19) == 1); |
|
381 |
+ REQUIRE(map.hash(20) == 2); |
|
382 |
+ REQUIRE(map.hash(1000) == 100); |
|
383 |
+ #endif |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ SECTION("Insert") |
|
387 |
+ { |
|
388 |
+ AtomHashMap map(100); |
|
389 |
+ map.setTotalLength(1000); |
|
390 |
+ |
|
391 |
+ map.insert(1, 1.f); |
|
392 |
+ REQUIRE(map.size() == 1); |
|
393 |
+ REQUIRE(map.contains(1)); |
|
394 |
+ REQUIRE(map.front()->pos == 1); |
|
395 |
+ |
|
396 |
+ map.insert(2, 3.f); |
|
397 |
+ map.insert(3, 3.f); |
|
398 |
+ REQUIRE(map.size() == 3); |
|
399 |
+ REQUIRE(map.contains(2)); |
|
400 |
+ REQUIRE(map.contains(3)); |
|
401 |
+ REQUIRE(map.front()->pos == 1); |
|
402 |
+ } |
|
403 |
+ |
|
404 |
+ SECTION("Erase") |
|
405 |
+ { |
|
406 |
+ AtomHashMap map(100); |
|
407 |
+ map.setTotalLength(1000); |
|
408 |
+ |
|
409 |
+ map.insert(1, 1.f); |
|
410 |
+ map.insert(2, 3.f); |
|
411 |
+ map.insert(3, 3.f); |
|
412 |
+ |
|
413 |
+ map.erase(1); |
|
414 |
+ REQUIRE(map.size() == 2); |
|
415 |
+ REQUIRE(!map.contains(1)); |
|
416 |
+ REQUIRE(map.contains(2)); |
|
417 |
+ REQUIRE(map.contains(3)); |
|
418 |
+ REQUIRE(map.front()->pos == 2); |
|
419 |
+ } |
|
420 |
+ |
|
421 |
+ #ifdef GAPS_INTERNAL_TESTS |
|
422 |
+ SECTION("Keeping Track of Full Buckets") |
|
423 |
+ { |
|
424 |
+ AtomHashMap map(100); |
|
425 |
+ map.setTotalLength(1000); |
|
426 |
+ |
|
427 |
+ map.insert(1, 1.f); |
|
428 |
+ REQUIRE(map.mFullBuckets.size() == 1); |
|
429 |
+ REQUIRE(map.mFullBuckets.count(0)); |
|
430 |
+ |
|
431 |
+ map.insert(2, 2.f); |
|
432 |
+ REQUIRE(map.mFullBuckets.size() == 1); |
|
433 |
+ |
|
434 |
+ map.insert(10, 10.f); |
|
435 |
+ REQUIRE(map.mFullBuckets.size() == 2); |
|
436 |
+ REQUIRE(map.mFullBuckets.count(1)); |
|
437 |
+ |
|
438 |
+ map.insert(20, 20.f); |
|
439 |
+ REQUIRE(map.mFullBuckets.size() == 3); |
|
440 |
+ REQUIRE(map.mFullBuckets.count(2)); |
|
441 |
+ |
|
442 |
+ map.erase(10); |
|
443 |
+ REQUIRE(map.mFullBuckets.size() == 2); |
|
444 |
+ REQUIRE(map.mFullBuckets.count(0)); |
|
445 |
+ REQUIRE(!map.mFullBuckets.count(1)); |
|
446 |
+ REQUIRE(map.mFullBuckets.count(2)); |
|
447 |
+ } |
|
448 |
+ |
|
449 |
+ SECTION("Keeping Track of Largest Bucket") |
|
450 |
+ { |
|
451 |
+ AtomHashMap map(100); |
|
452 |
+ map.setTotalLength(1000); |
|
453 |
+ |
|
454 |
+ for (unsigned i = 0; i < 9; ++i) |
|
455 |
+ { |
|
456 |
+ for (unsigned j = 1; j <= i + 1; ++j) |
|
457 |
+ { |
|
458 |
+ map.insert(10 * i + j, static_cast<float>(10 * i + j)); |
|
459 |
+ } |
|
460 |
+ REQUIRE(map.mWhichLongestBucket == i); |
|
461 |
+ REQUIRE(map.mLongestBucketSize == i + 1); |
|
462 |
+ } |
|
463 |
+ |
|
464 |
+ map.erase(89); |
|
465 |
+ REQUIRE(map.mLongestBucketSize == 8); |
|
466 |
+ |
|
467 |
+ map.erase(88); |
|
468 |
+ map.erase(78); |
|
469 |
+ REQUIRE(map.mLongestBucketSize == 7); |
|
470 |
+ |
|
471 |
+ map.erase(87); |
|
472 |
+ map.erase(77); |
|
473 |
+ map.erase(67); |
|
474 |
+ REQUIRE(map.mLongestBucketSize == 6); |
|
475 |
+ |
|
476 |
+ map.erase(86); |
|
477 |
+ map.erase(76); |
|
478 |
+ map.erase(66); |
|
479 |
+ map.erase(56); |
|
480 |
+ REQUIRE(map.mLongestBucketSize == 5); |
|
481 |
+ |
|
482 |
+ map.erase(85); |
|
483 |
+ map.erase(75); |
|
484 |
+ map.erase(65); |
|
485 |
+ map.erase(55); |
|
486 |
+ map.erase(45); |
|
487 |
+ REQUIRE(map.mLongestBucketSize == 4); |
|
488 |
+ } |
|
489 |
+ |
|
490 |
+ SECTION("Random Index Selection") |
|
491 |
+ { |
|
492 |
+ // create has map |
|
493 |
+ AtomHashMap map(100); |
|
494 |
+ map.setTotalLength(1000); |
|
495 |
+ |
|
496 |
+ for (unsigned i = 0; i < 9; ++i) |
|
497 |
+ { |
|
498 |
+ for (unsigned j = 1; j <= i + 1; ++j) |
|
499 |
+ { |
|
500 |
+ map.insert(10 * i + j, static_cast<float>(10 * i + j)); |
|
501 |
+ } |
|
502 |
+ REQUIRE(map.mWhichLongestBucket == i); |
|
503 |
+ REQUIRE(map.mLongestBucketSize == i + 1); |
|
504 |
+ } |
|
505 |
+ |
|
506 |
+ // all buckets should be selected uniformly |
|
507 |
+ unsigned counts[9] = {0}; |
|
508 |
+ for (unsigned i = 0; i < 45000; ++i) |
|
509 |
+ { |
|
510 |
+ HashMapIndex index = map.getRandomIndex(); |
|
511 |
+ counts[index.bucket]++; |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ for (unsigned i = 0; i < 9; ++i) |
|
515 |
+ { |
|
516 |
+ gaps_printf("bucket histogram: %d %d\n", i, counts[i]); |
|
517 |
+ REQUIRE(counts[i] > 950 * (i + 1)); |
|
518 |
+ REQUIRE(counts[i] < 1050 * (i + 1)); |
|
519 |
+ } |
|
520 |
+ |
|
521 |
+ // all positions should be selected uniformly |
|
522 |
+ unsigned largestBucket[9] = {0}; |
|
523 |
+ for (unsigned i = 0; i < 45000; ++i) |
|
524 |
+ { |
|
525 |
+ HashMapIndex index = map.getRandomIndex(); |
|
526 |
+ if (index.bucket == 8) |
|
527 |
+ { |
|
528 |
+ largestBucket[index.index]++; |
|
529 |
+ } |
|
530 |
+ } |
|
531 |
+ |
|
532 |
+ for (unsigned i = 0; i < 9; ++i) |
|
533 |
+ { |
|
534 |
+ gaps_printf("position histogram: %d %d\n", i, largestBucket[i]); |
|
535 |
+ REQUIRE(largestBucket[i] > 950); |
|
536 |
+ REQUIRE(largestBucket[i] < 1050); |
|
537 |
+ } |
|
538 |
+ } |
|
539 |
+ |
|
540 |
+ SECTION("Maintaining Adjacent Buckets") |
|
541 |
+ { |
|
542 |
+ AtomHashMap map(100); |
|
543 |
+ map.setTotalLength(1000); |
|
544 |
+ |
|
545 |
+ map.insert(1, 1.f); |
|
546 |
+ map.insert(9, 9.f); |
|
547 |
+ map.insert(10, 10.f); |
|
548 |
+ map.insert(19, 19.f); |
|
549 |
+ map.insert(20, 20.f); |
|
550 |
+ map.insert(29, 29.f); |
|
551 |
+ |
|
552 |
+ REQUIRE(map.mHashMap[0].getRight(1)->pos == 10); |
|
553 |
+ REQUIRE(map.mHashMap[1].getLeft(0)->pos == 9); |
|
554 |
+ |
|
555 |
+ REQUIRE(map.mHashMap[1].getRight(1)->pos == 20); |
|
556 |
+ REQUIRE(map.mHashMap[2].getLeft(0)->pos == 19); |
|
557 |
+ |
|
558 |
+ map.erase(10); |
|
559 |
+ map.erase(19); |
|
560 |
+ |
|
561 |
+ REQUIRE(map.mHashMap[0].getRight(1)->pos == 20); |
|
562 |
+ REQUIRE(map.mHashMap[2].getLeft(0)->pos == 9); |
|
563 |
+ } |
|
564 |
+ #endif |
|
565 |
+ |
|
566 |
+ SECTION("Random Atom Selection") |
|
567 |
+ { |
|
568 |
+ // create hash map |
|
569 |
+ AtomHashMap map(100); |
|
570 |
+ map.setTotalLength(1000); |
|
571 |
+ |
|
572 |
+ // average entry equal to 57 |
|
573 |
+ for (unsigned i = 0; i < 9; ++i) |
|
574 |
+ { |
|
575 |
+ for (unsigned j = 1; j <= i + 1; ++j) |
|
576 |
+ { |
|
577 |
+ map.insert(10 * i + j, static_cast<float>(10 * i + j)); |
|
578 |
+ } |
|
579 |
+ } |
|
580 |
+ |
|
581 |
+ // random selection of single atom |
|
582 |
+ float sum = 0.f; |
|
583 |
+ for (unsigned i = 0; i < 1000; ++i) |
|
584 |
+ { |
|
585 |
+ REQUIRE(map.randomAtom()->pos >= 1ull); |
|
586 |
+ REQUIRE(map.randomAtom()->pos <= 89ull); |
|
587 |
+ REQUIRE(map.randomAtom()->mass >= 1.f); |
|
588 |
+ REQUIRE(map.randomAtom()->mass <= 89.f); |
|
589 |
+ sum += map.randomAtom()->mass; |
|
590 |
+ } |
|
591 |
+ REQUIRE(sum > 0.95f * 57000.f); |
|
592 |
+ REQUIRE(sum < 1.05f * 57000.f); |
|
593 |
+ |
|
594 |
+ // random selection of atom and right neighbor |
|
595 |
+ sum = 0.f; |
|
596 |
+ for (unsigned i = 0; i < 1000; ++i) |
|
597 |
+ { |
|
598 |
+ AtomNeighborhood hood = map.randomAtomWithRightNeighbor(); |
|
599 |
+ REQUIRE(hood.center->pos >= 1ull); |
|
600 |
+ REQUIRE(hood.center->pos <= 89ull); |
|
601 |
+ REQUIRE(hood.center->mass >= 1.f); |
|
602 |
+ REQUIRE(hood.center->mass <= 89.f); |
|
603 |
+ sum += hood.center->mass; |
|
604 |
+ |
|
605 |
+ REQUIRE(!hood.hasLeft()); |
|
606 |
+ if (!hood.hasRight()) |
|
607 |
+ { |
|
608 |
+ REQUIRE(hood.center->pos == 89); |
|
609 |
+ } |
|
610 |
+ else |
|
611 |
+ { |
|
612 |
+ REQUIRE(hood.right->pos > hood.center->pos); |
|
613 |
+ REQUIRE(hood.right->mass > hood.center->mass); |
|
614 |
+ REQUIRE(hood.right->pos - hood.center->pos <= 10); |
|
615 |
+ } |
|
616 |
+ } |
|
617 |
+ REQUIRE(sum > 0.95f * 57000.f); |
|
618 |
+ REQUIRE(sum < 1.05f * 57000.f); |
|
619 |
+ |
|
620 |
+ // random selection of atom and both neighbors |
|
621 |
+ sum = 0.f; |
|
622 |
+ for (unsigned i = 0; i < 1000; ++i) |
|
623 |
+ { |
|
624 |
+ AtomNeighborhood hood = map.randomAtomWithNeighbors(); |
|
625 |
+ REQUIRE(hood.center->pos >= 1ull); |
|
626 |
+ REQUIRE(hood.center->pos <= 89ull); |
|
627 |
+ REQUIRE(hood.center->mass >= 1.f); |
|
628 |
+ REQUIRE(hood.center->mass <= 89.f); |
|
629 |
+ sum += hood.center->mass; |
|
630 |
+ |
|
631 |
+ if (!hood.hasLeft()) |
|
632 |
+ { |
|
633 |
+ REQUIRE(hood.center->pos == 1); |
|
634 |
+ } |
|
635 |
+ else |
|
636 |
+ { |
|
637 |
+ REQUIRE(hood.center->pos > hood.left->pos); |
|
638 |
+ REQUIRE(hood.center->mass > hood.left->mass); |
|
639 |
+ REQUIRE(hood.center->pos - hood.left->pos <= 10); |
|
640 |
+ } |
|
641 |
+ |
|
642 |
+ if (!hood.hasRight()) |
|
643 |
+ { |
|
644 |
+ REQUIRE(hood.center->pos == 89); |
|
645 |
+ } |
|
646 |
+ else |
|
647 |
+ { |
|
648 |
+ REQUIRE(hood.right->pos > hood.center->pos); |
|
649 |
+ REQUIRE(hood.right->mass > hood.center->mass); |
|
650 |
+ REQUIRE(hood.right->pos - hood.center->pos <= 10); |
|
651 |
+ } |
|
652 |
+ } |
|
653 |
+ REQUIRE(sum > 0.95f * 57000.f); |
|
654 |
+ REQUIRE(sum < 1.05f * 57000.f); |
|
655 |
+ } |
|
656 |
+} |
|
3 | 657 |
\ No newline at end of file |