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