Replace std::set by Set and fix issues with List and Map
This commit is contained in:
parent
220057a587
commit
b3e771838d
|
@ -199,6 +199,7 @@ SET (REACTPHYSICS3D_SOURCES
|
|||
"src/containers/LinkedList.h"
|
||||
"src/containers/List.h"
|
||||
"src/containers/Map.h"
|
||||
"src/containers/Set.h"
|
||||
)
|
||||
|
||||
# Create the library
|
||||
|
|
|
@ -37,20 +37,19 @@
|
|||
#include "collision/OverlapCallback.h"
|
||||
#include <cassert>
|
||||
#include <complex>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <utility>
|
||||
#include <unordered_set>
|
||||
|
||||
// We want to use the ReactPhysics3D namespace
|
||||
using namespace reactphysics3d;
|
||||
using namespace std;
|
||||
|
||||
|
||||
// Constructor
|
||||
CollisionDetection::CollisionDetection(CollisionWorld* world, MemoryManager& memoryManager)
|
||||
: mMemoryManager(memoryManager), mWorld(world), mNarrowPhaseInfoList(nullptr),
|
||||
mOverlappingPairs(mMemoryManager.getPoolAllocator()), mBroadPhaseAlgorithm(*this),
|
||||
mIsCollisionShapesAdded(false) {
|
||||
mNoCollisionPairs(mMemoryManager.getPoolAllocator()), mIsCollisionShapesAdded(false) {
|
||||
|
||||
// Set the default collision dispatch configuration
|
||||
setCollisionDispatch(&mDefaultCollisionDispatch);
|
||||
|
@ -127,14 +126,11 @@ void CollisionDetection::computeMiddlePhase() {
|
|||
// overlapping pair
|
||||
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||
|
||||
Map<OverlappingPair::OverlappingPairId, OverlappingPair*>::Iterator itToRemove = it;
|
||||
++it;
|
||||
|
||||
// Destroy the overlapping pair
|
||||
itToRemove->second->~OverlappingPair();
|
||||
it->second->~OverlappingPair();
|
||||
|
||||
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, itToRemove->second, sizeof(OverlappingPair));
|
||||
mOverlappingPairs.remove(itToRemove);
|
||||
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, it->second, sizeof(OverlappingPair));
|
||||
it = mOverlappingPairs.remove(it);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
@ -155,7 +151,7 @@ void CollisionDetection::computeMiddlePhase() {
|
|||
|
||||
// Check if the bodies are in the set of bodies that cannot collide between each other
|
||||
bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2);
|
||||
if (mNoCollisionPairs.count(bodiesIndex) > 0) continue;
|
||||
if (mNoCollisionPairs.contains(bodiesIndex) > 0) continue;
|
||||
|
||||
bool isShape1Convex = shape1->getCollisionShape()->isConvex();
|
||||
bool isShape2Convex = shape2->getCollisionShape()->isConvex();
|
||||
|
@ -349,15 +345,13 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) {
|
|||
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
|
||||
if (it->second->getShape1()->mBroadPhaseID == proxyShape->mBroadPhaseID||
|
||||
it->second->getShape2()->mBroadPhaseID == proxyShape->mBroadPhaseID) {
|
||||
Map<OverlappingPair::OverlappingPairId, OverlappingPair*>::Iterator itToRemove = it;
|
||||
++it;
|
||||
|
||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
||||
|
||||
// Destroy the overlapping pair
|
||||
itToRemove->second->~OverlappingPair();
|
||||
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, itToRemove->second, sizeof(OverlappingPair));
|
||||
mOverlappingPairs.remove(itToRemove);
|
||||
it->second->~OverlappingPair();
|
||||
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, it->second, sizeof(OverlappingPair));
|
||||
it = mOverlappingPairs.remove(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
|
@ -521,7 +515,7 @@ void CollisionDetection::testAABBOverlap(const AABB& aabb, OverlapCallback* over
|
|||
unsigned short categoryMaskBits) {
|
||||
assert(overlapCallback != nullptr);
|
||||
|
||||
std::unordered_set<bodyindex> reportedBodies;
|
||||
Set<bodyindex> reportedBodies(mMemoryManager.getPoolAllocator());
|
||||
|
||||
// Ask the broad-phase to get all the overlapping shapes
|
||||
LinkedList<int> overlappingNodes(mMemoryManager.getPoolAllocator());
|
||||
|
@ -544,7 +538,7 @@ void CollisionDetection::testAABBOverlap(const AABB& aabb, OverlapCallback* over
|
|||
if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) {
|
||||
|
||||
// Add the body into the set of reported bodies
|
||||
reportedBodies.insert(overlapBody->getID());
|
||||
reportedBodies.add(overlapBody->getID());
|
||||
|
||||
// Notify the overlap to the user
|
||||
overlapCallback->notifyOverlap(overlapBody);
|
||||
|
@ -637,7 +631,7 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
|||
|
||||
assert(overlapCallback != nullptr);
|
||||
|
||||
std::unordered_set<bodyindex> reportedBodies;
|
||||
Set<bodyindex> reportedBodies(mMemoryManager.getPoolAllocator());
|
||||
|
||||
// For each proxy shape proxy shape of the body
|
||||
ProxyShape* bodyProxyShape = body->getProxyShapesList();
|
||||
|
@ -717,7 +711,7 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
|||
CollisionBody* overlapBody = proxyShape->getBody();
|
||||
|
||||
// Add the body into the set of reported bodies
|
||||
reportedBodies.insert(overlapBody->getID());
|
||||
reportedBodies.add(overlapBody->getID());
|
||||
|
||||
// Notify the overlap to the user
|
||||
overlapCallback->notifyOverlap(overlapBody);
|
||||
|
|
|
@ -35,9 +35,26 @@
|
|||
#include "memory/MemoryManager.h"
|
||||
#include "constraint/ContactPoint.h"
|
||||
#include "containers/Map.h"
|
||||
#include <set>
|
||||
#include "containers/Set.h"
|
||||
#include <utility>
|
||||
|
||||
// Hash function for struct VerticesPair
|
||||
// TOOD : REMOVE THIS
|
||||
namespace std {
|
||||
|
||||
template <> struct hash<reactphysics3d::bodyindexpair> {
|
||||
|
||||
size_t operator()(const reactphysics3d::bodyindexpair& pair) const {
|
||||
|
||||
std::size_t seed = 0;
|
||||
reactphysics3d::hash_combine<reactphysics3d::bodyindex>(seed, pair.first);
|
||||
reactphysics3d::hash_combine<reactphysics3d::bodyindex>(seed, pair.second);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// ReactPhysics3D namespace
|
||||
namespace reactphysics3d {
|
||||
|
||||
|
@ -88,9 +105,8 @@ class CollisionDetection {
|
|||
// TODO : Delete this
|
||||
GJKAlgorithm mNarrowPhaseGJKAlgorithm;
|
||||
|
||||
// TODO : Maybe delete this set (what is the purpose ?)
|
||||
/// Set of pair of bodies that cannot collide between each other
|
||||
std::set<bodyindexpair> mNoCollisionPairs;
|
||||
Set<bodyindexpair> mNoCollisionPairs;
|
||||
|
||||
/// True if some collision shapes have been added previously
|
||||
bool mIsCollisionShapesAdded;
|
||||
|
@ -263,13 +279,13 @@ inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape,
|
|||
// Add a pair of bodies that cannot collide with each other
|
||||
inline void CollisionDetection::addNoCollisionPair(CollisionBody* body1,
|
||||
CollisionBody* body2) {
|
||||
mNoCollisionPairs.insert(OverlappingPair::computeBodiesIndexPair(body1, body2));
|
||||
mNoCollisionPairs.add(OverlappingPair::computeBodiesIndexPair(body1, body2));
|
||||
}
|
||||
|
||||
// Remove a pair of bodies that cannot collide with each other
|
||||
inline void CollisionDetection::removeNoCollisionPair(CollisionBody* body1,
|
||||
CollisionBody* body2) {
|
||||
mNoCollisionPairs.erase(OverlappingPair::computeBodiesIndexPair(body1, body2));
|
||||
mNoCollisionPairs.remove(OverlappingPair::computeBodiesIndexPair(body1, body2));
|
||||
}
|
||||
|
||||
// Ask for a collision shape to be tested again during broad-phase.
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "collision/TriangleMesh.h"
|
||||
#include "collision/PolyhedronMesh.h"
|
||||
#include "collision/narrowphase/GJK/GJKAlgorithm.h"
|
||||
#include <set>
|
||||
|
||||
/// ReactPhysics3D namespace
|
||||
namespace reactphysics3d {
|
||||
|
|
|
@ -154,6 +154,9 @@ class List {
|
|||
return !(*this == iterator);
|
||||
}
|
||||
|
||||
/// Frienship
|
||||
friend class List;
|
||||
|
||||
};
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
@ -227,8 +230,35 @@ class List {
|
|||
mSize++;
|
||||
}
|
||||
|
||||
/// Remove an element from the list at a given index
|
||||
void remove(uint index) {
|
||||
/// Try to find a given item of the list and return an iterator
|
||||
/// pointing to that element if it exists in the list. Otherwise,
|
||||
/// this method returns the end() iterator
|
||||
Iterator find(const T& element) {
|
||||
|
||||
for (uint i=0; i<mSize; i++) {
|
||||
if (element == static_cast<T*>(mBuffer)[i]) {
|
||||
return Iterator(mBuffer, i, mSize);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
/// Look for an element in the list and remove it
|
||||
Iterator remove(const T& element) {
|
||||
return remove(find(element));
|
||||
}
|
||||
|
||||
/// Remove an element from the list and return a iterator
|
||||
/// pointing to the element after the removed one (or end() if none)
|
||||
Iterator remove(const Iterator& it) {
|
||||
assert(it.mBuffer == mBuffer);
|
||||
return removeAt(it.mCurrentIndex);
|
||||
}
|
||||
|
||||
/// Remove an element from the list at a given index and return an
|
||||
/// iterator pointing to the element after the removed one (or end() if none)
|
||||
Iterator removeAt(uint index) {
|
||||
|
||||
assert(index >= 0 && index < mSize);
|
||||
|
||||
|
@ -244,6 +274,9 @@ class List {
|
|||
char* src = dest + sizeof(T);
|
||||
std::memcpy(static_cast<void*>(dest), static_cast<void*>(src), (mSize - index) * sizeof(T));
|
||||
}
|
||||
|
||||
// Return an iterator pointing to the element after the removed one
|
||||
return Iterator(mBuffer, index, mSize);
|
||||
}
|
||||
|
||||
/// Append another list at the end of the current one
|
||||
|
|
|
@ -39,7 +39,8 @@ namespace reactphysics3d {
|
|||
|
||||
// Class Map
|
||||
/**
|
||||
* This class represents a simple generic associative map
|
||||
* This class represents a simple generic associative map. This map is
|
||||
* implemented with a hash table.
|
||||
*/
|
||||
template<typename K, typename V>
|
||||
class Map {
|
||||
|
@ -60,9 +61,9 @@ class Map {
|
|||
}
|
||||
|
||||
/// Constructor
|
||||
Entry(size_t hashcode, int nextValue) {
|
||||
Entry(size_t hashcode, int nextEntry) {
|
||||
hashCode = hashcode;
|
||||
next = nextValue;
|
||||
next = nextEntry;
|
||||
keyValue = nullptr;
|
||||
}
|
||||
|
||||
|
@ -230,7 +231,7 @@ class Map {
|
|||
// If elements have been allocated
|
||||
if (mCapacity > 0) {
|
||||
|
||||
// Clear the list
|
||||
// Clear the map
|
||||
clear();
|
||||
|
||||
// Destroy the entries
|
||||
|
@ -320,7 +321,7 @@ class Map {
|
|||
reference operator*() const {
|
||||
assert(mCurrentEntry >= 0 && mCurrentEntry < mNbUsedEntries);
|
||||
assert(mEntries[mCurrentEntry].keyValue != nullptr);
|
||||
return mEntries[mCurrentEntry].keyValue;
|
||||
return *(mEntries[mCurrentEntry].keyValue);
|
||||
}
|
||||
|
||||
/// Deferencable
|
||||
|
@ -497,14 +498,18 @@ class Map {
|
|||
}
|
||||
|
||||
/// Remove the element pointed by some iterator
|
||||
bool remove(const Iterator& it) {
|
||||
/// This method returns an iterator pointing to the element after
|
||||
/// the one that has been removed
|
||||
Iterator remove(const Iterator& it) {
|
||||
|
||||
const K& key = it->first;
|
||||
return remove(key);
|
||||
}
|
||||
|
||||
/// Remove the element from the map with a given key
|
||||
bool remove(const K& key) {
|
||||
/// This method returns an iterator pointing to the element after
|
||||
/// the one that has been removed
|
||||
Iterator remove(const K& key) {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
|
||||
|
@ -533,15 +538,27 @@ class Map {
|
|||
mFreeIndex = i;
|
||||
mNbFreeEntries++;
|
||||
|
||||
return true;
|
||||
// Find the next entry to return the iterator
|
||||
for (i += 1; i < mNbUsedEntries; i++) {
|
||||
|
||||
// If the entry is not empty
|
||||
if (mEntries[i].keyValue != nullptr) {
|
||||
|
||||
// We have found the next non empty entry
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, i);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// Return the end iterator
|
||||
return end();
|
||||
}
|
||||
|
||||
/// Clear the list
|
||||
/// Clear the map
|
||||
void clear() {
|
||||
|
||||
if (mNbUsedEntries > 0) {
|
||||
|
|
264
src/containers/Pair.h
Normal file
264
src/containers/Pair.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
/********************************************************************************
|
||||
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||
*********************************************************************************
|
||||
* *
|
||||
* This software is provided 'as-is', without any express or implied warranty. *
|
||||
* In no event will the authors be held liable for any damages arising from the *
|
||||
* use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute it *
|
||||
* freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||
* that you wrote the original software. If you use this software in a *
|
||||
* product, an acknowledgment in the product documentation would be *
|
||||
* appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||
* misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source distribution. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef REACTPHYSICS3D_PAIR_H
|
||||
#define REACTPHYSICS3D_PAIR_H
|
||||
|
||||
// Libraries
|
||||
#include "configuration.h"
|
||||
#include "memory/MemoryAllocator.h"
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
namespace reactphysics3d {
|
||||
|
||||
// Class Pair
|
||||
/**
|
||||
* This class represents a simple generic pair
|
||||
*/
|
||||
template<typename T1, typename T2>
|
||||
class Pair {
|
||||
|
||||
public:
|
||||
|
||||
// -------------------- Attributes -------------------- //
|
||||
|
||||
/// First element of the pair
|
||||
T1 first;
|
||||
|
||||
/// Second element of the pair
|
||||
T2 second;
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
/// Constructor
|
||||
List(MemoryAllocator& allocator, size_t capacity = 0)
|
||||
: mBuffer(nullptr), mSize(0), mCapacity(0), mAllocator(allocator) {
|
||||
|
||||
if (capacity > 0) {
|
||||
|
||||
// Allocate memory
|
||||
reserve(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
List(const List<T>& list) : mBuffer(nullptr), mSize(0), mCapacity(0), mAllocator(list.mAllocator) {
|
||||
|
||||
// All all the elements of the list to the current one
|
||||
addRange(list);
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~List() {
|
||||
|
||||
// If elements have been allocated
|
||||
if (mCapacity > 0) {
|
||||
|
||||
// Clear the list
|
||||
clear();
|
||||
|
||||
// Release the memory allocated on the heap
|
||||
mAllocator.release(mBuffer, mCapacity * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate memory for a given number of elements
|
||||
void reserve(size_t capacity) {
|
||||
|
||||
if (capacity <= mCapacity) return;
|
||||
|
||||
// Allocate memory for the new array
|
||||
void* newMemory = mAllocator.allocate(capacity * sizeof(T));
|
||||
|
||||
if (mBuffer != nullptr) {
|
||||
|
||||
// Copy the elements to the new allocated memory location
|
||||
std::memcpy(newMemory, mBuffer, mSize * sizeof(T));
|
||||
|
||||
// Release the previously allocated memory
|
||||
mAllocator.release(mBuffer, mCapacity * sizeof(T));
|
||||
}
|
||||
|
||||
mBuffer = newMemory;
|
||||
assert(mBuffer != nullptr);
|
||||
|
||||
mCapacity = capacity;
|
||||
}
|
||||
|
||||
/// Add an element into the list
|
||||
void add(const T& element) {
|
||||
|
||||
// If we need to allocate more memory
|
||||
if (mSize == mCapacity) {
|
||||
reserve(mCapacity == 0 ? 1 : mCapacity * 2);
|
||||
}
|
||||
|
||||
// Use the copy-constructor to construct the element
|
||||
new (static_cast<char*>(mBuffer) + mSize * sizeof(T)) T(element);
|
||||
|
||||
mSize++;
|
||||
}
|
||||
|
||||
/// Try to find a given item of the list and return an iterator
|
||||
/// pointing to that element if it exists in the list. Otherwise,
|
||||
/// this method returns the end() iterator
|
||||
Iterator find(const T& element) {
|
||||
|
||||
for (uint i=0; i<mSize; i++) {
|
||||
if (element == *(static_cast<T*>(mBuffer)[i])) {
|
||||
return Iterator(mBuffer, i, mSize);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
/// Remove an element from the list
|
||||
void remove(const Iterator& it) {
|
||||
assert(it.mBuffer == mBuffer);
|
||||
remove(it.mCurrentIndex);
|
||||
}
|
||||
|
||||
/// Remove an element from the list at a given index
|
||||
void remove(uint index) {
|
||||
|
||||
assert(index >= 0 && index < mSize);
|
||||
|
||||
// Call the destructor
|
||||
(static_cast<T*>(mBuffer)[index]).~T();
|
||||
|
||||
mSize--;
|
||||
|
||||
if (index != mSize) {
|
||||
|
||||
// Move the elements to fill in the empty slot
|
||||
char* dest = static_cast<char*>(mBuffer) + index * sizeof(T);
|
||||
char* src = dest + sizeof(T);
|
||||
std::memcpy(static_cast<void*>(dest), static_cast<void*>(src), (mSize - index) * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
/// Append another list at the end of the current one
|
||||
void addRange(const List<T>& list) {
|
||||
|
||||
// If we need to allocate more memory
|
||||
if (mSize + list.size() > mCapacity) {
|
||||
|
||||
// Allocate memory
|
||||
reserve(mSize + list.size());
|
||||
}
|
||||
|
||||
// Add the elements of the list to the current one
|
||||
for(uint i=0; i<list.size(); i++) {
|
||||
|
||||
new (static_cast<char*>(mBuffer) + mSize * sizeof(T)) T(list[i]);
|
||||
mSize++;
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the list
|
||||
void clear() {
|
||||
|
||||
// Call the destructor of each element
|
||||
for (uint i=0; i < mSize; i++) {
|
||||
(static_cast<T*>(mBuffer)[i]).~T();
|
||||
}
|
||||
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
/// Return the number of elements in the list
|
||||
size_t size() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
/// Return the capacity of the list
|
||||
size_t capacity() const {
|
||||
return mCapacity;
|
||||
}
|
||||
|
||||
/// Overloaded index operator
|
||||
T& operator[](const uint index) {
|
||||
assert(index >= 0 && index < mSize);
|
||||
return (static_cast<T*>(mBuffer)[index]);
|
||||
}
|
||||
|
||||
/// Overloaded const index operator
|
||||
const T& operator[](const uint index) const {
|
||||
assert(index >= 0 && index < mSize);
|
||||
return (static_cast<T*>(mBuffer)[index]);
|
||||
}
|
||||
|
||||
/// Overloaded equality operator
|
||||
bool operator==(const List<T>& list) const {
|
||||
|
||||
if (mSize != list.mSize) return false;
|
||||
|
||||
T* items = static_cast<T*>(mBuffer);
|
||||
for (int i=0; i < mSize; i++) {
|
||||
if (items[i] != list[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Overloaded not equal operator
|
||||
bool operator!=(const List<T>& list) const {
|
||||
|
||||
return !((*this) == list);
|
||||
}
|
||||
|
||||
/// Overloaded assignment operator
|
||||
List<T>& operator=(const List<T>& list) {
|
||||
|
||||
if (this != &list) {
|
||||
|
||||
// Clear all the elements
|
||||
clear();
|
||||
|
||||
// Add all the elements of the list to the current one
|
||||
addRange(list);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a begin iterator
|
||||
Iterator begin() const {
|
||||
return Iterator(mBuffer, 0, mSize);
|
||||
}
|
||||
|
||||
/// Return a end iterator
|
||||
Iterator end() const {
|
||||
return Iterator(mBuffer, mSize, mSize);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
712
src/containers/Set.h
Normal file
712
src/containers/Set.h
Normal file
|
@ -0,0 +1,712 @@
|
|||
/********************************************************************************
|
||||
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||
*********************************************************************************
|
||||
* *
|
||||
* This software is provided 'as-is', without any express or implied warranty. *
|
||||
* In no event will the authors be held liable for any damages arising from the *
|
||||
* use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute it *
|
||||
* freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||
* that you wrote the original software. If you use this software in a *
|
||||
* product, an acknowledgment in the product documentation would be *
|
||||
* appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||
* misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source distribution. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef REACTPHYSICS3D_SET_H
|
||||
#define REACTPHYSICS3D_SET_H
|
||||
|
||||
// Libraries
|
||||
#include "memory/MemoryAllocator.h"
|
||||
#include "mathematics/mathematics_functions.h"
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace reactphysics3d {
|
||||
|
||||
// Class Set
|
||||
/**
|
||||
* This class represents a simple generic set. This set is implemented
|
||||
* with a hash table.
|
||||
*/
|
||||
template<typename V>
|
||||
class Set {
|
||||
|
||||
private:
|
||||
|
||||
/// An entry of the set
|
||||
struct Entry {
|
||||
|
||||
size_t hashCode; // Hash code of the entry
|
||||
int next; // Index of the next entry
|
||||
V* value; // Pointer to the value stored in the entry
|
||||
|
||||
/// Constructor
|
||||
Entry() {
|
||||
next = -1;
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
Entry(size_t hashcode, int nextEntry) {
|
||||
hashCode = hashcode;
|
||||
next = nextEntry;
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~Entry() {
|
||||
|
||||
assert(value == nullptr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -------------------- Constants -------------------- //
|
||||
|
||||
/// Number of prime numbers in array
|
||||
static constexpr int NB_PRIMES = 70;
|
||||
|
||||
/// Array of prime numbers for the size of the set
|
||||
static const int PRIMES[NB_PRIMES];
|
||||
|
||||
/// Largest prime number
|
||||
static int LARGEST_PRIME;
|
||||
|
||||
// -------------------- Attributes -------------------- //
|
||||
|
||||
/// Current number of used entries in the set
|
||||
int mNbUsedEntries;
|
||||
|
||||
/// Number of free entries among the used ones
|
||||
int mNbFreeEntries;
|
||||
|
||||
/// Current capacity of the set
|
||||
int mCapacity;
|
||||
|
||||
/// Array with all the buckets
|
||||
int* mBuckets;
|
||||
|
||||
/// Array with all the entries
|
||||
Entry* mEntries;
|
||||
|
||||
/// Memory allocator
|
||||
MemoryAllocator& mAllocator;
|
||||
|
||||
/// Index to the fist free entry
|
||||
int mFreeIndex;
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
/// Initialize the set
|
||||
void initialize(int capacity) {
|
||||
|
||||
// Compute the next larger prime size
|
||||
mCapacity = getPrimeSize(capacity);
|
||||
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||
|
||||
// Initialize the buckets and entries
|
||||
for (int i=0; i<mCapacity; i++) {
|
||||
|
||||
mBuckets[i] = -1;
|
||||
|
||||
// Construct the entry
|
||||
new (&mEntries[i]) Entry();
|
||||
}
|
||||
|
||||
mNbUsedEntries = 0;
|
||||
mNbFreeEntries = 0;
|
||||
mFreeIndex = -1;
|
||||
}
|
||||
|
||||
/// Expand the capacity of the set
|
||||
void expand(int newCapacity) {
|
||||
|
||||
assert(newCapacity > mCapacity);
|
||||
assert(isPrimeNumber(newCapacity));
|
||||
|
||||
// Allocate memory for the buckets
|
||||
int* newBuckets = static_cast<int*>(mAllocator.allocate(newCapacity * sizeof(int)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
Entry* newEntries = static_cast<Entry*>(mAllocator.allocate(newCapacity * sizeof(Entry)));
|
||||
|
||||
// Initialize the new buckets
|
||||
for (int i=0; i<newCapacity; i++) {
|
||||
newBuckets[i] = -1;
|
||||
}
|
||||
|
||||
// Copy the old entries to the new allocated memory location
|
||||
std::memcpy(newEntries, mEntries, mNbUsedEntries * sizeof(Entry));
|
||||
|
||||
// Construct the new entries
|
||||
for (int i=mNbUsedEntries; i<newCapacity; i++) {
|
||||
|
||||
// Construct the entry
|
||||
new (static_cast<void*>(&newEntries[i])) Entry();
|
||||
}
|
||||
|
||||
// For each used entry
|
||||
for (int i=0; i<mNbUsedEntries; i++) {
|
||||
|
||||
// If the entry is not free
|
||||
if (newEntries[i].hashCode != -1) {
|
||||
|
||||
// Get the corresponding bucket
|
||||
int bucket = newEntries[i].hashCode % newCapacity;
|
||||
|
||||
newEntries[i].next = newBuckets[bucket];
|
||||
newBuckets[bucket] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Release previously allocated memory
|
||||
mAllocator.release(mBuckets, mCapacity * sizeof(int));
|
||||
mAllocator.release(mEntries, mCapacity * sizeof(Entry));
|
||||
|
||||
mCapacity = newCapacity;
|
||||
mBuckets = newBuckets;
|
||||
mEntries = newEntries;
|
||||
}
|
||||
|
||||
/// Return the index of the entry with a given value or -1 if there is no entry with this value
|
||||
int findEntry(const V& value) const {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
|
||||
size_t hashCode = std::hash<V>()(value);
|
||||
int bucket = hashCode % mCapacity;
|
||||
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
if (mEntries[i].hashCode == hashCode && (*mEntries[i].value) == value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Return the prime number that is larger or equal to the number in parameter
|
||||
/// for the size of the set
|
||||
static int getPrimeSize(int number) {
|
||||
|
||||
// Check if the next larger prime number is in the precomputed array of primes
|
||||
for (int i = 0; i < NB_PRIMES; i++) {
|
||||
if (PRIMES[i] >= number) return PRIMES[i];
|
||||
}
|
||||
|
||||
// Manually compute the next larger prime number
|
||||
for (int i = (number | 1); i < std::numeric_limits<int>::max(); i+=2) {
|
||||
|
||||
if (isPrimeNumber(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
/// Clear and reset the set
|
||||
void reset() {
|
||||
|
||||
// If elements have been allocated
|
||||
if (mCapacity > 0) {
|
||||
|
||||
// Clear the list
|
||||
clear();
|
||||
|
||||
// Destroy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
mEntries[i].~Entry();
|
||||
}
|
||||
|
||||
mAllocator.release(mBuckets, mCapacity * sizeof(int));
|
||||
mAllocator.release(mEntries, mCapacity * sizeof(Entry));
|
||||
|
||||
mNbUsedEntries = 0;
|
||||
mNbFreeEntries = 0;
|
||||
mCapacity = 0;
|
||||
mBuckets = nullptr;
|
||||
mEntries = nullptr;
|
||||
mFreeIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Class Iterator
|
||||
/**
|
||||
* This class represents an iterator for the Set
|
||||
*/
|
||||
class Iterator {
|
||||
|
||||
private:
|
||||
|
||||
/// Array of entries
|
||||
const Entry* mEntries;
|
||||
|
||||
/// Capacity of the map
|
||||
int mCapacity;
|
||||
|
||||
/// Number of used entries in the map
|
||||
int mNbUsedEntries;
|
||||
|
||||
/// Index of the current entry
|
||||
int mCurrentEntry;
|
||||
|
||||
/// Advance the iterator
|
||||
void advance() {
|
||||
|
||||
// If we are trying to move past the end
|
||||
assert(mCurrentEntry < mNbUsedEntries);
|
||||
|
||||
for (mCurrentEntry += 1; mCurrentEntry < mNbUsedEntries; mCurrentEntry++) {
|
||||
|
||||
// If the entry is not empty
|
||||
if (mEntries[mCurrentEntry].value != nullptr) {
|
||||
|
||||
// We have found the next non empty entry
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We have not find a non empty entry, we return an iterator to the end
|
||||
mCurrentEntry = mCapacity;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Iterator traits
|
||||
using value_type = V;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = V*;
|
||||
using reference = V&;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
/// Constructor
|
||||
Iterator() = default;
|
||||
|
||||
/// Constructor
|
||||
Iterator(const Entry* entries, int capacity, int nbUsedEntries, int currentEntry)
|
||||
:mEntries(entries), mCapacity(capacity), mNbUsedEntries(nbUsedEntries), mCurrentEntry(currentEntry) {
|
||||
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
Iterator(const Iterator& it)
|
||||
:mEntries(it.mEntries), mCapacity(it.mCapacity), mNbUsedEntries(it.mNbUsedEntries), mCurrentEntry(it.mCurrentEntry) {
|
||||
|
||||
}
|
||||
|
||||
/// Deferencable
|
||||
reference operator*() const {
|
||||
assert(mCurrentEntry >= 0 && mCurrentEntry < mNbUsedEntries);
|
||||
assert(mEntries[mCurrentEntry].value != nullptr);
|
||||
return *(mEntries[mCurrentEntry].value);
|
||||
}
|
||||
|
||||
/// Deferencable
|
||||
pointer operator->() const {
|
||||
assert(mCurrentEntry >= 0 && mCurrentEntry < mNbUsedEntries);
|
||||
assert(mEntries[mCurrentEntry].value != nullptr);
|
||||
return mEntries[mCurrentEntry].value;
|
||||
}
|
||||
|
||||
/// Post increment (it++)
|
||||
Iterator& operator++() {
|
||||
advance();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Pre increment (++it)
|
||||
Iterator operator++(int number) {
|
||||
Iterator tmp = *this;
|
||||
advance();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/// Equality operator (it == end())
|
||||
bool operator==(const Iterator& iterator) const {
|
||||
return mCurrentEntry == iterator.mCurrentEntry && mEntries == iterator.mEntries;
|
||||
}
|
||||
|
||||
/// Inequality operator (it != end())
|
||||
bool operator!=(const Iterator& iterator) const {
|
||||
return !(*this == iterator);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
/// Constructor
|
||||
Set(MemoryAllocator& allocator, size_t capacity = 0)
|
||||
: mNbUsedEntries(0), mNbFreeEntries(0), mCapacity(0), mBuckets(nullptr),
|
||||
mEntries(nullptr), mAllocator(allocator), mFreeIndex(-1) {
|
||||
|
||||
// If the largest prime has not been computed yet
|
||||
if (LARGEST_PRIME == -1) {
|
||||
|
||||
// Compute the largest prime number (largest map capacity)
|
||||
LARGEST_PRIME = getPrimeSize(PRIMES[NB_PRIMES - 1] + 2);
|
||||
}
|
||||
|
||||
if (capacity > 0) {
|
||||
|
||||
initialize(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
Set(const Set<V>& set)
|
||||
:mNbUsedEntries(set.mNbUsedEntries), mNbFreeEntries(set.mNbFreeEntries), mCapacity(set.mCapacity),
|
||||
mAllocator(set.mAllocator), mFreeIndex(set.mFreeIndex) {
|
||||
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||
|
||||
// Copy the buckets
|
||||
std::memcpy(mBuckets, set.mBuckets, mCapacity * sizeof(int));
|
||||
|
||||
// Copy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
|
||||
new (&mEntries[i]) Entry(set.mEntries[i].hashCode, set.mEntries[i].next);
|
||||
|
||||
if (set.mEntries[i].value != nullptr) {
|
||||
mEntries[i].value = static_cast<V*>(mAllocator.allocate(sizeof(V)));
|
||||
new (mEntries[i].value) V(*(set.mEntries[i].value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~Set() {
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Allocate memory for a given number of elements
|
||||
void reserve(size_t capacity) {
|
||||
|
||||
if (capacity <= mCapacity) return;
|
||||
|
||||
if (capacity > LARGEST_PRIME && LARGEST_PRIME > mCapacity) {
|
||||
capacity = LARGEST_PRIME;
|
||||
}
|
||||
else {
|
||||
capacity = getPrimeSize(capacity);
|
||||
}
|
||||
|
||||
expand(capacity);
|
||||
}
|
||||
|
||||
/// Return true if the set contains a given value
|
||||
bool contains(const V& value) const {
|
||||
return findEntry(value) != -1;
|
||||
}
|
||||
|
||||
/// Add a value into the set
|
||||
void add(const V& value) {
|
||||
|
||||
if (mCapacity == 0) {
|
||||
initialize(0);
|
||||
}
|
||||
|
||||
// Compute the hash code of the value
|
||||
size_t hashCode = std::hash<V>()(value);
|
||||
|
||||
// Compute the corresponding bucket index
|
||||
int bucket = hashCode % mCapacity;
|
||||
|
||||
// Check if the item is already in the set
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
|
||||
// If there is already an item with the same value in the set
|
||||
if (mEntries[i].hashCode == hashCode && (*mEntries[i].value) == value) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t entryIndex;
|
||||
|
||||
// If there are free entries to use
|
||||
if (mNbFreeEntries > 0) {
|
||||
assert(mFreeIndex >= 0);
|
||||
entryIndex = mFreeIndex;
|
||||
mFreeIndex = mEntries[entryIndex].next;
|
||||
mNbFreeEntries--;
|
||||
}
|
||||
else {
|
||||
|
||||
// If we need to allocator more entries
|
||||
if (mNbUsedEntries == mCapacity) {
|
||||
|
||||
// Allocate more memory
|
||||
reserve(mCapacity * 2);
|
||||
|
||||
// Recompute the bucket index
|
||||
bucket = hashCode % mCapacity;
|
||||
}
|
||||
|
||||
entryIndex = mNbUsedEntries;
|
||||
mNbUsedEntries++;
|
||||
}
|
||||
|
||||
assert(mEntries[entryIndex].value == nullptr);
|
||||
mEntries[entryIndex].hashCode = hashCode;
|
||||
mEntries[entryIndex].next = mBuckets[bucket];
|
||||
mEntries[entryIndex].value = static_cast<V*>(mAllocator.allocate(sizeof(V)));
|
||||
assert(mEntries[entryIndex].value != nullptr);
|
||||
new (mEntries[entryIndex].value) V(value);
|
||||
mBuckets[bucket] = entryIndex;
|
||||
}
|
||||
|
||||
/// Remove the element pointed by some iterator
|
||||
/// This method returns an iterator pointing to the
|
||||
/// element after the one that has been removed
|
||||
Iterator remove(const Iterator& it) {
|
||||
|
||||
return remove(*it);
|
||||
}
|
||||
|
||||
/// Remove the element from the set with a given value
|
||||
/// This method returns an iterator pointing to the
|
||||
/// element after the one that has been removed
|
||||
Iterator remove(const V& value) {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
|
||||
size_t hashcode = std::hash<V>()(value);
|
||||
int bucket = hashcode % mCapacity;
|
||||
int last = -1;
|
||||
for (int i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].next) {
|
||||
|
||||
if (mEntries[i].hashCode == hashcode && (*mEntries[i].value) == value) {
|
||||
|
||||
if (last < 0 ) {
|
||||
mBuckets[bucket] = mEntries[i].next;
|
||||
}
|
||||
else {
|
||||
mEntries[last].next = mEntries[i].next;
|
||||
}
|
||||
|
||||
// Release memory for the value if any
|
||||
if (mEntries[i].value != nullptr) {
|
||||
mEntries[i].value->~V();
|
||||
mAllocator.release(mEntries[i].value, sizeof(V));
|
||||
mEntries[i].value = nullptr;
|
||||
}
|
||||
mEntries[i].hashCode = -1;
|
||||
mEntries[i].next = mFreeIndex;
|
||||
mFreeIndex = i;
|
||||
mNbFreeEntries++;
|
||||
|
||||
// Find the next valid entry to return an iterator
|
||||
for (i += 1; i < mNbUsedEntries; i++) {
|
||||
|
||||
// If the entry is not empty
|
||||
if (mEntries[i].value != nullptr) {
|
||||
|
||||
// We have found the next non empty entry
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, i);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
/// Clear the set
|
||||
void clear() {
|
||||
|
||||
if (mNbUsedEntries > 0) {
|
||||
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
mBuckets[i] = -1;
|
||||
mEntries[i].next = -1;
|
||||
if (mEntries[i].value != nullptr) {
|
||||
mEntries[i].value->~V();
|
||||
mAllocator.release(mEntries[i].value, sizeof(V));
|
||||
mEntries[i].value = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mFreeIndex = -1;
|
||||
mNbUsedEntries = 0;
|
||||
mNbFreeEntries = 0;
|
||||
}
|
||||
|
||||
assert(size() == 0);
|
||||
}
|
||||
|
||||
/// Return the number of elements in the set
|
||||
int size() const {
|
||||
return mNbUsedEntries - mNbFreeEntries;
|
||||
}
|
||||
|
||||
/// Return the capacity of the set
|
||||
int capacity() const {
|
||||
return mCapacity;
|
||||
}
|
||||
|
||||
/// Try to find an item of the set given a key.
|
||||
/// The method returns an iterator to the found item or
|
||||
/// an iterator pointing to the end if not found
|
||||
Iterator find(const V& value) const {
|
||||
|
||||
int bucket;
|
||||
int entry = -1;
|
||||
|
||||
if (mCapacity > 0) {
|
||||
|
||||
size_t hashCode = std::hash<V>()(value);
|
||||
bucket = hashCode % mCapacity;
|
||||
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
if (mEntries[i].hashCode == hashCode && *(mEntries[i].value) == value) {
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == -1) {
|
||||
return end();
|
||||
}
|
||||
|
||||
assert(mEntries[entry].value != nullptr);
|
||||
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, entry);
|
||||
}
|
||||
|
||||
/// Overloaded equality operator
|
||||
bool operator==(const Set<V>& set) const {
|
||||
|
||||
if (size() != set.size()) return false;
|
||||
|
||||
for (auto it = begin(); it != end(); ++it) {
|
||||
if(!set.contains(*it)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Overloaded not equal operator
|
||||
bool operator!=(const Set<V>& set) const {
|
||||
|
||||
return !((*this) == set);
|
||||
}
|
||||
|
||||
/// Overloaded assignment operator
|
||||
Set<V>& operator=(const Set<V>& set) {
|
||||
|
||||
// Check for self assignment
|
||||
if (this != &set) {
|
||||
|
||||
// Reset the set
|
||||
reset();
|
||||
|
||||
if (set.mCapacity > 0) {
|
||||
|
||||
// Compute the next larger prime size
|
||||
mCapacity = getPrimeSize(set.mCapacity);
|
||||
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||
|
||||
// Copy the buckets
|
||||
std::memcpy(mBuckets, set.mBuckets, mCapacity * sizeof(int));
|
||||
|
||||
// Copy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
|
||||
new (&mEntries[i]) Entry(set.mEntries[i].hashCode, set.mEntries[i].next);
|
||||
|
||||
if (set.mEntries[i].value != nullptr) {
|
||||
mEntries[i].value = static_cast<V*>(mAllocator.allocate(sizeof(V)));
|
||||
new (mEntries[i].value) V(*(set.mEntries[i].value));
|
||||
}
|
||||
}
|
||||
|
||||
mNbUsedEntries = set.mNbUsedEntries;
|
||||
mNbFreeEntries = set.mNbFreeEntries;
|
||||
mFreeIndex = set.mFreeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a begin iterator
|
||||
Iterator begin() const {
|
||||
|
||||
// If the map is empty
|
||||
if (size() == 0) {
|
||||
|
||||
// Return an iterator to the end
|
||||
return end();
|
||||
}
|
||||
|
||||
// Find the first used entry
|
||||
int entry;
|
||||
for (entry=0; entry < mNbUsedEntries; entry++) {
|
||||
if (mEntries[entry].value != nullptr) {
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, entry);
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/// Return a end iterator
|
||||
Iterator end() const {
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, mCapacity);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename V>
|
||||
const int Set<V>::PRIMES[NB_PRIMES] = {3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
||||
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
||||
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
||||
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
||||
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559};
|
||||
|
||||
template<typename V>
|
||||
int Set<V>::LARGEST_PRIME = -1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -33,7 +33,7 @@ using namespace std;
|
|||
|
||||
// Constructor
|
||||
CollisionWorld::CollisionWorld()
|
||||
: mCollisionDetection(this, mMemoryManager), mCurrentBodyID(0),
|
||||
: mCollisionDetection(this, mMemoryManager), mBodies(mMemoryManager.getPoolAllocator()), mCurrentBodyID(0),
|
||||
mFreeBodiesIDs(mMemoryManager.getPoolAllocator()), mEventListener(nullptr) {
|
||||
|
||||
#ifdef IS_PROFILING_ACTIVE
|
||||
|
@ -49,14 +49,11 @@ CollisionWorld::CollisionWorld()
|
|||
CollisionWorld::~CollisionWorld() {
|
||||
|
||||
// Destroy all the collision bodies that have not been removed
|
||||
std::set<CollisionBody*>::iterator itBodies;
|
||||
for (itBodies = mBodies.begin(); itBodies != mBodies.end(); ) {
|
||||
std::set<CollisionBody*>::iterator itToRemove = itBodies;
|
||||
++itBodies;
|
||||
destroyCollisionBody(*itToRemove);
|
||||
for (int i=mBodies.size() - 1 ; i >= 0; i--) {
|
||||
destroyCollisionBody(mBodies[i]);
|
||||
}
|
||||
|
||||
assert(mBodies.empty());
|
||||
assert(mBodies.size() == 0);
|
||||
}
|
||||
|
||||
// Create a collision body and add it to the world
|
||||
|
@ -80,7 +77,7 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) {
|
|||
assert(collisionBody != nullptr);
|
||||
|
||||
// Add the collision body to the world
|
||||
mBodies.insert(collisionBody);
|
||||
mBodies.add(collisionBody);
|
||||
|
||||
#ifdef IS_PROFILING_ACTIVE
|
||||
|
||||
|
@ -108,7 +105,7 @@ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
|
|||
collisionBody->~CollisionBody();
|
||||
|
||||
// Remove the collision body from the list of bodies
|
||||
mBodies.erase(collisionBody);
|
||||
mBodies.remove(collisionBody);
|
||||
|
||||
// Free the object from the memory allocator
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, collisionBody, sizeof(CollisionBody));
|
||||
|
@ -121,7 +118,7 @@ bodyindex CollisionWorld::computeNextAvailableBodyID() {
|
|||
bodyindex bodyID;
|
||||
if (mFreeBodiesIDs.size() != 0) {
|
||||
bodyID = mFreeBodiesIDs[mFreeBodiesIDs.size() - 1];
|
||||
mFreeBodiesIDs.remove(mFreeBodiesIDs.size() - 1);
|
||||
mFreeBodiesIDs.removeAt(mFreeBodiesIDs.size() - 1);
|
||||
}
|
||||
else {
|
||||
bodyID = mCurrentBodyID;
|
||||
|
@ -135,7 +132,7 @@ bodyindex CollisionWorld::computeNextAvailableBodyID() {
|
|||
void CollisionWorld::resetContactManifoldListsOfBodies() {
|
||||
|
||||
// For each rigid body of the world
|
||||
for (std::set<CollisionBody*>::iterator it = mBodies.begin(); it != mBodies.end(); ++it) {
|
||||
for (List<CollisionBody*>::Iterator it = mBodies.begin(); it != mBodies.end(); ++it) {
|
||||
|
||||
// Reset the contact manifold list of the body
|
||||
(*it)->resetContactManifoldsList();
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
#define REACTPHYSICS3D_COLLISION_WORLD_H
|
||||
|
||||
// Libraries
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include "mathematics/mathematics.h"
|
||||
#include "containers/List.h"
|
||||
|
@ -68,7 +66,7 @@ class CollisionWorld {
|
|||
CollisionDetection mCollisionDetection;
|
||||
|
||||
/// All the bodies (rigid and soft) of the world
|
||||
std::set<CollisionBody*> mBodies;
|
||||
List<CollisionBody*> mBodies;
|
||||
|
||||
/// Current body ID
|
||||
bodyindex mCurrentBodyID;
|
||||
|
@ -109,12 +107,6 @@ class CollisionWorld {
|
|||
/// Deleted assignment operator
|
||||
CollisionWorld& operator=(const CollisionWorld& world) = delete;
|
||||
|
||||
/// Return an iterator to the beginning of the bodies of the physics world
|
||||
std::set<CollisionBody*>::iterator getBodiesBeginIterator();
|
||||
|
||||
/// Return an iterator to the end of the bodies of the physics world
|
||||
std::set<CollisionBody*>::iterator getBodiesEndIterator();
|
||||
|
||||
/// Create a collision body
|
||||
CollisionBody* createCollisionBody(const Transform& transform);
|
||||
|
||||
|
@ -167,22 +159,6 @@ class CollisionWorld {
|
|||
friend class ConvexMeshShape;
|
||||
};
|
||||
|
||||
// Return an iterator to the beginning of the bodies of the physics world
|
||||
/**
|
||||
* @return An starting iterator to the set of bodies of the world
|
||||
*/
|
||||
inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesBeginIterator() {
|
||||
return mBodies.begin();
|
||||
}
|
||||
|
||||
// Return an iterator to the end of the bodies of the physics world
|
||||
/**
|
||||
* @return An ending iterator to the set of bodies of the world
|
||||
*/
|
||||
inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator() {
|
||||
return mBodies.end();
|
||||
}
|
||||
|
||||
// Set the collision dispatch configuration
|
||||
/// This can be used to replace default collision detection algorithms by your
|
||||
/// custom algorithm for instance.
|
||||
|
|
|
@ -44,7 +44,8 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity)
|
|||
mContactSolver(mMemoryManager),
|
||||
mNbVelocitySolverIterations(DEFAULT_VELOCITY_SOLVER_NB_ITERATIONS),
|
||||
mNbPositionSolverIterations(DEFAULT_POSITION_SOLVER_NB_ITERATIONS),
|
||||
mIsSleepingEnabled(SLEEPING_ENABLED), mGravity(gravity), mTimeStep(decimal(1.0f / 60.0f)),
|
||||
mIsSleepingEnabled(SLEEPING_ENABLED), mRigidBodies(mMemoryManager.getPoolAllocator()),
|
||||
mJoints(mMemoryManager.getPoolAllocator()), mGravity(gravity), mTimeStep(decimal(1.0f / 60.0f)),
|
||||
mIsGravityEnabled(true), mConstrainedLinearVelocities(nullptr),
|
||||
mConstrainedAngularVelocities(nullptr), mSplitLinearVelocities(nullptr),
|
||||
mSplitAngularVelocities(nullptr), mConstrainedPositions(nullptr),
|
||||
|
@ -67,19 +68,13 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity)
|
|||
DynamicsWorld::~DynamicsWorld() {
|
||||
|
||||
// Destroy all the joints that have not been removed
|
||||
std::set<Joint*>::iterator itJoints;
|
||||
for (itJoints = mJoints.begin(); itJoints != mJoints.end();) {
|
||||
std::set<Joint*>::iterator itToRemove = itJoints;
|
||||
++itJoints;
|
||||
destroyJoint(*itToRemove);
|
||||
for (int i=mJoints.size() - 1; i >= 0; i--) {
|
||||
destroyJoint(mJoints[i]);
|
||||
}
|
||||
|
||||
// Destroy all the rigid bodies that have not been removed
|
||||
std::set<RigidBody*>::iterator itRigidBodies;
|
||||
for (itRigidBodies = mRigidBodies.begin(); itRigidBodies != mRigidBodies.end();) {
|
||||
std::set<RigidBody*>::iterator itToRemove = itRigidBodies;
|
||||
++itRigidBodies;
|
||||
destroyRigidBody(*itToRemove);
|
||||
for (int i=mRigidBodies.size() - 1; i >= 0; i--) {
|
||||
destroyRigidBody(mRigidBodies[i]);
|
||||
}
|
||||
|
||||
assert(mJoints.size() == 0);
|
||||
|
@ -257,7 +252,7 @@ void DynamicsWorld::initVelocityArrays() {
|
|||
|
||||
// Initialize the map of body indexes in the velocity arrays
|
||||
uint i = 0;
|
||||
for (std::set<RigidBody*>::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
for (List<RigidBody*>::Iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
|
||||
mSplitLinearVelocities[i].setToZero();
|
||||
mSplitAngularVelocities[i].setToZero();
|
||||
|
@ -388,7 +383,7 @@ void DynamicsWorld::solvePositionCorrection() {
|
|||
PROFILE("DynamicsWorld::solvePositionCorrection()", &mProfiler);
|
||||
|
||||
// Do not continue if there is no constraints
|
||||
if (mJoints.empty()) return;
|
||||
if (mJoints.size() == 0) return;
|
||||
|
||||
// For each island of the world
|
||||
for (uint islandIndex = 0; islandIndex < mNbIslands; islandIndex++) {
|
||||
|
@ -423,8 +418,8 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) {
|
|||
assert(rigidBody != nullptr);
|
||||
|
||||
// Add the rigid body to the physics world
|
||||
mBodies.insert(rigidBody);
|
||||
mRigidBodies.insert(rigidBody);
|
||||
mBodies.add(rigidBody);
|
||||
mRigidBodies.add(rigidBody);
|
||||
|
||||
#ifdef IS_PROFILING_ACTIVE
|
||||
|
||||
|
@ -461,8 +456,8 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) {
|
|||
rigidBody->~RigidBody();
|
||||
|
||||
// Remove the rigid body from the list of rigid bodies
|
||||
mBodies.erase(rigidBody);
|
||||
mRigidBodies.erase(rigidBody);
|
||||
mBodies.remove(rigidBody);
|
||||
mRigidBodies.remove(rigidBody);
|
||||
|
||||
// Free the object from the memory allocator
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, rigidBody, sizeof(RigidBody));
|
||||
|
@ -536,7 +531,7 @@ Joint* DynamicsWorld::createJoint(const JointInfo& jointInfo) {
|
|||
}
|
||||
|
||||
// Add the joint into the world
|
||||
mJoints.insert(newJoint);
|
||||
mJoints.add(newJoint);
|
||||
|
||||
// Add the joint into the joint list of the bodies involved in the joint
|
||||
addJointToBody(newJoint);
|
||||
|
@ -565,7 +560,7 @@ void DynamicsWorld::destroyJoint(Joint* joint) {
|
|||
joint->getBody2()->setIsSleeping(false);
|
||||
|
||||
// Remove the joint from the world
|
||||
mJoints.erase(joint);
|
||||
mJoints.remove(joint);
|
||||
|
||||
// Remove the joint from the joint list of the bodies involved in the joint
|
||||
joint->mBody1->removeJointFromJointsList(mMemoryManager, joint);
|
||||
|
@ -622,11 +617,11 @@ void DynamicsWorld::computeIslands() {
|
|||
int nbContactManifolds = 0;
|
||||
|
||||
// Reset all the isAlreadyInIsland variables of bodies, joints and contact manifolds
|
||||
for (std::set<RigidBody*>::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
for (List<RigidBody*>::Iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
int nbBodyManifolds = (*it)->resetIsAlreadyInIslandAndCountManifolds();
|
||||
nbContactManifolds += nbBodyManifolds;
|
||||
}
|
||||
for (std::set<Joint*>::iterator it = mJoints.begin(); it != mJoints.end(); ++it) {
|
||||
for (List<Joint*>::Iterator it = mJoints.begin(); it != mJoints.end(); ++it) {
|
||||
(*it)->mIsAlreadyInIsland = false;
|
||||
}
|
||||
|
||||
|
@ -636,7 +631,7 @@ void DynamicsWorld::computeIslands() {
|
|||
nbBytesStack));
|
||||
|
||||
// For each rigid body of the world
|
||||
for (std::set<RigidBody*>::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
for (List<RigidBody*>::Iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
|
||||
RigidBody* body = *it;
|
||||
|
||||
|
@ -818,7 +813,7 @@ void DynamicsWorld::enableSleeping(bool isSleepingEnabled) {
|
|||
if (!mIsSleepingEnabled) {
|
||||
|
||||
// For each body of the world
|
||||
std::set<RigidBody*>::iterator it;
|
||||
List<RigidBody*>::Iterator it;
|
||||
for (it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
|
||||
// Wake up the rigid body
|
||||
|
|
|
@ -66,10 +66,10 @@ class DynamicsWorld : public CollisionWorld {
|
|||
bool mIsSleepingEnabled;
|
||||
|
||||
/// All the rigid bodies of the physics world
|
||||
std::set<RigidBody*> mRigidBodies;
|
||||
List<RigidBody*> mRigidBodies;
|
||||
|
||||
/// All the joints of the world
|
||||
std::set<Joint*> mJoints;
|
||||
List<Joint*> mJoints;
|
||||
|
||||
/// Gravity vector of the world
|
||||
Vector3 mGravity;
|
||||
|
@ -215,12 +215,6 @@ class DynamicsWorld : public CollisionWorld {
|
|||
/// Return the number of joints in the world
|
||||
uint getNbJoints() const;
|
||||
|
||||
/// Return an iterator to the beginning of the rigid bodies of the physics world
|
||||
std::set<RigidBody*>::iterator getRigidBodiesBeginIterator();
|
||||
|
||||
/// Return an iterator to the end of the rigid bodies of the physics world
|
||||
std::set<RigidBody*>::iterator getRigidBodiesEndIterator();
|
||||
|
||||
/// Return true if the sleeping technique is enabled
|
||||
bool isSleepingEnabled() const;
|
||||
|
||||
|
@ -260,7 +254,7 @@ class DynamicsWorld : public CollisionWorld {
|
|||
inline void DynamicsWorld::resetBodiesForceAndTorque() {
|
||||
|
||||
// For each body of the world
|
||||
std::set<RigidBody*>::iterator it;
|
||||
List<RigidBody*>::Iterator it;
|
||||
for (it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
|
||||
(*it)->mExternalForce.setToZero();
|
||||
(*it)->mExternalTorque.setToZero();
|
||||
|
@ -370,22 +364,6 @@ inline uint DynamicsWorld::getNbJoints() const {
|
|||
return mJoints.size();
|
||||
}
|
||||
|
||||
// Return an iterator to the beginning of the bodies of the physics world
|
||||
/**
|
||||
* @return Starting iterator of the set of rigid bodies
|
||||
*/
|
||||
inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesBeginIterator() {
|
||||
return mRigidBodies.begin();
|
||||
}
|
||||
|
||||
// Return an iterator to the end of the bodies of the physics world
|
||||
/**
|
||||
* @return Ending iterator of the set of rigid bodies
|
||||
*/
|
||||
inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesEndIterator() {
|
||||
return mRigidBodies.end();
|
||||
}
|
||||
|
||||
// Return true if the sleeping technique is enabled
|
||||
/**
|
||||
* @return True if the sleeping technique is enabled and false otherwise
|
||||
|
|
|
@ -187,7 +187,7 @@ void OverlappingPair::clearObsoleteLastFrameCollisionInfos() {
|
|||
it->second->~LastFrameCollisionInfo();
|
||||
mPersistentAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
|
||||
|
||||
mLastFrameCollisionInfos.remove(it++);
|
||||
it = mLastFrameCollisionInfos.remove(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "tests/collision/TestTriangleVertexArray.h"
|
||||
#include "tests/containers/TestList.h"
|
||||
#include "tests/containers/TestMap.h"
|
||||
#include "tests/containers/TestSet.h"
|
||||
|
||||
using namespace reactphysics3d;
|
||||
|
||||
|
@ -52,6 +53,7 @@ int main() {
|
|||
|
||||
testSuite.addTest(new TestList("List"));
|
||||
testSuite.addTest(new TestMap("Map"));
|
||||
testSuite.addTest(new TestSet("Set"));
|
||||
|
||||
// ---------- Mathematics tests ---------- //
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class TestList : public Test {
|
|||
testAddRemoveClear();
|
||||
testAssignment();
|
||||
testIndexing();
|
||||
testFind();
|
||||
testEquality();
|
||||
testReserve();
|
||||
testIterators();
|
||||
|
@ -142,27 +143,52 @@ class TestList : public Test {
|
|||
list3.add(3);
|
||||
list3.add(4);
|
||||
|
||||
list3.remove(3);
|
||||
auto it = list3.removeAt(3);
|
||||
test(list3.size() == 3);
|
||||
test(list3.capacity() == 4);
|
||||
test(it == list3.end());
|
||||
test(list3[0] = 1);
|
||||
test(list3[1] = 2);
|
||||
test(list3[2] = 3);
|
||||
|
||||
list3.remove(1);
|
||||
it = list3.removeAt(1);
|
||||
test(list3.size() == 2);
|
||||
test(list3.capacity() == 4);
|
||||
test(list3[0] = 1);
|
||||
test(list3[1] = 3);
|
||||
test(*it = 3);
|
||||
|
||||
list3.remove(0);
|
||||
list3.removeAt(0);
|
||||
test(list3.size() == 1);
|
||||
test(list3.capacity() == 4);
|
||||
test(list3[0] = 3);
|
||||
|
||||
list3.remove(0);
|
||||
it = list3.removeAt(0);
|
||||
test(list3.size() == 0);
|
||||
test(list3.capacity() == 4);
|
||||
test(it == list3.end());
|
||||
|
||||
list3.add(1);
|
||||
list3.add(2);
|
||||
list3.add(3);
|
||||
it = list3.begin();
|
||||
list3.remove(it);
|
||||
test(list3.size() == 2);
|
||||
test(list3[0] == 2);
|
||||
test(list3[1] == 3);
|
||||
it = list3.find(3);
|
||||
list3.remove(it);
|
||||
test(list3.size() == 1);
|
||||
test(list3[0] == 2);
|
||||
|
||||
list3.add(5);
|
||||
list3.add(6);
|
||||
list3.add(7);
|
||||
it = list3.remove(7);
|
||||
test(it == list3.end());
|
||||
test(list3.size() == 3);
|
||||
it = list3.remove(5);
|
||||
test((*it) == 6);
|
||||
|
||||
// ----- Test addRange() ----- //
|
||||
|
||||
|
@ -270,6 +296,20 @@ class TestList : public Test {
|
|||
test(list1[1] == 8);
|
||||
}
|
||||
|
||||
void testFind() {
|
||||
|
||||
List<int> list1(mAllocator);
|
||||
list1.add(1);
|
||||
list1.add(2);
|
||||
list1.add(3);
|
||||
list1.add(4);
|
||||
list1.add(5);
|
||||
|
||||
test(list1.find(1) == list1.begin());
|
||||
test(*(list1.find(2)) == 2);
|
||||
test(*(list1.find(5)) == 5);
|
||||
}
|
||||
|
||||
void testEquality() {
|
||||
|
||||
List<int> list1(mAllocator);
|
||||
|
|
|
@ -195,9 +195,10 @@ class TestMap : public Test {
|
|||
test(!map1.containsKey(8));
|
||||
test(map1.size() == 1);
|
||||
|
||||
map1.remove(56);
|
||||
auto it = map1.remove(56);
|
||||
test(!map1.containsKey(56));
|
||||
test(map1.size() == 0);
|
||||
test(it == map1.end());
|
||||
|
||||
isValid = true;
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
|
@ -219,12 +220,19 @@ class TestMap : public Test {
|
|||
map3.add(std::make_pair(2, 20));
|
||||
map3.add(std::make_pair(3, 30));
|
||||
test(map3.size() == 3);
|
||||
auto it = map3.begin();
|
||||
it = map3.begin();
|
||||
map3.remove(it++);
|
||||
test(!map3.containsKey(1));
|
||||
test(map3.size() == 2);
|
||||
test(it->second == 20);
|
||||
|
||||
map3.add(std::make_pair(56, 32));
|
||||
map3.add(std::make_pair(23, 89));
|
||||
for (it = map3.begin(); it != map3.end();) {
|
||||
it = map3.remove(it);
|
||||
}
|
||||
test(map3.size() == 0);
|
||||
|
||||
// ----- Test clear() ----- //
|
||||
|
||||
Map<int, int> map4(mAllocator);
|
||||
|
@ -367,6 +375,7 @@ class TestMap : public Test {
|
|||
Map<int, int> map2(mAllocator);
|
||||
map2 = map1;
|
||||
test(map2.size() == map1.size());
|
||||
test(map1 == map2);
|
||||
test(map2[1] == 3);
|
||||
test(map2[2] == 6);
|
||||
test(map2[10] == 30);
|
||||
|
@ -374,6 +383,7 @@ class TestMap : public Test {
|
|||
Map<int, int> map3(mAllocator, 100);
|
||||
map3 = map1;
|
||||
test(map3.size() == map1.size());
|
||||
test(map3 == map1);
|
||||
test(map3[1] == 3);
|
||||
test(map3[2] == 6);
|
||||
test(map3[10] == 30);
|
||||
|
@ -381,12 +391,14 @@ class TestMap : public Test {
|
|||
Map<int, int> map4(mAllocator);
|
||||
map3 = map4;
|
||||
test(map3.size() == 0);
|
||||
test(map3 == map4);
|
||||
|
||||
Map<int, int> map5(mAllocator);
|
||||
map5.add(std::make_pair(7, 8));
|
||||
map5.add(std::make_pair(19, 70));
|
||||
map1 = map5;
|
||||
test(map5.size() == map1.size());
|
||||
test(map5 == map1);
|
||||
test(map1[7] == 8);
|
||||
test(map1[19] == 70);
|
||||
}
|
||||
|
|
417
test/tests/containers/TestSet.h
Normal file
417
test/tests/containers/TestSet.h
Normal file
|
@ -0,0 +1,417 @@
|
|||
/********************************************************************************
|
||||
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||
*********************************************************************************
|
||||
* *
|
||||
* This software is provided 'as-is', without any express or implied warranty. *
|
||||
* In no event will the authors be held liable for any damages arising from the *
|
||||
* use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute it *
|
||||
* freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||
* that you wrote the original software. If you use this software in a *
|
||||
* product, an acknowledgment in the product documentation would be *
|
||||
* appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||
* misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source distribution. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef TEST_SET_H
|
||||
#define TEST_SET_H
|
||||
|
||||
// Libraries
|
||||
#include "Test.h"
|
||||
#include "containers/Set.h"
|
||||
#include "memory/DefaultAllocator.h"
|
||||
|
||||
// Key to test map with always same hash values
|
||||
namespace reactphysics3d {
|
||||
struct TestValueSet {
|
||||
int key;
|
||||
|
||||
TestValueSet(int k) :key(k) {}
|
||||
|
||||
bool operator==(const TestValueSet& testValue) const {
|
||||
return key == testValue.key;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Hash function for struct VerticesPair
|
||||
namespace std {
|
||||
|
||||
template <> struct hash<reactphysics3d::TestValueSet> {
|
||||
|
||||
size_t operator()(const reactphysics3d::TestValueSet& value) const {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Reactphysics3D namespace
|
||||
namespace reactphysics3d {
|
||||
|
||||
// Class TestSet
|
||||
/**
|
||||
* Unit test for the Set class
|
||||
*/
|
||||
class TestSet : public Test {
|
||||
|
||||
private :
|
||||
|
||||
// ---------- Atributes ---------- //
|
||||
|
||||
DefaultAllocator mAllocator;
|
||||
|
||||
public :
|
||||
|
||||
// ---------- Methods ---------- //
|
||||
|
||||
/// Constructor
|
||||
TestSet(const std::string& name) : Test(name) {
|
||||
|
||||
}
|
||||
|
||||
/// Run the tests
|
||||
void run() {
|
||||
|
||||
testConstructors();
|
||||
testReserve();
|
||||
testAddRemoveClear();
|
||||
testContains();
|
||||
testFind();
|
||||
testEquality();
|
||||
testAssignment();
|
||||
testIterators();
|
||||
}
|
||||
|
||||
void testConstructors() {
|
||||
|
||||
// ----- Constructors ----- //
|
||||
|
||||
Set<std::string> set1(mAllocator);
|
||||
test(set1.capacity() == 0);
|
||||
test(set1.size() == 0);
|
||||
|
||||
Set<std::string> set2(mAllocator, 100);
|
||||
test(set2.capacity() >= 100);
|
||||
test(set2.size() == 0);
|
||||
|
||||
// ----- Copy Constructors ----- //
|
||||
Set<std::string> set3(set1);
|
||||
test(set3.capacity() == set1.capacity());
|
||||
test(set3.size() == set1.size());
|
||||
|
||||
Set<int> set4(mAllocator);
|
||||
set4.add(10);
|
||||
set4.add(20);
|
||||
set4.add(30);
|
||||
test(set4.capacity() >= 3);
|
||||
test(set4.size() == 3);
|
||||
set4.add(30);
|
||||
test(set4.size() == 3);
|
||||
|
||||
Set<int> set5(set4);
|
||||
test(set5.capacity() == set4.capacity());
|
||||
test(set5.size() == set4.size());
|
||||
test(set5.contains(10));
|
||||
test(set5.contains(20));
|
||||
test(set5.contains(30));
|
||||
}
|
||||
|
||||
void testReserve() {
|
||||
|
||||
Set<std::string> set1(mAllocator);
|
||||
set1.reserve(15);
|
||||
test(set1.capacity() >= 15);
|
||||
set1.add("test1");
|
||||
set1.add("test2");
|
||||
test(set1.capacity() >= 15);
|
||||
|
||||
set1.reserve(10);
|
||||
test(set1.capacity() >= 15);
|
||||
|
||||
set1.reserve(100);
|
||||
test(set1.capacity() >= 100);
|
||||
test(set1.contains("test1"));
|
||||
test(set1.contains("test2"));
|
||||
}
|
||||
|
||||
void testAddRemoveClear() {
|
||||
|
||||
// ----- Test add() ----- //
|
||||
|
||||
Set<int> set1(mAllocator);
|
||||
set1.add(10);
|
||||
set1.add(80);
|
||||
set1.add(130);
|
||||
test(set1.contains(10));
|
||||
test(set1.contains(80));
|
||||
test(set1.contains(130));
|
||||
test(set1.size() == 3);
|
||||
|
||||
Set<int> set2(mAllocator, 15);
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
set2.add(i);
|
||||
}
|
||||
bool isValid = true;
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
if (!set2.contains(i)) isValid = false;
|
||||
}
|
||||
test(isValid);
|
||||
|
||||
set1.remove(10);
|
||||
set1.add(10);
|
||||
test(set1.size() == 3);
|
||||
test(set1.contains(10));
|
||||
|
||||
set1.add(34);
|
||||
test(set1.contains(34));
|
||||
test(set1.size() == 4);
|
||||
|
||||
// ----- Test remove() ----- //
|
||||
|
||||
set1.remove(10);
|
||||
test(!set1.contains(10));
|
||||
test(set1.contains(80));
|
||||
test(set1.contains(130));
|
||||
test(set1.contains(34));
|
||||
test(set1.size() == 3);
|
||||
|
||||
set1.remove(80);
|
||||
test(!set1.contains(80));
|
||||
test(set1.contains(130));
|
||||
test(set1.contains(34));
|
||||
test(set1.size() == 2);
|
||||
|
||||
set1.remove(130);
|
||||
test(!set1.contains(130));
|
||||
test(set1.contains(34));
|
||||
test(set1.size() == 1);
|
||||
|
||||
set1.remove(34);
|
||||
test(!set1.contains(34));
|
||||
test(set1.size() == 0);
|
||||
|
||||
isValid = true;
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
set2.remove(i);
|
||||
}
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
if (set2.contains(i)) isValid = false;
|
||||
}
|
||||
test(isValid);
|
||||
test(set2.size() == 0);
|
||||
|
||||
Set<int> set3(mAllocator);
|
||||
for (int i=0; i < 1000000; i++) {
|
||||
set3.add(i);
|
||||
set3.remove(i);
|
||||
}
|
||||
|
||||
set3.add(1);
|
||||
set3.add(2);
|
||||
set3.add(3);
|
||||
test(set3.size() == 3);
|
||||
auto it = set3.begin();
|
||||
set3.remove(it++);
|
||||
test(!set3.contains(1));
|
||||
test(set3.size() == 2);
|
||||
test(*it == 2);
|
||||
|
||||
set3.add(6);
|
||||
set3.add(7);
|
||||
set3.add(8);
|
||||
for (it = set3.begin(); it != set3.end();) {
|
||||
it = set3.remove(it);
|
||||
}
|
||||
test(set3.size() == 0);
|
||||
|
||||
// ----- Test clear() ----- //
|
||||
|
||||
Set<int> set4(mAllocator);
|
||||
set4.add(2);
|
||||
set4.add(4);
|
||||
set4.add(6);
|
||||
set4.clear();
|
||||
test(set4.size() == 0);
|
||||
set4.add(2);
|
||||
test(set4.size() == 1);
|
||||
test(set4.contains(2));
|
||||
set4.clear();
|
||||
test(set4.size() == 0);
|
||||
|
||||
Set<int> set5(mAllocator);
|
||||
set5.clear();
|
||||
test(set5.size() == 0);
|
||||
|
||||
// ----- Test map with always same hash value for keys ----- //
|
||||
|
||||
Set<TestValueSet> set6(mAllocator);
|
||||
for (int i=0; i < 1000; i++) {
|
||||
set6.add(TestValueSet(i));
|
||||
}
|
||||
bool isTestValid = true;
|
||||
for (int i=0; i < 1000; i++) {
|
||||
if (!set6.contains(TestValueSet(i))) {
|
||||
isTestValid = false;
|
||||
}
|
||||
}
|
||||
test(isTestValid);
|
||||
for (int i=0; i < 1000; i++) {
|
||||
set6.remove(TestValueSet(i));
|
||||
}
|
||||
test(set6.size() == 0);
|
||||
}
|
||||
|
||||
void testContains() {
|
||||
|
||||
Set<int> set1(mAllocator);
|
||||
|
||||
test(!set1.contains(2));
|
||||
test(!set1.contains(4));
|
||||
test(!set1.contains(6));
|
||||
|
||||
set1.add(2);
|
||||
set1.add(4);
|
||||
set1.add(6);
|
||||
|
||||
test(set1.contains(2));
|
||||
test(set1.contains(4));
|
||||
test(set1.contains(6));
|
||||
|
||||
set1.remove(4);
|
||||
test(!set1.contains(4));
|
||||
test(set1.contains(2));
|
||||
test(set1.contains(6));
|
||||
|
||||
set1.clear();
|
||||
test(!set1.contains(2));
|
||||
test(!set1.contains(6));
|
||||
}
|
||||
|
||||
void testFind() {
|
||||
|
||||
Set<int> set1(mAllocator);
|
||||
set1.add(2);
|
||||
set1.add(4);
|
||||
set1.add(6);
|
||||
test(set1.find(2) != set1.end());
|
||||
test(set1.find(4) != set1.end());
|
||||
test(set1.find(6) != set1.end());
|
||||
test(set1.find(45) == set1.end());
|
||||
|
||||
set1.remove(2);
|
||||
|
||||
test(set1.find(2) == set1.end());
|
||||
}
|
||||
|
||||
void testEquality() {
|
||||
|
||||
Set<std::string> set1(mAllocator, 10);
|
||||
Set<std::string> set2(mAllocator, 2);
|
||||
|
||||
test(set1 == set2);
|
||||
|
||||
set1.add("a");
|
||||
set1.add("b");
|
||||
set1.add("c");
|
||||
|
||||
set2.add("a");
|
||||
set2.add("b");
|
||||
set2.add("h");
|
||||
|
||||
test(set1 == set1);
|
||||
test(set2 == set2);
|
||||
test(set1 != set2);
|
||||
test(set2 != set1);
|
||||
|
||||
set1.add("a");
|
||||
set2.remove("h");
|
||||
set2.add("c");
|
||||
|
||||
test(set1 == set2);
|
||||
test(set2 == set1);
|
||||
|
||||
Set<std::string> set3(mAllocator);
|
||||
set3.add("a");
|
||||
|
||||
test(set1 != set3);
|
||||
test(set2 != set3);
|
||||
test(set3 != set1);
|
||||
test(set3 != set2);
|
||||
}
|
||||
|
||||
void testAssignment() {
|
||||
|
||||
Set<int> set1(mAllocator);
|
||||
set1.add(1);
|
||||
set1.add(2);
|
||||
set1.add(10);
|
||||
|
||||
Set<int> set2(mAllocator);
|
||||
set2 = set1;
|
||||
test(set2.size() == set1.size());
|
||||
test(set2.contains(1));
|
||||
test(set2.contains(2));
|
||||
test(set2.contains(10));
|
||||
test(set1 == set2);
|
||||
|
||||
Set<int> set3(mAllocator, 100);
|
||||
set3 = set1;
|
||||
test(set3.size() == set1.size());
|
||||
test(set3 == set1);
|
||||
test(set3.contains(1));
|
||||
test(set3.contains(2));
|
||||
test(set3.contains(10));
|
||||
|
||||
Set<int> set4(mAllocator);
|
||||
set3 = set4;
|
||||
test(set3.size() == 0);
|
||||
test(set3 == set4);
|
||||
|
||||
Set<int> set5(mAllocator);
|
||||
set5.add(7);
|
||||
set5.add(19);
|
||||
set1 = set5;
|
||||
test(set5.size() == set1.size());
|
||||
test(set1 == set5);
|
||||
test(set1.contains(7));
|
||||
test(set1.contains(19));
|
||||
}
|
||||
|
||||
void testIterators() {
|
||||
|
||||
Set<int> set1(mAllocator);
|
||||
|
||||
test(set1.begin() == set1.end());
|
||||
|
||||
set1.add(1);
|
||||
set1.add(2);
|
||||
set1.add(3);
|
||||
set1.add(4);
|
||||
|
||||
Set<int>::Iterator itBegin = set1.begin();
|
||||
Set<int>::Iterator it = set1.begin();
|
||||
|
||||
test(itBegin == it);
|
||||
|
||||
int size = 0;
|
||||
for (auto it = set1.begin(); it != set1.end(); ++it) {
|
||||
test(set1.contains(*it));
|
||||
size++;
|
||||
}
|
||||
test(set1.size() == size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user