Refactoring and optimization of List and Set containers
This commit is contained in:
parent
a1e0e0aa94
commit
de6630a03d
File diff suppressed because it is too large
Load Diff
|
@ -47,197 +47,59 @@ 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;
|
||||
}
|
||||
|
||||
/// Copy-constructor
|
||||
Entry(const Entry& entry) {
|
||||
hashCode = entry.hashCode;
|
||||
next = entry.next;
|
||||
value = entry.value;
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~Entry() {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -------------------- Constants -------------------- //
|
||||
|
||||
/// Number of prime numbers in array
|
||||
static constexpr int NB_PRIMES = 70;
|
||||
/// Default load factor
|
||||
static constexpr float DEFAULT_LOAD_FACTOR = 0.75;
|
||||
|
||||
/// Array of prime numbers for the size of the set
|
||||
static const int PRIMES[NB_PRIMES];
|
||||
|
||||
/// Largest prime number
|
||||
static int LARGEST_PRIME;
|
||||
/// Invalid index in the array
|
||||
static constexpr uint32 INVALID_INDEX = 0xffffffff;
|
||||
|
||||
// -------------------- Attributes -------------------- //
|
||||
|
||||
/// Current number of used entries in the set
|
||||
int mNbUsedEntries;
|
||||
/// Total number of allocated entries
|
||||
uint32 mNbAllocatedEntries;
|
||||
|
||||
/// Number of free entries among the used ones
|
||||
int mNbFreeEntries;
|
||||
/// Number of items in the set
|
||||
uint32 mNbEntries;
|
||||
|
||||
/// Current capacity of the set
|
||||
int mCapacity;
|
||||
/// Number of buckets and size of the hash table (nbEntries = loadFactor * mHashSize)
|
||||
uint32 mHashSize ;
|
||||
|
||||
/// Array with all the buckets
|
||||
int* mBuckets;
|
||||
uint32* mBuckets;
|
||||
|
||||
/// Array with all the entries
|
||||
Entry* mEntries;
|
||||
/// Array with all the entries (nbEntries = loadFactor * mHashSize)
|
||||
V* mEntries;
|
||||
|
||||
/// For each entry, index of the next entry at the same bucket
|
||||
uint32* mNextEntries;
|
||||
|
||||
/// Memory allocator
|
||||
MemoryAllocator& mAllocator;
|
||||
|
||||
/// Index to the fist free entry
|
||||
int mFreeIndex;
|
||||
uint32 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;
|
||||
}
|
||||
|
||||
if (mNbUsedEntries > 0) {
|
||||
|
||||
// Copy the old entries to the new allocated memory location
|
||||
std::uninitialized_copy(mEntries, mEntries + mNbUsedEntries, newEntries);
|
||||
|
||||
// Destruct the old entries at previous location
|
||||
for (int i=0; i<mNbUsedEntries; i++) {
|
||||
mEntries[i].~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].value != nullptr) {
|
||||
|
||||
// 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 {
|
||||
uint32 findEntry(const V& value) const {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
if (mHashSize > 0) {
|
||||
|
||||
size_t hashCode = Hash()(value);
|
||||
int bucket = hashCode % mCapacity;
|
||||
auto keyEqual = KeyEqual();
|
||||
const size_t hashCode = Hash()(value);
|
||||
const uint32 bucket = hashCode & (mHashSize - 1);
|
||||
auto keyEqual = KeyEqual();
|
||||
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
if (mEntries[i].hashCode == hashCode && keyEqual(*mEntries[i].value, value)) {
|
||||
for (uint32 i = mBuckets[bucket]; i != INVALID_INDEX; i = mNextEntries[i]) {
|
||||
if (Hash()(mEntries[i]) == hashCode && keyEqual(mEntries[i], 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;
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -250,36 +112,36 @@ class Set {
|
|||
|
||||
private:
|
||||
|
||||
/// Array of entries
|
||||
const Entry* mEntries;
|
||||
/// Pointer to the set
|
||||
const Set* mSet;
|
||||
|
||||
/// Capacity of the map
|
||||
int mCapacity;
|
||||
|
||||
/// Number of used entries in the map
|
||||
int mNbUsedEntries;
|
||||
/// Index of the current bucket
|
||||
uint32 mCurrentBucketIndex;
|
||||
|
||||
/// Index of the current entry
|
||||
int mCurrentEntry;
|
||||
uint32 mCurrentEntryIndex;
|
||||
|
||||
/// Advance the iterator
|
||||
void advance() {
|
||||
|
||||
// If we are trying to move past the end
|
||||
assert(mCurrentEntry < mNbUsedEntries);
|
||||
assert(mCurrentBucketIndex < mSet->mHashSize);
|
||||
assert(mCurrentEntryIndex < mSet->mNbAllocatedEntries);
|
||||
|
||||
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;
|
||||
}
|
||||
// Try the next entry
|
||||
if (mSet->mNextEntries[mCurrentEntryIndex] != INVALID_INDEX) {
|
||||
mCurrentEntryIndex = mSet->mNextEntries[mCurrentEntryIndex];
|
||||
return;
|
||||
}
|
||||
|
||||
// We have not find a non empty entry, we return an iterator to the end
|
||||
mCurrentEntry = mCapacity;
|
||||
// Try to move to the next bucket
|
||||
mCurrentEntryIndex = 0;
|
||||
mCurrentBucketIndex++;
|
||||
while(mCurrentBucketIndex < mSet->mHashSize && mSet->mBuckets[mCurrentBucketIndex] == INVALID_INDEX) {
|
||||
mCurrentBucketIndex++;
|
||||
}
|
||||
if (mCurrentBucketIndex < mSet->mHashSize) {
|
||||
mCurrentEntryIndex = mSet->mBuckets[mCurrentBucketIndex];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -295,29 +157,29 @@ class Set {
|
|||
Iterator() = default;
|
||||
|
||||
/// Constructor
|
||||
Iterator(const Entry* entries, int capacity, int nbUsedEntries, int currentEntry)
|
||||
:mEntries(entries), mCapacity(capacity), mNbUsedEntries(nbUsedEntries), mCurrentEntry(currentEntry) {
|
||||
Iterator(const Set* set, uint32 bucketIndex, uint32 entryIndex)
|
||||
:mSet(set), mCurrentBucketIndex(bucketIndex), mCurrentEntryIndex(entryIndex) {
|
||||
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
Iterator(const Iterator& it)
|
||||
:mEntries(it.mEntries), mCapacity(it.mCapacity), mNbUsedEntries(it.mNbUsedEntries), mCurrentEntry(it.mCurrentEntry) {
|
||||
:mSet(it.mSet), mCurrentBucketIndex(it.mCurrentBucketIndex), mCurrentEntryIndex(it.mCurrentEntryIndex) {
|
||||
|
||||
}
|
||||
|
||||
/// Deferencable
|
||||
reference operator*() const {
|
||||
assert(mCurrentEntry >= 0 && mCurrentEntry < mNbUsedEntries);
|
||||
assert(mEntries[mCurrentEntry].value != nullptr);
|
||||
return *(mEntries[mCurrentEntry].value);
|
||||
assert(mCurrentEntryIndex < mSet->mNbAllocatedEntries);
|
||||
assert(mCurrentEntryIndex != INVALID_INDEX);
|
||||
return mSet->mEntries[mCurrentEntryIndex];
|
||||
}
|
||||
|
||||
/// Deferencable
|
||||
pointer operator->() const {
|
||||
assert(mCurrentEntry >= 0 && mCurrentEntry < mNbUsedEntries);
|
||||
assert(mEntries[mCurrentEntry].value != nullptr);
|
||||
return mEntries[mCurrentEntry].value;
|
||||
assert(mCurrentEntryIndex < mSet->mNbAllocatedEntries);
|
||||
assert(mCurrentEntryIndex != INVALID_INDEX);
|
||||
return &(mSet->mEntries[mCurrentEntryIndex]);
|
||||
}
|
||||
|
||||
/// Post increment (it++)
|
||||
|
@ -335,61 +197,71 @@ class Set {
|
|||
|
||||
/// Equality operator (it == end())
|
||||
bool operator==(const Iterator& iterator) const {
|
||||
return mCurrentEntry == iterator.mCurrentEntry && mEntries == iterator.mEntries;
|
||||
return mCurrentBucketIndex == iterator.mCurrentBucketIndex && mCurrentEntryIndex == iterator.mCurrentEntryIndex && mSet == iterator.mSet;
|
||||
}
|
||||
|
||||
/// Inequality operator (it != end())
|
||||
bool operator!=(const Iterator& iterator) const {
|
||||
return !(*this == iterator);
|
||||
}
|
||||
|
||||
/// Overloaded assignment operator
|
||||
Iterator& operator=(const Iterator& it) {
|
||||
|
||||
// Check for self assignment
|
||||
if (this != &it) {
|
||||
|
||||
mSet = it.mSet;
|
||||
mCurrentBucketIndex = it.mCurrentBucketIndex;
|
||||
mCurrentEntryIndex = it.mCurrentEntryIndex;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------- 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);
|
||||
}
|
||||
Set(MemoryAllocator& allocator, uint32 capacity = 0)
|
||||
: mNbAllocatedEntries(0), mNbEntries(0), mHashSize(0), mBuckets(nullptr),
|
||||
mEntries(nullptr), mNextEntries(nullptr), mAllocator(allocator), mFreeIndex(INVALID_INDEX) {
|
||||
|
||||
if (capacity > 0) {
|
||||
|
||||
initialize(capacity);
|
||||
reserve(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
Set(const Set<V, Hash, KeyEqual>& set)
|
||||
:mNbUsedEntries(set.mNbUsedEntries), mNbFreeEntries(set.mNbFreeEntries), mCapacity(set.mCapacity),
|
||||
mBuckets(nullptr), mEntries(nullptr), mAllocator(set.mAllocator), mFreeIndex(set.mFreeIndex) {
|
||||
:mNbAllocatedEntries(set.mNbAllocatedEntries), mNbEntries(set.mNbEntries), mHashSize(set.mHashSize),
|
||||
mBuckets(nullptr), mEntries(nullptr), mNextEntries(nullptr), mAllocator(set.mAllocator), mFreeIndex(set.mFreeIndex) {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<uint32*>(mAllocator.allocate(mHashSize * sizeof(uint32)));
|
||||
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<V*>(mAllocator.allocate(mNbAllocatedEntries * sizeof(V)));
|
||||
mNextEntries = static_cast<uint32*>(mAllocator.allocate(mNbAllocatedEntries * sizeof(uint32)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||
// Copy the buckets array
|
||||
std::memcpy(mBuckets, set.mBuckets, mHashSize * sizeof(uint32));
|
||||
|
||||
// Copy the buckets
|
||||
std::uninitialized_copy(set.mBuckets, set.mBuckets + mCapacity, mBuckets);
|
||||
// Copy the next entries indices
|
||||
std::memcpy(mNextEntries, set.mNextEntries, mNbAllocatedEntries * sizeof(uint32));
|
||||
|
||||
// Copy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
// Copy the entries
|
||||
for (uint32 i=0; i<mHashSize; i++) {
|
||||
|
||||
new (&mEntries[i]) Entry(set.mEntries[i].hashCode, set.mEntries[i].next);
|
||||
uint32 entryIndex = mBuckets[i];
|
||||
while(entryIndex != INVALID_INDEX) {
|
||||
|
||||
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));
|
||||
}
|
||||
// Copy the entry to the new location and destroy the previous one
|
||||
new (mEntries + entryIndex) V(set.mEntries[entryIndex]);
|
||||
|
||||
entryIndex = mNextEntries[entryIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,82 +273,146 @@ class Set {
|
|||
}
|
||||
|
||||
/// Allocate memory for a given number of elements
|
||||
void reserve(int capacity) {
|
||||
void reserve(uint32 capacity) {
|
||||
|
||||
if (capacity <= mCapacity) return;
|
||||
if (capacity <= mHashSize) return;
|
||||
|
||||
if (capacity > LARGEST_PRIME && LARGEST_PRIME > mCapacity) {
|
||||
capacity = LARGEST_PRIME;
|
||||
}
|
||||
else {
|
||||
capacity = getPrimeSize(capacity);
|
||||
}
|
||||
if (capacity < 16) capacity = 16;
|
||||
|
||||
expand(capacity);
|
||||
// Make sure we have a power of two size
|
||||
if (!isPowerOfTwo(capacity)) {
|
||||
capacity = nextPowerOfTwo32Bits(capacity);
|
||||
}
|
||||
|
||||
assert(capacity < INVALID_INDEX);
|
||||
|
||||
assert(capacity > mHashSize);
|
||||
|
||||
// Allocate memory for the buckets
|
||||
uint32* newBuckets = static_cast<uint32*>(mAllocator.allocate(capacity * sizeof(uint32)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
const uint32 nbAllocatedEntries = capacity * DEFAULT_LOAD_FACTOR;
|
||||
assert(nbAllocatedEntries > 0);
|
||||
V* newEntries = static_cast<V*>(mAllocator.allocate(nbAllocatedEntries * sizeof(V)));
|
||||
uint32* newNextEntries = static_cast<uint32*>(mAllocator.allocate(nbAllocatedEntries * sizeof(uint32)));
|
||||
|
||||
assert(newEntries != nullptr);
|
||||
assert(newNextEntries != nullptr);
|
||||
|
||||
// Initialize the new buckets
|
||||
for (uint32 i=0; i<capacity; i++) {
|
||||
newBuckets[i] = INVALID_INDEX;
|
||||
}
|
||||
|
||||
if (mNbAllocatedEntries > 0) {
|
||||
|
||||
assert(mNextEntries != nullptr);
|
||||
|
||||
// Copy the free nodes indices in the nextEntries array
|
||||
std::memcpy(newNextEntries, mNextEntries, mNbAllocatedEntries * sizeof(uint32));
|
||||
}
|
||||
|
||||
// Recompute the buckets (hash) with the new hash size
|
||||
for (uint32 i=0; i<mHashSize; i++) {
|
||||
|
||||
uint32 entryIndex = mBuckets[i];
|
||||
while(entryIndex != INVALID_INDEX) {
|
||||
|
||||
// Get the corresponding bucket
|
||||
const size_t hashCode = Hash()(mEntries[entryIndex]);
|
||||
const uint32 bucketIndex = hashCode & (capacity - 1);
|
||||
|
||||
newNextEntries[entryIndex] = newBuckets[bucketIndex];
|
||||
newBuckets[bucketIndex] = entryIndex;
|
||||
|
||||
// Copy the entry to the new location and destroy the previous one
|
||||
new (newEntries + entryIndex) V(mEntries[entryIndex]);
|
||||
mEntries[entryIndex].~V();
|
||||
|
||||
entryIndex = mNextEntries[entryIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if (mNbAllocatedEntries > 0) {
|
||||
|
||||
// Release previously allocated memory
|
||||
mAllocator.release(mBuckets, mHashSize * sizeof(uint32));
|
||||
mAllocator.release(mEntries, mNbAllocatedEntries * sizeof(V));
|
||||
mAllocator.release(mNextEntries, mNbAllocatedEntries * sizeof(uint32));
|
||||
}
|
||||
|
||||
// Add the new entries to the free list
|
||||
for (uint32 i=mNbAllocatedEntries; i < nbAllocatedEntries-1; i++) {
|
||||
newNextEntries[i] = i + 1;
|
||||
}
|
||||
newNextEntries[nbAllocatedEntries - 1] = mFreeIndex;
|
||||
mFreeIndex = mNbAllocatedEntries;
|
||||
|
||||
mHashSize = capacity;
|
||||
mNbAllocatedEntries = nbAllocatedEntries;
|
||||
mBuckets = newBuckets;
|
||||
mEntries = newEntries;
|
||||
mNextEntries = newNextEntries;
|
||||
|
||||
assert(mFreeIndex != INVALID_INDEX);
|
||||
}
|
||||
|
||||
/// Return true if the set contains a given value
|
||||
bool contains(const V& value) const {
|
||||
return findEntry(value) != -1;
|
||||
return findEntry(value) != INVALID_INDEX;
|
||||
}
|
||||
|
||||
/// Add a value into the set.
|
||||
/// Returns true if the item has been inserted and false otherwise.
|
||||
bool add(const V& value) {
|
||||
|
||||
if (mCapacity == 0) {
|
||||
initialize(0);
|
||||
}
|
||||
uint32 bucket;
|
||||
|
||||
// Compute the hash code of the value
|
||||
size_t hashCode = Hash()(value);
|
||||
const size_t hashCode = Hash()(value);
|
||||
|
||||
// Compute the corresponding bucket index
|
||||
int bucket = hashCode % mCapacity;
|
||||
if (mHashSize > 0) {
|
||||
|
||||
auto keyEqual = KeyEqual();
|
||||
// Compute the corresponding bucket index
|
||||
bucket = hashCode & (mHashSize - 1);
|
||||
|
||||
// Check if the item is already in the set
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
auto keyEqual = KeyEqual();
|
||||
|
||||
// If there is already an item with the same value in the set
|
||||
if (mEntries[i].hashCode == hashCode && keyEqual(*mEntries[i].value, value)) {
|
||||
// Check if the item is already in the set
|
||||
for (uint32 i = mBuckets[bucket]; i != INVALID_INDEX; i = mNextEntries[i]) {
|
||||
|
||||
return false;
|
||||
// If there is already an item with the same value in the set
|
||||
if (Hash()(mEntries[i]) == hashCode && keyEqual(mEntries[i], value)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 there are no more free entries to use
|
||||
if (mFreeIndex == INVALID_INDEX) {
|
||||
|
||||
// If we need to allocator more entries
|
||||
if (mNbUsedEntries == mCapacity) {
|
||||
// Allocate more memory
|
||||
reserve(mHashSize == 0 ? 16 : mHashSize * 2);
|
||||
|
||||
// Allocate more memory
|
||||
reserve(mCapacity * 2);
|
||||
|
||||
// Recompute the bucket index
|
||||
bucket = hashCode % mCapacity;
|
||||
}
|
||||
|
||||
entryIndex = mNbUsedEntries;
|
||||
mNbUsedEntries++;
|
||||
// Recompute the bucket index
|
||||
bucket = hashCode & (mHashSize - 1);
|
||||
}
|
||||
|
||||
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);
|
||||
assert(mNbEntries < mNbAllocatedEntries);
|
||||
assert(mFreeIndex != INVALID_INDEX);
|
||||
|
||||
// Get the next free entry
|
||||
entryIndex = mFreeIndex;
|
||||
mFreeIndex = mNextEntries[entryIndex];
|
||||
|
||||
mNbEntries++;
|
||||
|
||||
mNextEntries[entryIndex] = mBuckets[bucket];
|
||||
new (mEntries + entryIndex) V(value);
|
||||
mBuckets[bucket] = entryIndex;
|
||||
|
||||
return true;
|
||||
|
@ -495,46 +431,46 @@ class Set {
|
|||
/// element after the one that has been removed
|
||||
Iterator remove(const V& value) {
|
||||
|
||||
if (mCapacity > 0) {
|
||||
if (mHashSize > 0) {
|
||||
|
||||
size_t hashcode = Hash()(value);
|
||||
auto keyEqual = KeyEqual();
|
||||
int bucket = hashcode % mCapacity;
|
||||
int last = -1;
|
||||
for (int i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].next) {
|
||||
const size_t hashcode = Hash()(value);
|
||||
auto keyEqual = KeyEqual();
|
||||
const uint32 bucket = hashcode & (mHashSize - 1);
|
||||
uint32 last = INVALID_INDEX;
|
||||
for (uint32 i = mBuckets[bucket]; i != INVALID_INDEX; last = i, i = mNextEntries[i]) {
|
||||
|
||||
if (mEntries[i].hashCode == hashcode && keyEqual(*mEntries[i].value, value)) {
|
||||
// If we have found the item
|
||||
if (Hash()(mEntries[i]) == hashcode && keyEqual(mEntries[i], value)) {
|
||||
|
||||
if (last < 0 ) {
|
||||
mBuckets[bucket] = mEntries[i].next;
|
||||
if (last == INVALID_INDEX) {
|
||||
mBuckets[bucket] = mNextEntries[i];
|
||||
}
|
||||
else {
|
||||
mEntries[last].next = mEntries[i].next;
|
||||
mNextEntries[last] = mNextEntries[i];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
assert(mEntries[i].value == nullptr);
|
||||
mEntries[i].next = mFreeIndex;
|
||||
uint32 nextEntryIndex = mNextEntries[i];
|
||||
uint32 nextBucketIndex = bucket;
|
||||
|
||||
mEntries[i].~V();
|
||||
mNextEntries[i] = mFreeIndex;
|
||||
mFreeIndex = i;
|
||||
mNbFreeEntries++;
|
||||
mNbEntries--;
|
||||
|
||||
// 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);
|
||||
// Find the next entry to return an iterator
|
||||
if (nextEntryIndex == INVALID_INDEX) {
|
||||
nextEntryIndex = 0;
|
||||
nextBucketIndex++;
|
||||
while(nextBucketIndex < mHashSize && mBuckets[nextBucketIndex] == INVALID_INDEX) {
|
||||
nextBucketIndex++;
|
||||
}
|
||||
if (nextBucketIndex < mHashSize) {
|
||||
nextEntryIndex = mBuckets[nextBucketIndex];
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
// We have found the next non empty entry
|
||||
return Iterator(this, nextBucketIndex, nextEntryIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -547,10 +483,8 @@ class Set {
|
|||
|
||||
List<V> list(listAllocator);
|
||||
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
if (mEntries[i].value != nullptr) {
|
||||
list.add(*(mEntries[i].value));
|
||||
}
|
||||
for (auto it = begin(); it != end(); ++it) {
|
||||
list.add(*it);
|
||||
}
|
||||
|
||||
return list;
|
||||
|
@ -559,50 +493,52 @@ class Set {
|
|||
/// Clear the set
|
||||
void clear(bool releaseMemory = false) {
|
||||
|
||||
if (mNbUsedEntries > 0) {
|
||||
for (uint32 i=0; i<mHashSize; i++) {
|
||||
|
||||
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;
|
||||
}
|
||||
uint32 entryIndex = mBuckets[i];
|
||||
while(entryIndex != INVALID_INDEX) {
|
||||
|
||||
// Destroy the entry
|
||||
mEntries[entryIndex].~V();
|
||||
|
||||
uint32 nextEntryIndex = mNextEntries[entryIndex];
|
||||
|
||||
// Add entry to the free list
|
||||
mNextEntries[entryIndex] = mFreeIndex;
|
||||
mFreeIndex = entryIndex;
|
||||
|
||||
entryIndex = nextEntryIndex;
|
||||
}
|
||||
|
||||
mFreeIndex = -1;
|
||||
mNbUsedEntries = 0;
|
||||
mNbFreeEntries = 0;
|
||||
mBuckets[i] = INVALID_INDEX;
|
||||
}
|
||||
|
||||
// If elements have been allocated
|
||||
if (releaseMemory && mCapacity > 0) {
|
||||
if (releaseMemory && mNbAllocatedEntries > 0) {
|
||||
|
||||
// Destroy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
mEntries[i].~Entry();
|
||||
}
|
||||
// Release previously allocated memory
|
||||
mAllocator.release(mBuckets, mHashSize * sizeof(uint32));
|
||||
mAllocator.release(mEntries, mNbAllocatedEntries * sizeof(V));
|
||||
mAllocator.release(mNextEntries, mNbAllocatedEntries * sizeof(uint32));
|
||||
|
||||
mAllocator.release(mBuckets, mCapacity * sizeof(int));
|
||||
mAllocator.release(mEntries, mCapacity * sizeof(Entry));
|
||||
|
||||
mCapacity = 0;
|
||||
mBuckets = nullptr;
|
||||
mEntries = nullptr;
|
||||
mNextEntries = nullptr;
|
||||
|
||||
mNbAllocatedEntries = 0;
|
||||
mHashSize = 0;
|
||||
}
|
||||
|
||||
assert(size() == 0);
|
||||
mNbEntries = 0;
|
||||
}
|
||||
|
||||
/// Return the number of elements in the set
|
||||
int size() const {
|
||||
return mNbUsedEntries - mNbFreeEntries;
|
||||
uint32 size() const {
|
||||
return mNbEntries;
|
||||
}
|
||||
|
||||
/// Return the capacity of the set
|
||||
int capacity() const {
|
||||
return mCapacity;
|
||||
uint32 capacity() const {
|
||||
return mHashSize;
|
||||
}
|
||||
|
||||
/// Try to find an item of the set given a key.
|
||||
|
@ -610,30 +546,28 @@ class Set {
|
|||
/// an iterator pointing to the end if not found
|
||||
Iterator find(const V& value) const {
|
||||
|
||||
int bucket;
|
||||
int entry = -1;
|
||||
uint32 bucket;
|
||||
uint32 entry = INVALID_INDEX;
|
||||
|
||||
if (mCapacity > 0) {
|
||||
if (mHashSize > 0) {
|
||||
|
||||
size_t hashCode = Hash()(value);
|
||||
bucket = hashCode % mCapacity;
|
||||
auto keyEqual = KeyEqual();
|
||||
const size_t hashCode = Hash()(value);
|
||||
bucket = hashCode & (mHashSize - 1);
|
||||
auto keyEqual = KeyEqual();
|
||||
|
||||
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||
if (mEntries[i].hashCode == hashCode && keyEqual(*(mEntries[i].value), value)) {
|
||||
for (uint32 i = mBuckets[bucket]; i != INVALID_INDEX; i = mNextEntries[i]) {
|
||||
if (Hash()(mEntries[i]) == hashCode && keyEqual(mEntries[i], value)) {
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == -1) {
|
||||
if (entry == INVALID_INDEX) {
|
||||
return end();
|
||||
}
|
||||
|
||||
assert(mEntries[entry].value != nullptr);
|
||||
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, entry);
|
||||
return Iterator(this, bucket, entry);
|
||||
}
|
||||
|
||||
/// Overloaded equality operator
|
||||
|
@ -665,34 +599,35 @@ class Set {
|
|||
// Clear the set
|
||||
clear(true);
|
||||
|
||||
if (set.mCapacity > 0) {
|
||||
mNbAllocatedEntries = set.mNbAllocatedEntries;
|
||||
mNbEntries = set.mNbEntries;
|
||||
mHashSize = set.mHashSize;
|
||||
mFreeIndex = set.mFreeIndex;
|
||||
|
||||
// Compute the next larger prime size
|
||||
mCapacity = getPrimeSize(set.mCapacity);
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<uint32*>(mAllocator.allocate(mHashSize * sizeof(uint32)));
|
||||
|
||||
// Allocate memory for the buckets
|
||||
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<V*>(mAllocator.allocate(mNbAllocatedEntries * sizeof(V)));
|
||||
mNextEntries = static_cast<uint32*>(mAllocator.allocate(mNbAllocatedEntries * sizeof(uint32)));
|
||||
|
||||
// Allocate memory for the entries
|
||||
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||
// Copy the buckets array
|
||||
std::memcpy(mBuckets, set.mBuckets, mHashSize * sizeof(uint32));
|
||||
|
||||
// Copy the buckets
|
||||
std::uninitialized_copy(set.mBuckets, set.mBuckets + mCapacity, mBuckets);
|
||||
// Copy the next entries indices
|
||||
std::memcpy(mNextEntries, set.mNextEntries, mNbAllocatedEntries * sizeof(uint32));
|
||||
|
||||
// Copy the entries
|
||||
for (int i=0; i < mCapacity; i++) {
|
||||
// Copy the entries
|
||||
for (uint32 i=0; i<mHashSize; i++) {
|
||||
|
||||
new (&mEntries[i]) Entry(set.mEntries[i].hashCode, set.mEntries[i].next);
|
||||
uint32 entryIndex = mBuckets[i];
|
||||
while(entryIndex != INVALID_INDEX) {
|
||||
|
||||
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));
|
||||
}
|
||||
// Copy the entry to the new location and destroy the previous one
|
||||
new (mEntries + entryIndex) V(set.mEntries[entryIndex]);
|
||||
|
||||
entryIndex = mNextEntries[entryIndex];
|
||||
}
|
||||
|
||||
mNbUsedEntries = set.mNbUsedEntries;
|
||||
mNbFreeEntries = set.mNbFreeEntries;
|
||||
mFreeIndex = set.mFreeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,7 +637,7 @@ class Set {
|
|||
/// Return a begin iterator
|
||||
Iterator begin() const {
|
||||
|
||||
// If the map is empty
|
||||
// If the set is empty
|
||||
if (size() == 0) {
|
||||
|
||||
// Return an iterator to the end
|
||||
|
@ -710,33 +645,29 @@ class Set {
|
|||
}
|
||||
|
||||
// Find the first used entry
|
||||
int entry;
|
||||
for (entry=0; entry < mNbUsedEntries; entry++) {
|
||||
if (mEntries[entry].value != nullptr) {
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, entry);
|
||||
}
|
||||
uint32 bucketIndex = 0;
|
||||
while (mBuckets[bucketIndex] == INVALID_INDEX) {
|
||||
|
||||
bucketIndex++;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return end();
|
||||
assert(bucketIndex < mHashSize);
|
||||
assert(mBuckets[bucketIndex] != INVALID_INDEX);
|
||||
|
||||
return Iterator(this, bucketIndex, mBuckets[bucketIndex]);
|
||||
}
|
||||
|
||||
/// Return a end iterator
|
||||
Iterator end() const {
|
||||
return Iterator(mEntries, mCapacity, mNbUsedEntries, mCapacity);
|
||||
|
||||
return Iterator(this, mHashSize, 0);
|
||||
}
|
||||
|
||||
// ---------- Friendship ---------- //
|
||||
|
||||
friend class Iterator;
|
||||
};
|
||||
|
||||
template<typename V, class Hash, class KeyEqual>
|
||||
const int Set<V, Hash, KeyEqual>::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, class Hash, class KeyEqual>
|
||||
int Set<V, Hash, KeyEqual>::LARGEST_PRIME = -1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -97,6 +97,36 @@ class PhysicsCommon {
|
|||
/// Destroy and release everything that has been allocated
|
||||
void release();
|
||||
|
||||
/// Delete an instance of PhysicsWorld
|
||||
void deletePhysicsWorld(PhysicsWorld* world);
|
||||
|
||||
/// Delete a sphere collision shape
|
||||
void deleteSphereShape(SphereShape* sphereShape);
|
||||
|
||||
/// Delete a box collision shape
|
||||
void deleteBoxShape(BoxShape* boxShape);
|
||||
|
||||
/// Delete a capsule collision shape
|
||||
void deleteCapsuleShape(CapsuleShape* capsuleShape);
|
||||
|
||||
/// Delete a convex mesh shape
|
||||
void deleteConvexMeshShape(ConvexMeshShape* convexMeshShape);
|
||||
|
||||
/// Delete a height-field shape
|
||||
void deleteHeightFieldShape(HeightFieldShape* heightFieldShape);
|
||||
|
||||
/// Delete a concave mesh shape
|
||||
void deleteConcaveMeshShape(ConcaveMeshShape* concaveMeshShape);
|
||||
|
||||
/// Delete a polyhedron mesh
|
||||
void deletePolyhedronMesh(PolyhedronMesh* polyhedronMesh);
|
||||
|
||||
/// Delete a triangle mesh
|
||||
void deleteTriangleMesh(TriangleMesh* triangleMesh);
|
||||
|
||||
/// Delete a default logger
|
||||
void deleteDefaultLogger(DefaultLogger* logger);
|
||||
|
||||
// If profiling is enabled
|
||||
#ifdef IS_RP3D_PROFILING_ENABLED
|
||||
|
||||
|
@ -106,6 +136,9 @@ class PhysicsCommon {
|
|||
/// Destroy a profiler
|
||||
void destroyProfiler(Profiler* profiler);
|
||||
|
||||
/// Delete a profiler
|
||||
void deleteProfiler(Profiler* profiler);
|
||||
|
||||
#endif
|
||||
|
||||
public :
|
||||
|
@ -186,7 +219,6 @@ class PhysicsCommon {
|
|||
|
||||
/// Set the logger
|
||||
static void setLogger(Logger* logger);
|
||||
|
||||
};
|
||||
|
||||
// Return the current logger
|
||||
|
|
|
@ -126,8 +126,23 @@ Vector3 projectPointOntoPlane(const Vector3& point, const Vector3& planeNormal,
|
|||
/// Return the distance between a point and a plane (the plane normal must be normalized)
|
||||
decimal computePointToPlaneDistance(const Vector3& point, const Vector3& planeNormal, const Vector3& planePoint);
|
||||
|
||||
/// Return true if the given number is prime
|
||||
bool isPrimeNumber(int number);
|
||||
/// Return true if a number is a power of two
|
||||
RP3D_FORCE_INLINE bool isPowerOfTwo(uint32 number) {
|
||||
return number != 0 && !(number & (number -1));
|
||||
}
|
||||
|
||||
/// Return the next power of two larger than the number in parameter
|
||||
RP3D_FORCE_INLINE uint32 nextPowerOfTwo32Bits(uint32 number) {
|
||||
number--;
|
||||
number |= number >> 1;
|
||||
number |= number >> 2;
|
||||
number |= number >> 4;
|
||||
number |= number >> 8;
|
||||
number |= number >> 16;
|
||||
number++;
|
||||
number += (number == 0);
|
||||
return number;
|
||||
}
|
||||
|
||||
/// Return an unique integer from two integer numbers (pairing function)
|
||||
/// Here we assume that the two parameter numbers are sorted such that
|
||||
|
|
|
@ -58,53 +58,63 @@ void PhysicsCommon::release() {
|
|||
|
||||
// Destroy the physics worlds
|
||||
for (auto it = mPhysicsWorlds.begin(); it != mPhysicsWorlds.end(); ++it) {
|
||||
destroyPhysicsWorld(*it);
|
||||
deletePhysicsWorld(*it);
|
||||
}
|
||||
mPhysicsWorlds.clear();
|
||||
|
||||
// Destroy the sphere shapes
|
||||
for (auto it = mSphereShapes.begin(); it != mSphereShapes.end(); ++it) {
|
||||
destroySphereShape(*it);
|
||||
deleteSphereShape(*it);
|
||||
}
|
||||
mSphereShapes.clear();
|
||||
|
||||
// Destroy the box shapes
|
||||
for (auto it = mBoxShapes.begin(); it != mBoxShapes.end(); ++it) {
|
||||
destroyBoxShape(*it);
|
||||
deleteBoxShape(*it);
|
||||
}
|
||||
mBoxShapes.clear();
|
||||
|
||||
// Destroy the capsule shapes
|
||||
for (auto it = mCapsuleShapes.begin(); it != mCapsuleShapes.end(); ++it) {
|
||||
destroyCapsuleShape(*it);
|
||||
deleteCapsuleShape(*it);
|
||||
}
|
||||
mCapsuleShapes.clear();
|
||||
|
||||
// Destroy the convex mesh shapes
|
||||
for (auto it = mConvexMeshShapes.begin(); it != mConvexMeshShapes.end(); ++it) {
|
||||
destroyConvexMeshShape(*it);
|
||||
deleteConvexMeshShape(*it);
|
||||
}
|
||||
mConvexMeshShapes.clear();
|
||||
|
||||
// Destroy the heigh-field shapes
|
||||
for (auto it = mHeightFieldShapes.begin(); it != mHeightFieldShapes.end(); ++it) {
|
||||
destroyHeightFieldShape(*it);
|
||||
deleteHeightFieldShape(*it);
|
||||
}
|
||||
mHeightFieldShapes.clear();
|
||||
|
||||
// Destroy the concave mesh shapes
|
||||
for (auto it = mConcaveMeshShapes.begin(); it != mConcaveMeshShapes.end(); ++it) {
|
||||
destroyConcaveMeshShape(*it);
|
||||
deleteConcaveMeshShape(*it);
|
||||
}
|
||||
mConcaveMeshShapes.clear();
|
||||
|
||||
// Destroy the polyhedron mesh
|
||||
for (auto it = mPolyhedronMeshes.begin(); it != mPolyhedronMeshes.end(); ++it) {
|
||||
destroyPolyhedronMesh(*it);
|
||||
deletePolyhedronMesh(*it);
|
||||
}
|
||||
mPolyhedronMeshes.clear();
|
||||
|
||||
// Destroy the triangle mesh
|
||||
for (auto it = mTriangleMeshes.begin(); it != mTriangleMeshes.end(); ++it) {
|
||||
destroyTriangleMesh(*it);
|
||||
deleteTriangleMesh(*it);
|
||||
}
|
||||
mTriangleMeshes.clear();
|
||||
|
||||
// Destroy the default loggers
|
||||
for (auto it = mDefaultLoggers.begin(); it != mDefaultLoggers.end(); ++it) {
|
||||
destroyDefaultLogger(*it);
|
||||
deleteDefaultLogger(*it);
|
||||
}
|
||||
mDefaultLoggers.clear();
|
||||
|
||||
// If profiling is enabled
|
||||
#ifdef IS_RP3D_PROFILING_ENABLED
|
||||
|
@ -112,8 +122,9 @@ void PhysicsCommon::release() {
|
|||
|
||||
// Destroy the profilers
|
||||
for (auto it = mProfilers.begin(); it != mProfilers.end(); ++it) {
|
||||
destroyProfiler(*it);
|
||||
deleteProfiler(*it);
|
||||
}
|
||||
mProfilers.clear();
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -151,13 +162,22 @@ PhysicsWorld* PhysicsCommon::createPhysicsWorld(const PhysicsWorld::WorldSetting
|
|||
*/
|
||||
void PhysicsCommon::destroyPhysicsWorld(PhysicsWorld* world) {
|
||||
|
||||
deletePhysicsWorld(world);
|
||||
|
||||
mPhysicsWorlds.remove(world);
|
||||
}
|
||||
|
||||
// Delete an instance of PhysicsWorld
|
||||
/**
|
||||
* @param world A pointer to the physics world to destroy
|
||||
*/
|
||||
void PhysicsCommon::deletePhysicsWorld(PhysicsWorld* world) {
|
||||
|
||||
// Call the destructor of the world
|
||||
world->~PhysicsWorld();
|
||||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Heap, world, sizeof(PhysicsWorld));
|
||||
|
||||
mPhysicsWorlds.remove(world);
|
||||
}
|
||||
|
||||
// Create and return a sphere collision shape
|
||||
|
@ -185,6 +205,17 @@ SphereShape* PhysicsCommon::createSphereShape(const decimal radius) {
|
|||
*/
|
||||
void PhysicsCommon::destroySphereShape(SphereShape* sphereShape) {
|
||||
|
||||
deleteSphereShape(sphereShape);
|
||||
|
||||
mSphereShapes.remove(sphereShape);
|
||||
}
|
||||
|
||||
// Delete a sphere collision shape
|
||||
/**
|
||||
* @param sphereShape A pointer to the sphere collision shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteSphereShape(SphereShape* sphereShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (sphereShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -197,8 +228,6 @@ void PhysicsCommon::destroySphereShape(SphereShape* sphereShape) {
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, sphereShape, sizeof(SphereShape));
|
||||
|
||||
mSphereShapes.remove(sphereShape);
|
||||
}
|
||||
|
||||
// Create and return a box collision shape
|
||||
|
@ -226,6 +255,17 @@ BoxShape* PhysicsCommon::createBoxShape(const Vector3& halfExtents) {
|
|||
*/
|
||||
void PhysicsCommon::destroyBoxShape(BoxShape* boxShape) {
|
||||
|
||||
deleteBoxShape(boxShape);
|
||||
|
||||
mBoxShapes.remove(boxShape);
|
||||
}
|
||||
|
||||
// Delete a box collision shape
|
||||
/**
|
||||
* @param boxShape A pointer to the box shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteBoxShape(BoxShape* boxShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (boxShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -238,8 +278,6 @@ void PhysicsCommon::destroyBoxShape(BoxShape* boxShape) {
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, boxShape, sizeof(BoxShape));
|
||||
|
||||
mBoxShapes.remove(boxShape);
|
||||
}
|
||||
|
||||
// Create and return a capsule shape
|
||||
|
@ -275,6 +313,17 @@ CapsuleShape* PhysicsCommon::createCapsuleShape(decimal radius, decimal height)
|
|||
*/
|
||||
void PhysicsCommon::destroyCapsuleShape(CapsuleShape* capsuleShape) {
|
||||
|
||||
deleteCapsuleShape(capsuleShape);
|
||||
|
||||
mCapsuleShapes.remove(capsuleShape);
|
||||
}
|
||||
|
||||
// Delete a capsule collision shape
|
||||
/**
|
||||
* @param capsuleShape A pointer to the capsule shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteCapsuleShape(CapsuleShape* capsuleShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (capsuleShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -287,8 +336,6 @@ void PhysicsCommon::destroyCapsuleShape(CapsuleShape* capsuleShape) {
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, capsuleShape, sizeof(CapsuleShape));
|
||||
|
||||
mCapsuleShapes.remove(capsuleShape);
|
||||
}
|
||||
|
||||
// Create and return a convex mesh shape
|
||||
|
@ -312,6 +359,17 @@ ConvexMeshShape* PhysicsCommon::createConvexMeshShape(PolyhedronMesh* polyhedron
|
|||
*/
|
||||
void PhysicsCommon::destroyConvexMeshShape(ConvexMeshShape* convexMeshShape) {
|
||||
|
||||
deleteConvexMeshShape(convexMeshShape);
|
||||
|
||||
mConvexMeshShapes.remove(convexMeshShape);
|
||||
}
|
||||
|
||||
// Delete a convex mesh shape
|
||||
/**
|
||||
* @param convexMeshShape A pointer to the convex mesh shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteConvexMeshShape(ConvexMeshShape* convexMeshShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (convexMeshShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -324,8 +382,6 @@ void PhysicsCommon::destroyConvexMeshShape(ConvexMeshShape* convexMeshShape) {
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, convexMeshShape, sizeof(ConvexMeshShape));
|
||||
|
||||
mConvexMeshShapes.remove(convexMeshShape);
|
||||
}
|
||||
|
||||
// Create and return a height-field shape
|
||||
|
@ -358,6 +414,17 @@ HeightFieldShape* PhysicsCommon::createHeightFieldShape(int nbGridColumns, int n
|
|||
*/
|
||||
void PhysicsCommon::destroyHeightFieldShape(HeightFieldShape* heightFieldShape) {
|
||||
|
||||
deleteHeightFieldShape(heightFieldShape);
|
||||
|
||||
mHeightFieldShapes.remove(heightFieldShape);
|
||||
}
|
||||
|
||||
// Delete a height-field shape
|
||||
/**
|
||||
* @param heightFieldShape A pointer to the height field shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteHeightFieldShape(HeightFieldShape* heightFieldShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (heightFieldShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -370,8 +437,6 @@ void PhysicsCommon::destroyHeightFieldShape(HeightFieldShape* heightFieldShape)
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, heightFieldShape, sizeof(HeightFieldShape));
|
||||
|
||||
mHeightFieldShapes.remove(heightFieldShape);
|
||||
}
|
||||
|
||||
// Create and return a concave mesh shape
|
||||
|
@ -395,6 +460,17 @@ ConcaveMeshShape* PhysicsCommon::createConcaveMeshShape(TriangleMesh* triangleMe
|
|||
*/
|
||||
void PhysicsCommon::destroyConcaveMeshShape(ConcaveMeshShape* concaveMeshShape) {
|
||||
|
||||
deleteConcaveMeshShape(concaveMeshShape);
|
||||
|
||||
mConcaveMeshShapes.remove(concaveMeshShape);
|
||||
}
|
||||
|
||||
// Delete a concave mesh shape
|
||||
/**
|
||||
* @param concaveMeshShape A pointer to the concave mesh shape to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteConcaveMeshShape(ConcaveMeshShape* concaveMeshShape) {
|
||||
|
||||
// If the shape is still part of some colliders
|
||||
if (concaveMeshShape->mColliders.size() > 0) {
|
||||
|
||||
|
@ -407,8 +483,6 @@ void PhysicsCommon::destroyConcaveMeshShape(ConcaveMeshShape* concaveMeshShape)
|
|||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, concaveMeshShape, sizeof(ConcaveMeshShape));
|
||||
|
||||
mConcaveMeshShapes.remove(concaveMeshShape);
|
||||
}
|
||||
|
||||
// Create a polyhedron mesh
|
||||
|
@ -431,13 +505,22 @@ PolyhedronMesh* PhysicsCommon::createPolyhedronMesh(PolygonVertexArray* polygonV
|
|||
*/
|
||||
void PhysicsCommon::destroyPolyhedronMesh(PolyhedronMesh* polyhedronMesh) {
|
||||
|
||||
deletePolyhedronMesh(polyhedronMesh);
|
||||
|
||||
mPolyhedronMeshes.remove(polyhedronMesh);
|
||||
}
|
||||
|
||||
// Delete a polyhedron mesh
|
||||
/**
|
||||
* @param polyhedronMesh A pointer to the polyhedron mesh to destroy
|
||||
*/
|
||||
void PhysicsCommon::deletePolyhedronMesh(PolyhedronMesh* polyhedronMesh) {
|
||||
|
||||
// Call the destructor of the shape
|
||||
polyhedronMesh->~PolyhedronMesh();
|
||||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, polyhedronMesh, sizeof(PolyhedronMesh));
|
||||
|
||||
mPolyhedronMeshes.remove(polyhedronMesh);
|
||||
}
|
||||
|
||||
// Create a triangle mesh
|
||||
|
@ -459,13 +542,22 @@ TriangleMesh* PhysicsCommon::createTriangleMesh() {
|
|||
*/
|
||||
void PhysicsCommon::destroyTriangleMesh(TriangleMesh* triangleMesh) {
|
||||
|
||||
deleteTriangleMesh(triangleMesh);
|
||||
|
||||
mTriangleMeshes.remove(triangleMesh);
|
||||
}
|
||||
|
||||
// Delete a triangle mesh
|
||||
/**
|
||||
* @param A pointer to the triangle mesh to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteTriangleMesh(TriangleMesh* triangleMesh) {
|
||||
|
||||
// Call the destructor of the shape
|
||||
triangleMesh->~TriangleMesh();
|
||||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, triangleMesh, sizeof(TriangleMesh));
|
||||
|
||||
mTriangleMeshes.remove(triangleMesh);
|
||||
}
|
||||
|
||||
// Create and return a new logger
|
||||
|
@ -487,13 +579,22 @@ DefaultLogger* PhysicsCommon::createDefaultLogger() {
|
|||
*/
|
||||
void PhysicsCommon::destroyDefaultLogger(DefaultLogger* logger) {
|
||||
|
||||
deleteDefaultLogger(logger);
|
||||
|
||||
mDefaultLoggers.remove(logger);
|
||||
}
|
||||
|
||||
// Delete a logger
|
||||
/**
|
||||
* @param A pointer to the default logger to destroy
|
||||
*/
|
||||
void PhysicsCommon::deleteDefaultLogger(DefaultLogger* logger) {
|
||||
|
||||
// Call the destructor of the logger
|
||||
logger->~DefaultLogger();
|
||||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, logger, sizeof(DefaultLogger));
|
||||
|
||||
mDefaultLoggers.remove(logger);
|
||||
}
|
||||
|
||||
// If profiling is enabled
|
||||
|
@ -514,13 +615,18 @@ Profiler* PhysicsCommon::createProfiler() {
|
|||
// Destroy a profiler
|
||||
void PhysicsCommon::destroyProfiler(Profiler* profiler) {
|
||||
|
||||
deleteProfiler(profiler);
|
||||
|
||||
mProfilers.remove(profiler);
|
||||
}
|
||||
|
||||
// Delete a profiler
|
||||
void PhysicsCommon::deleteProfiler(Profiler* profiler) {
|
||||
|
||||
// Call the destructor of the profiler
|
||||
profiler->~Profiler();
|
||||
|
||||
// Release allocated memory
|
||||
mMemoryManager.release(MemoryManager::AllocationType::Pool, profiler, sizeof(Profiler));
|
||||
|
||||
mProfilers.remove(profiler);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -379,27 +379,3 @@ Vector3 reactphysics3d::projectPointOntoPlane(const Vector3& point, const Vector
|
|||
decimal reactphysics3d::computePointToPlaneDistance(const Vector3& point, const Vector3& planeNormal, const Vector3& planePoint) {
|
||||
return planeNormal.dot(point - planePoint);
|
||||
}
|
||||
|
||||
// Return true if the given number is prime
|
||||
bool reactphysics3d::isPrimeNumber(int number) {
|
||||
|
||||
// If it's a odd number
|
||||
if ((number & 1) != 0) {
|
||||
|
||||
int limit = static_cast<int>(std::sqrt(number));
|
||||
|
||||
for (int divisor = 3; divisor <= limit; divisor += 2) {
|
||||
|
||||
// If we have found a divisor
|
||||
if ((number % divisor) == 0) {
|
||||
|
||||
// It is not a prime number
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return number == 2;
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@ int main() {
|
|||
|
||||
// ---------- Containers tests ---------- //
|
||||
|
||||
testSuite.addTest(new TestSet("Set"));
|
||||
testSuite.addTest(new TestList("List"));
|
||||
testSuite.addTest(new TestMap("Map"));
|
||||
testSuite.addTest(new TestSet("Set"));
|
||||
testSuite.addTest(new TestDeque("Deque"));
|
||||
testSuite.addTest(new TestStack("Stack"));
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class TestList : public Test {
|
|||
rp3d_test(list4.size() == 0);
|
||||
|
||||
List<int> list5(list3);
|
||||
rp3d_test(list5.capacity() == list3.size());
|
||||
rp3d_test(list5.capacity() == list3.capacity());
|
||||
rp3d_test(list5.size() == list3.size());
|
||||
for (uint i=0; i<list3.size(); i++) {
|
||||
rp3d_test(list5[i] == list3[i]);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
// Libraries
|
||||
#include <reactphysics3d/containers/List.h>
|
||||
#include <reactphysics3d/memory/DefaultAllocator.h>
|
||||
#include <reactphysics3d/mathematics/mathematics.h>
|
||||
|
||||
/// Reactphysics3D namespace
|
||||
namespace reactphysics3d {
|
||||
|
@ -267,6 +268,33 @@ class TestMathematicsFunctions : public Test {
|
|||
rp3d_test(approxEqual(clipPolygonVertices[3].y, 4, 0.000001));
|
||||
rp3d_test(approxEqual(clipPolygonVertices[3].z, 0, 0.000001));
|
||||
|
||||
// Test isPowerOfTwo()
|
||||
rp3d_test(!isPowerOfTwo(0));
|
||||
rp3d_test(!isPowerOfTwo(3));
|
||||
rp3d_test(!isPowerOfTwo(144));
|
||||
rp3d_test(!isPowerOfTwo(13));
|
||||
rp3d_test(!isPowerOfTwo(18));
|
||||
rp3d_test(!isPowerOfTwo(1000));
|
||||
|
||||
rp3d_test(isPowerOfTwo(1));
|
||||
rp3d_test(isPowerOfTwo(2));
|
||||
rp3d_test(isPowerOfTwo(4));
|
||||
rp3d_test(isPowerOfTwo(8));
|
||||
rp3d_test(isPowerOfTwo(256));
|
||||
rp3d_test(isPowerOfTwo(1024));
|
||||
rp3d_test(isPowerOfTwo(2048));
|
||||
|
||||
// Test nextPowerOfTwo32Bits()
|
||||
rp3d_test(nextPowerOfTwo32Bits(0) == 1);
|
||||
rp3d_test(nextPowerOfTwo32Bits(1) == 1);
|
||||
rp3d_test(nextPowerOfTwo32Bits(2) == 2);
|
||||
rp3d_test(nextPowerOfTwo32Bits(3) == 4);
|
||||
rp3d_test(nextPowerOfTwo32Bits(5) == 8);
|
||||
rp3d_test(nextPowerOfTwo32Bits(6) == 8);
|
||||
rp3d_test(nextPowerOfTwo32Bits(7) == 8);
|
||||
rp3d_test(nextPowerOfTwo32Bits(1000) == 1024);
|
||||
rp3d_test(nextPowerOfTwo32Bits(129) == 256);
|
||||
rp3d_test(nextPowerOfTwo32Bits(260) == 512);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user