Replace std::set by Set and fix issues with List and Map

This commit is contained in:
Daniel Chappuis 2018-02-03 20:48:08 +01:00
parent 220057a587
commit b3e771838d
17 changed files with 1581 additions and 128 deletions

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -33,7 +33,6 @@
#include "collision/TriangleMesh.h"
#include "collision/PolyhedronMesh.h"
#include "collision/narrowphase/GJK/GJKAlgorithm.h"
#include <set>
/// ReactPhysics3D namespace
namespace reactphysics3d {

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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();

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 ---------- //

View File

@ -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);

View File

@ -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);
}

View 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