Working on containers
This commit is contained in:
parent
261ffef616
commit
ceb27760cb
|
@ -198,6 +198,7 @@ SET (REACTPHYSICS3D_SOURCES
|
||||||
"src/containers/Stack.h"
|
"src/containers/Stack.h"
|
||||||
"src/containers/LinkedList.h"
|
"src/containers/LinkedList.h"
|
||||||
"src/containers/List.h"
|
"src/containers/List.h"
|
||||||
|
"src/containers/Map.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create the library
|
# Create the library
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "memory/MemoryAllocator.h"
|
#include "memory/MemoryAllocator.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
@ -61,6 +62,102 @@ class List {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Class Iterator
|
||||||
|
/**
|
||||||
|
* This class represents an iterator for the List
|
||||||
|
*/
|
||||||
|
class Iterator {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
size_t mCurrentIndex;
|
||||||
|
T* mBuffer;
|
||||||
|
size_t mSize;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Iterator traits
|
||||||
|
using value_type = T;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
Iterator() = default;
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
Iterator(T* buffer, size_t index, size_t size)
|
||||||
|
:mCurrentIndex(index), mBuffer(buffer), mSize(size) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
Iterator(const Iterator& it)
|
||||||
|
:mCurrentIndex(it.mCurrentIndex), mBuffer(it.mBuffer), mSize(it.size) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deferencable
|
||||||
|
reference operator*() const {
|
||||||
|
assert(mCurrentIndex >= 0 && mCurrentIndex < mSize);
|
||||||
|
return mBuffer[mCurrentIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deferencable
|
||||||
|
pointer operator->() const {
|
||||||
|
assert(mCurrentIndex >= 0 && mCurrentIndex < mSize);
|
||||||
|
return &(mBuffer[mCurrentIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Post increment (it++)
|
||||||
|
Iterator& operator++() {
|
||||||
|
assert(mCurrentIndex < mSize - 1);
|
||||||
|
mCurrentIndex++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pre increment (++it)
|
||||||
|
Iterator operator++(int number) {
|
||||||
|
assert(mCurrentIndex < mSize - 1);
|
||||||
|
Iterator tmp = *this;
|
||||||
|
mCurrentIndex++;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Post decrement (it--)
|
||||||
|
Iterator& operator--() {
|
||||||
|
assert(mCurrentIndex > 0);
|
||||||
|
mCurrentIndex--;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pre decrement (--it)
|
||||||
|
Iterator operator--(int number) {
|
||||||
|
assert(mCurrentIndex > 0);
|
||||||
|
Iterator tmp = *this;
|
||||||
|
mCurrentIndex--;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equality operator (it == end())
|
||||||
|
bool operator==(const Iterator& iterator) const {
|
||||||
|
assert(mCurrentIndex >= 0 && mCurrentIndex <= mSize);
|
||||||
|
|
||||||
|
// If both iterators points to the end of the list
|
||||||
|
if (mCurrentIndex == mSize && iterator.mCurrentIndex == iterator.mSize) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &(mBuffer[mCurrentIndex]) == &(iterator.mBuffer[mCurrentIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inequality operator (it != end())
|
||||||
|
bool operator!=(const Iterator& iterator) const {
|
||||||
|
return !(*this == iterator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -151,7 +248,7 @@ class List {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append another list to the current one
|
/// Append another list at the end of the current one
|
||||||
void addRange(const List<T>& list) {
|
void addRange(const List<T>& list) {
|
||||||
|
|
||||||
// If we need to allocate more memory
|
// If we need to allocate more memory
|
||||||
|
@ -180,7 +277,7 @@ class List {
|
||||||
mSize = 0;
|
mSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the number of elments in the list
|
/// Return the number of elements in the list
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return mSize;
|
return mSize;
|
||||||
}
|
}
|
||||||
|
@ -202,14 +299,38 @@ class List {
|
||||||
return (static_cast<T*>(mBuffer)[index]);
|
return (static_cast<T*>(mBuffer)[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overloaded equality operator
|
||||||
|
bool operator==(const List<T>& list) const {
|
||||||
|
|
||||||
|
if (mSize != list.mSize) return false;
|
||||||
|
|
||||||
|
T* items = static_cast<T*>(mBuffer);
|
||||||
|
for (int i=0; i < mSize; i++) {
|
||||||
|
if (items[i] != list[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded not equal operator
|
||||||
|
bool operator!=(const List<T>& list) const {
|
||||||
|
|
||||||
|
return !((*this) == list);
|
||||||
|
}
|
||||||
|
|
||||||
/// Overloaded assignment operator
|
/// Overloaded assignment operator
|
||||||
List<T>& operator=(const List<T>& list) {
|
List<T>& operator=(const List<T>& list) {
|
||||||
|
|
||||||
|
if (this != &list) {
|
||||||
|
|
||||||
// Clear all the elements
|
// Clear all the elements
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
// Add all the elements of the list to the current one
|
// Add all the elements of the list to the current one
|
||||||
addRange(list);
|
addRange(list);
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
532
src/containers/Map.h
Normal file
532
src/containers/Map.h
Normal file
|
@ -0,0 +1,532 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||||
|
*********************************************************************************
|
||||||
|
* *
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. *
|
||||||
|
* In no event will the authors be held liable for any damages arising from the *
|
||||||
|
* use of this software. *
|
||||||
|
* *
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, *
|
||||||
|
* including commercial applications, and to alter it and redistribute it *
|
||||||
|
* freely, subject to the following restrictions: *
|
||||||
|
* *
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||||
|
* that you wrote the original software. If you use this software in a *
|
||||||
|
* product, an acknowledgment in the product documentation would be *
|
||||||
|
* appreciated but is not required. *
|
||||||
|
* *
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||||
|
* misrepresented as being the original software. *
|
||||||
|
* *
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef REACTPHYSICS3D_MAP_H
|
||||||
|
#define REACTPHYSICS3D_MAP_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "memory/MemoryAllocator.h"
|
||||||
|
#include "mathematics/mathematics_functions.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Class Map
|
||||||
|
/**
|
||||||
|
* This class represents a simple generic associative map
|
||||||
|
*/
|
||||||
|
template<typename K, typename V>
|
||||||
|
class Map {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// An entry of the map
|
||||||
|
struct Entry {
|
||||||
|
|
||||||
|
size_t hashCode; // Hash code of the entry
|
||||||
|
int next; // Index of the next entry
|
||||||
|
std::pair<K, V>* keyValue; // Pointer to the pair with key and value
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
Entry() {
|
||||||
|
next = -1;
|
||||||
|
keyValue = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~Entry() {
|
||||||
|
|
||||||
|
assert(keyValue == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------- Constants -------------------- //
|
||||||
|
|
||||||
|
/// Number of prime numbers in array
|
||||||
|
static constexpr int NB_PRIMES = 70;
|
||||||
|
|
||||||
|
/// Array of prime numbers for the size of the map
|
||||||
|
static const int PRIMES[NB_PRIMES];
|
||||||
|
|
||||||
|
/// Largest prime number
|
||||||
|
static int LARGEST_PRIME;
|
||||||
|
|
||||||
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
|
/// Current number of used entries in the map
|
||||||
|
int mNbUsedEntries;
|
||||||
|
|
||||||
|
/// Number of free entries among the used ones
|
||||||
|
int mNbFreeEntries;
|
||||||
|
|
||||||
|
/// Current capacity of the map
|
||||||
|
int mCapacity;
|
||||||
|
|
||||||
|
/// Array with all the buckets
|
||||||
|
int* mBuckets;
|
||||||
|
|
||||||
|
/// Array with all the entries
|
||||||
|
Entry* mEntries;
|
||||||
|
|
||||||
|
/// Memory allocator
|
||||||
|
MemoryAllocator& mAllocator;
|
||||||
|
|
||||||
|
/// Index to the fist free entry
|
||||||
|
int mFreeIndex;
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
/// Initialize the map
|
||||||
|
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 map
|
||||||
|
void expand(int newCapacity) {
|
||||||
|
|
||||||
|
assert(newCapacity > mCapacity);
|
||||||
|
assert(isPrimeNumber(newCapacity));
|
||||||
|
|
||||||
|
// Allocate memory for the buckets
|
||||||
|
int* newBuckets = static_cast<int*>(mAllocator.allocate(newCapacity * sizeof(int)));
|
||||||
|
|
||||||
|
// Allocate memory for the entries
|
||||||
|
Entry* newEntries = static_cast<Entry*>(mAllocator.allocate(newCapacity * sizeof(Entry)));
|
||||||
|
|
||||||
|
// Initialize the new buckets
|
||||||
|
for (int i=0; i<newCapacity; i++) {
|
||||||
|
newBuckets[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the old entries to the new allocated memory location
|
||||||
|
std::memcpy(newEntries, mEntries, mNbUsedEntries * sizeof(Entry));
|
||||||
|
|
||||||
|
// Construct the new entries
|
||||||
|
for (int i=mNbUsedEntries; i<newCapacity; i++) {
|
||||||
|
|
||||||
|
// Construct the entry
|
||||||
|
new (static_cast<void*>(&newEntries[i])) Entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each used entry
|
||||||
|
for (int i=0; i<mNbUsedEntries; i++) {
|
||||||
|
|
||||||
|
// If the entry is not free
|
||||||
|
if (newEntries[i].hashCode != -1) {
|
||||||
|
|
||||||
|
// Get the corresponding bucket
|
||||||
|
int bucket = newEntries[i].hashCode % newCapacity;
|
||||||
|
|
||||||
|
newEntries[i].next = newBuckets[bucket];
|
||||||
|
newBuckets[bucket] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release previously allocated memory
|
||||||
|
mAllocator.release(mBuckets, mCapacity * sizeof(int));
|
||||||
|
mAllocator.release(mEntries, mCapacity * sizeof(Entry));
|
||||||
|
|
||||||
|
mCapacity = newCapacity;
|
||||||
|
mBuckets = newBuckets;
|
||||||
|
mEntries = newEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the index of the entry with a given key or -1 if there is no entry with this key
|
||||||
|
int findEntry(const K& key) const {
|
||||||
|
|
||||||
|
if (mCapacity > 0) {
|
||||||
|
|
||||||
|
size_t hashCode = std::hash<K>()(key);
|
||||||
|
int bucket = hashCode % mCapacity;
|
||||||
|
|
||||||
|
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||||
|
if (mEntries[i].hashCode == hashCode && mEntries[i].keyValue->first == key) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the prime number that is larger or equal to the number in parameter
|
||||||
|
/// for the size of the map
|
||||||
|
static int getPrimeSize(int number) {
|
||||||
|
|
||||||
|
// Check if the next larger prime number is in the precomputed array of primes
|
||||||
|
for (int i = 0; i < NB_PRIMES; i++) {
|
||||||
|
if (PRIMES[i] >= number) return PRIMES[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually compute the next larger prime number
|
||||||
|
for (int i = (number | 1); i < std::numeric_limits<int>::max(); i+=2) {
|
||||||
|
|
||||||
|
if (isPrimeNumber(i)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear and reset the map
|
||||||
|
void reset() {
|
||||||
|
|
||||||
|
// If elements have been allocated
|
||||||
|
if (mCapacity > 0) {
|
||||||
|
|
||||||
|
// Clear the list
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// Destroy the entries
|
||||||
|
for (int i=0; i < mCapacity; i++) {
|
||||||
|
mEntries[i].~Entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAllocator.release(mBuckets, mCapacity * sizeof(int));
|
||||||
|
mAllocator.release(mEntries, mCapacity * sizeof(Entry));
|
||||||
|
|
||||||
|
mNbUsedEntries = 0;
|
||||||
|
mNbFreeEntries = 0;
|
||||||
|
mCapacity = 0;
|
||||||
|
mBuckets = nullptr;
|
||||||
|
mEntries = nullptr;
|
||||||
|
mFreeIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
Map(MemoryAllocator& allocator, size_t capacity = 0)
|
||||||
|
: mNbUsedEntries(0), mNbFreeEntries(0), mCapacity(0), mBuckets(nullptr),
|
||||||
|
mEntries(nullptr), mAllocator(allocator), mFreeIndex(-1) {
|
||||||
|
|
||||||
|
// If the largest prime has not been computed yet
|
||||||
|
if (LARGEST_PRIME == -1) {
|
||||||
|
|
||||||
|
// Compute the largest prime number (largest map capacity)
|
||||||
|
LARGEST_PRIME = getPrimeSize(PRIMES[NB_PRIMES - 1] + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capacity > 0) {
|
||||||
|
|
||||||
|
initialize(capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
Map(const Map<K, V>& map)
|
||||||
|
:mNbUsedEntries(map.mNbUsedEntries), mNbFreeEntries(map.mNbFreeEntries), mCapacity(map.mCapacity),
|
||||||
|
mAllocator(map.mAllocator), mFreeIndex(map.mFreeIndex) {
|
||||||
|
|
||||||
|
// Allocate memory for the buckets
|
||||||
|
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||||
|
|
||||||
|
// Allocate memory for the entries
|
||||||
|
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||||
|
|
||||||
|
// Copy the buckets
|
||||||
|
std::memcpy(mBuckets, map.mBuckets, mCapacity * sizeof(int));
|
||||||
|
|
||||||
|
// Copy the entries
|
||||||
|
std::memcpy(mEntries, map.mEntries, mCapacity * sizeof(Entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~Map() {
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory for a given number of elements
|
||||||
|
void reserve(size_t capacity) {
|
||||||
|
|
||||||
|
if (capacity <= mCapacity) return;
|
||||||
|
|
||||||
|
if (capacity > LARGEST_PRIME && LARGEST_PRIME > mCapacity) {
|
||||||
|
capacity = LARGEST_PRIME;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
capacity = getPrimeSize(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
expand(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if the map contains an item with the given key
|
||||||
|
bool containsKey(const K& key) const {
|
||||||
|
return findEntry(key) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an element into the map
|
||||||
|
void add(const std::pair<K,V>& keyValue) {
|
||||||
|
|
||||||
|
if (mCapacity == 0) {
|
||||||
|
initialize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the hash code of the key
|
||||||
|
size_t hashCode = std::hash<K>()(keyValue.first);
|
||||||
|
|
||||||
|
// Compute the corresponding bucket index
|
||||||
|
int bucket = hashCode % mCapacity;
|
||||||
|
|
||||||
|
// Check if the item is already in the map
|
||||||
|
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
|
||||||
|
|
||||||
|
// If there is already an item with the same key in the map
|
||||||
|
if (mEntries[i].hashCode == hashCode && mEntries[i].keyValue->first == keyValue.first) {
|
||||||
|
|
||||||
|
throw std::runtime_error("The key and value pair already exists in the map");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t entryIndex;
|
||||||
|
|
||||||
|
// If there are free entries to use
|
||||||
|
if (mNbFreeEntries > 0) {
|
||||||
|
assert(mFreeIndex >= 0);
|
||||||
|
entryIndex = mFreeIndex;
|
||||||
|
mFreeIndex = mEntries[entryIndex].next;
|
||||||
|
mNbFreeEntries--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// If we need to allocator more entries
|
||||||
|
if (mNbUsedEntries == mCapacity) {
|
||||||
|
|
||||||
|
// Allocate more memory
|
||||||
|
reserve(mCapacity * 2);
|
||||||
|
|
||||||
|
// Recompute the bucket index
|
||||||
|
bucket = hashCode % mCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
entryIndex = mNbUsedEntries;
|
||||||
|
mNbUsedEntries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mEntries[entryIndex].keyValue == nullptr);
|
||||||
|
mEntries[entryIndex].hashCode = hashCode;
|
||||||
|
mEntries[entryIndex].next = mBuckets[bucket];
|
||||||
|
mEntries[entryIndex].keyValue = static_cast<std::pair<K,V>*>(mAllocator.allocate(sizeof(std::pair<K,V>)));
|
||||||
|
assert(mEntries[entryIndex].keyValue != nullptr);
|
||||||
|
new (mEntries[entryIndex].keyValue) std::pair<K,V>(keyValue);
|
||||||
|
mBuckets[bucket] = entryIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the element from the map with a given key
|
||||||
|
bool remove(const K& key) {
|
||||||
|
|
||||||
|
if (mCapacity > 0) {
|
||||||
|
|
||||||
|
size_t hashcode = std::hash<K>()(key);
|
||||||
|
int bucket = hashcode % mCapacity;
|
||||||
|
int last = -1;
|
||||||
|
for (int i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].next) {
|
||||||
|
|
||||||
|
if (mEntries[i].hashCode == hashcode && mEntries[i].keyValue->first == key) {
|
||||||
|
|
||||||
|
if (last < 0 ) {
|
||||||
|
mBuckets[bucket] = mEntries[i].next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mEntries[last].next = mEntries[i].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release memory for the key/value pair if any
|
||||||
|
if (mEntries[i].keyValue != nullptr) {
|
||||||
|
mEntries[i].keyValue->~pair<K,V>();
|
||||||
|
mAllocator.release(mEntries[i].keyValue, sizeof(std::pair<K,V>));
|
||||||
|
mEntries[i].keyValue = nullptr;
|
||||||
|
}
|
||||||
|
mEntries[i].hashCode = -1;
|
||||||
|
mEntries[i].next = mFreeIndex;
|
||||||
|
mFreeIndex = i;
|
||||||
|
mNbFreeEntries++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the list
|
||||||
|
void clear() {
|
||||||
|
|
||||||
|
if (mNbUsedEntries > 0) {
|
||||||
|
|
||||||
|
for (int i=0; i < mCapacity; i++) {
|
||||||
|
mBuckets[i] = -1;
|
||||||
|
mEntries[i].next = -1;
|
||||||
|
if (mEntries[i].keyValue != nullptr) {
|
||||||
|
mEntries[i].keyValue->~pair<K,V>();
|
||||||
|
mAllocator.release(mEntries[i].keyValue, sizeof(std::pair<K,V>));
|
||||||
|
mEntries[i].keyValue = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mFreeIndex = -1;
|
||||||
|
mNbUsedEntries = 0;
|
||||||
|
mNbFreeEntries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the number of elements in the map
|
||||||
|
int size() const {
|
||||||
|
return mNbUsedEntries - mNbFreeEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the capacity of the map
|
||||||
|
int capacity() const {
|
||||||
|
return mCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded index operator
|
||||||
|
V& operator[](const K& key) {
|
||||||
|
|
||||||
|
int entry = -1;
|
||||||
|
|
||||||
|
if (mCapacity > 0) {
|
||||||
|
entry = findEntry(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == -1) {
|
||||||
|
throw std::runtime_error("No item with given key has been found in the map");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mEntries[entry].keyValue != nullptr);
|
||||||
|
|
||||||
|
return mEntries[entry].keyValue->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded index operator
|
||||||
|
const V& operator[](const K& key) const {
|
||||||
|
|
||||||
|
int entry = -1;
|
||||||
|
|
||||||
|
if (mCapacity > 0) {
|
||||||
|
entry = findEntry(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == -1) {
|
||||||
|
throw std::runtime_error("No item with given key has been found in the map");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mEntries[entry];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded equality operator
|
||||||
|
bool operator==(const Map<K,V>& map) const {
|
||||||
|
|
||||||
|
// TODO : Implement this
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded not equal operator
|
||||||
|
bool operator!=(const Map<K,V>& map) const {
|
||||||
|
|
||||||
|
return !((*this) == map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overloaded assignment operator
|
||||||
|
Map<K,V>& operator=(const Map<K, V>& map) {
|
||||||
|
|
||||||
|
// Check for self assignment
|
||||||
|
if (this != &map) {
|
||||||
|
|
||||||
|
// Reset the map
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (map.mCapacity > 0) {
|
||||||
|
|
||||||
|
// Compute the next larger prime size
|
||||||
|
mCapacity = getPrimeSize(map.mCapacity);
|
||||||
|
|
||||||
|
// Allocate memory for the buckets
|
||||||
|
mBuckets = static_cast<int*>(mAllocator.allocate(mCapacity * sizeof(int)));
|
||||||
|
|
||||||
|
// Allocate memory for the entries
|
||||||
|
mEntries = static_cast<Entry*>(mAllocator.allocate(mCapacity * sizeof(Entry)));
|
||||||
|
|
||||||
|
// Copy the buckets
|
||||||
|
std::memcpy(mBuckets, map.mBuckets, mCapacity * sizeof(int));
|
||||||
|
|
||||||
|
// Copy the entries
|
||||||
|
std::memcpy(mEntries, map.mEntries, mCapacity * sizeof(Entry));
|
||||||
|
|
||||||
|
mNbUsedEntries = map.mNbUsedEntries;
|
||||||
|
mNbFreeEntries = map.mNbFreeEntries;
|
||||||
|
mFreeIndex = map.mFreeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename K, typename V>
|
||||||
|
const int Map<K,V>::PRIMES[NB_PRIMES] = {3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
||||||
|
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
||||||
|
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
||||||
|
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
||||||
|
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559};
|
||||||
|
|
||||||
|
template<typename K, typename V>
|
||||||
|
int Map<K,V>::LARGEST_PRIME = -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -383,4 +383,28 @@ Vector3 reactphysics3d::projectPointOntoPlane(const Vector3& point, const Vector
|
||||||
return point - unitPlaneNormal.dot(point - planePoint) * unitPlaneNormal;
|
return point - unitPlaneNormal.dot(point - planePoint) * unitPlaneNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,9 @@ List<Vector3> clipPolygonWithPlanes(const List<Vector3>& polygonVertices, const
|
||||||
/// Project a point onto a plane that is given by a point and its unit length normal
|
/// Project a point onto a plane that is given by a point and its unit length normal
|
||||||
Vector3 projectPointOntoPlane(const Vector3& point, const Vector3& planeNormal, const Vector3& planePoint);
|
Vector3 projectPointOntoPlane(const Vector3& point, const Vector3& planeNormal, const Vector3& planePoint);
|
||||||
|
|
||||||
|
/// Return true if the given number is prime
|
||||||
|
bool isPrimeNumber(int number);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "tests/collision/TestDynamicAABBTree.h"
|
#include "tests/collision/TestDynamicAABBTree.h"
|
||||||
#include "tests/collision/TestHalfEdgeStructure.h"
|
#include "tests/collision/TestHalfEdgeStructure.h"
|
||||||
#include "tests/collision/TestTriangleVertexArray.h"
|
#include "tests/collision/TestTriangleVertexArray.h"
|
||||||
|
#include "tests/containers/TestList.h"
|
||||||
|
#include "tests/containers/TestMap.h"
|
||||||
|
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
|
@ -46,6 +48,11 @@ int main() {
|
||||||
|
|
||||||
TestSuite testSuite("ReactPhysics3D Tests");
|
TestSuite testSuite("ReactPhysics3D Tests");
|
||||||
|
|
||||||
|
// ---------- Containers tests ---------- //
|
||||||
|
|
||||||
|
testSuite.addTest(new TestList("List"));
|
||||||
|
testSuite.addTest(new TestMap("Map"));
|
||||||
|
|
||||||
// ---------- Mathematics tests ---------- //
|
// ---------- Mathematics tests ---------- //
|
||||||
|
|
||||||
testSuite.addTest(new TestVector2("Vector2"));
|
testSuite.addTest(new TestVector2("Vector2"));
|
||||||
|
|
331
test/tests/containers/TestList.h
Normal file
331
test/tests/containers/TestList.h
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||||
|
*********************************************************************************
|
||||||
|
* *
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. *
|
||||||
|
* In no event will the authors be held liable for any damages arising from the *
|
||||||
|
* use of this software. *
|
||||||
|
* *
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, *
|
||||||
|
* including commercial applications, and to alter it and redistribute it *
|
||||||
|
* freely, subject to the following restrictions: *
|
||||||
|
* *
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||||
|
* that you wrote the original software. If you use this software in a *
|
||||||
|
* product, an acknowledgment in the product documentation would be *
|
||||||
|
* appreciated but is not required. *
|
||||||
|
* *
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||||
|
* misrepresented as being the original software. *
|
||||||
|
* *
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TEST_LIST_H
|
||||||
|
#define TEST_LIST_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "Test.h"
|
||||||
|
#include "containers/List.h"
|
||||||
|
#include "memory/DefaultAllocator.h"
|
||||||
|
|
||||||
|
/// Reactphysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Class TestList
|
||||||
|
/**
|
||||||
|
* Unit test for the List class
|
||||||
|
*/
|
||||||
|
class TestList : public Test {
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
// ---------- Atributes ---------- //
|
||||||
|
|
||||||
|
DefaultAllocator mAllocator;
|
||||||
|
|
||||||
|
public :
|
||||||
|
|
||||||
|
// ---------- Methods ---------- //
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
TestList(const std::string& name) : Test(name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the tests
|
||||||
|
void run() {
|
||||||
|
|
||||||
|
testConstructors();
|
||||||
|
testAddRemoveClear();
|
||||||
|
testAssignment();
|
||||||
|
testIndexing();
|
||||||
|
testEquality();
|
||||||
|
testReserve();
|
||||||
|
testIteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConstructors() {
|
||||||
|
|
||||||
|
// ----- Constructors ----- //
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
test(list1.capacity() == 0);
|
||||||
|
test(list1.size() == 0);
|
||||||
|
|
||||||
|
List<int> list2(mAllocator, 100);
|
||||||
|
test(list2.capacity() == 100);
|
||||||
|
test(list2.size() == 0);
|
||||||
|
|
||||||
|
List<int> list3(mAllocator);
|
||||||
|
list3.add(1);
|
||||||
|
list3.add(2);
|
||||||
|
list3.add(3);
|
||||||
|
test(list3.capacity() == 4);
|
||||||
|
test(list3.size() == 3);
|
||||||
|
|
||||||
|
// ----- Copy Constructors ----- //
|
||||||
|
|
||||||
|
List<int> list4(list1);
|
||||||
|
test(list4.capacity() == 0);
|
||||||
|
test(list4.size() == 0);
|
||||||
|
|
||||||
|
List<int> list5(list3);
|
||||||
|
test(list5.capacity() == list3.size());
|
||||||
|
test(list5.size() == list3.size());
|
||||||
|
for (uint i=0; i<list3.size(); i++) {
|
||||||
|
test(list5[i] == list3[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Test capacity grow ----- //
|
||||||
|
List<std::string> list6(mAllocator, 20);
|
||||||
|
test(list6.capacity() == 20);
|
||||||
|
for (uint i=0; i<20; i++) {
|
||||||
|
list6.add("test");
|
||||||
|
}
|
||||||
|
test(list6.capacity() == 20);
|
||||||
|
list6.add("test");
|
||||||
|
test(list6.capacity() == 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAddRemoveClear() {
|
||||||
|
|
||||||
|
// ----- Test add() ----- //
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
list1.add(4);
|
||||||
|
test(list1.size() == 1);
|
||||||
|
test(list1[0] == 4);
|
||||||
|
list1.add(9);
|
||||||
|
test(list1.size() == 2);
|
||||||
|
test(list1[0] == 4);
|
||||||
|
test(list1[1] == 9);
|
||||||
|
|
||||||
|
const int arraySize = 15;
|
||||||
|
int arrayTest[arraySize] = {3, 145, -182, 34, 12, 95, -1834, 4143, -111, -111, 4343, 234, 22983, -3432, 753};
|
||||||
|
List<int> list2(mAllocator);
|
||||||
|
for (uint i=0; i<arraySize; i++) {
|
||||||
|
list2.add(arrayTest[i]);
|
||||||
|
}
|
||||||
|
test(list2.size() == arraySize);
|
||||||
|
for (uint i=0; i<arraySize; i++) {
|
||||||
|
test(list2[i] == arrayTest[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Test remove() ----- //
|
||||||
|
|
||||||
|
List<int> list3(mAllocator);
|
||||||
|
list3.add(1);
|
||||||
|
list3.add(2);
|
||||||
|
list3.add(3);
|
||||||
|
list3.add(4);
|
||||||
|
|
||||||
|
list3.remove(3);
|
||||||
|
test(list3.size() == 3);
|
||||||
|
test(list3.capacity() == 4);
|
||||||
|
test(list3[0] = 1);
|
||||||
|
test(list3[1] = 2);
|
||||||
|
test(list3[2] = 3);
|
||||||
|
|
||||||
|
list3.remove(1);
|
||||||
|
test(list3.size() == 2);
|
||||||
|
test(list3.capacity() == 4);
|
||||||
|
test(list3[0] = 1);
|
||||||
|
test(list3[1] = 3);
|
||||||
|
|
||||||
|
list3.remove(0);
|
||||||
|
test(list3.size() == 1);
|
||||||
|
test(list3.capacity() == 4);
|
||||||
|
test(list3[0] = 3);
|
||||||
|
|
||||||
|
list3.remove(0);
|
||||||
|
test(list3.size() == 0);
|
||||||
|
test(list3.capacity() == 4);
|
||||||
|
|
||||||
|
// ----- Test addRange() ----- //
|
||||||
|
|
||||||
|
List<int> list4(mAllocator);
|
||||||
|
list4.add(1);
|
||||||
|
list4.add(2);
|
||||||
|
list4.add(3);
|
||||||
|
|
||||||
|
List<int> list5(mAllocator);
|
||||||
|
list5.add(4);
|
||||||
|
list5.add(5);
|
||||||
|
|
||||||
|
List<int> list6(mAllocator);
|
||||||
|
list6.addRange(list5);
|
||||||
|
test(list6.size() == list5.size());
|
||||||
|
test(list6[0] == 4);
|
||||||
|
test(list6[1] == 5);
|
||||||
|
|
||||||
|
list4.addRange(list5);
|
||||||
|
test(list4.size() == 3 + list5.size());
|
||||||
|
test(list4[0] == 1);
|
||||||
|
test(list4[1] == 2);
|
||||||
|
test(list4[2] == 3);
|
||||||
|
test(list4[3] == 4);
|
||||||
|
test(list4[4] == 5);
|
||||||
|
|
||||||
|
// ----- Test clear() ----- //
|
||||||
|
|
||||||
|
List<std::string> list7(mAllocator);
|
||||||
|
list7.add("test1");
|
||||||
|
list7.add("test2");
|
||||||
|
list7.add("test3");
|
||||||
|
list7.clear();
|
||||||
|
test(list7.size() == 0);
|
||||||
|
list7.add("new");
|
||||||
|
test(list7.size() == 1);
|
||||||
|
test(list7[0] == "new");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAssignment() {
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
list1.add(1);
|
||||||
|
list1.add(2);
|
||||||
|
list1.add(3);
|
||||||
|
|
||||||
|
List<int> list2(mAllocator);
|
||||||
|
list2.add(5);
|
||||||
|
list2.add(6);
|
||||||
|
|
||||||
|
List<int> list3(mAllocator);
|
||||||
|
List<int> list4(mAllocator);
|
||||||
|
list4.add(1);
|
||||||
|
list4.add(2);
|
||||||
|
|
||||||
|
List<int> list5(mAllocator);
|
||||||
|
list5.add(1);
|
||||||
|
list5.add(2);
|
||||||
|
list5.add(3);
|
||||||
|
|
||||||
|
list3 = list2;
|
||||||
|
test(list2.size() == list3.size());
|
||||||
|
test(list2[0] == list3[0]);
|
||||||
|
test(list2[1] == list3[1]);
|
||||||
|
|
||||||
|
list4 = list1;
|
||||||
|
test(list4.size() == list1.size())
|
||||||
|
test(list4[0] = list1[0]);
|
||||||
|
test(list4[1] = list1[1]);
|
||||||
|
test(list4[2] = list1[2]);
|
||||||
|
|
||||||
|
list5 = list2;
|
||||||
|
test(list5.size() == list2.size());
|
||||||
|
test(list5[0] = list2[0]);
|
||||||
|
test(list5[1] = list2[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testIndexing() {
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
list1.add(1);
|
||||||
|
list1.add(2);
|
||||||
|
list1.add(3);
|
||||||
|
|
||||||
|
test(list1[0] == 1);
|
||||||
|
test(list1[1] == 2);
|
||||||
|
test(list1[2] == 3);
|
||||||
|
|
||||||
|
list1[0] = 6;
|
||||||
|
list1[1] = 7;
|
||||||
|
list1[2] = 8;
|
||||||
|
|
||||||
|
test(list1[0] == 6);
|
||||||
|
test(list1[1] == 7);
|
||||||
|
test(list1[2] == 8);
|
||||||
|
|
||||||
|
const int a = list1[0];
|
||||||
|
const int b = list1[1];
|
||||||
|
test(a == 6);
|
||||||
|
test(b == 7);
|
||||||
|
|
||||||
|
list1[0]++;
|
||||||
|
list1[1]++;
|
||||||
|
test(list1[0] == 7);
|
||||||
|
test(list1[1] == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testEquality() {
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
list1.add(1);
|
||||||
|
list1.add(2);
|
||||||
|
list1.add(3);
|
||||||
|
|
||||||
|
List<int> list2(mAllocator);
|
||||||
|
list2.add(1);
|
||||||
|
list2.add(2);
|
||||||
|
|
||||||
|
List<int> list3(mAllocator);
|
||||||
|
list3.add(1);
|
||||||
|
list3.add(2);
|
||||||
|
list3.add(3);
|
||||||
|
|
||||||
|
List<int> list4(mAllocator);
|
||||||
|
list4.add(1);
|
||||||
|
list4.add(5);
|
||||||
|
list4.add(3);
|
||||||
|
|
||||||
|
test(list1 == list1);
|
||||||
|
test(list1 != list2);
|
||||||
|
test(list1 == list3);
|
||||||
|
test(list1 != list4);
|
||||||
|
test(list2 != list4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testReserve() {
|
||||||
|
|
||||||
|
List<int> list1(mAllocator);
|
||||||
|
list1.reserve(10);
|
||||||
|
test(list1.size() == 0);
|
||||||
|
test(list1.capacity() == 10);
|
||||||
|
list1.add(1);
|
||||||
|
list1.add(2);
|
||||||
|
test(list1.capacity() == 10);
|
||||||
|
test(list1.size() == 2);
|
||||||
|
test(list1[0] == 1);
|
||||||
|
test(list1[1] == 2);
|
||||||
|
|
||||||
|
list1.reserve(1);
|
||||||
|
test(list1.capacity() == 10);
|
||||||
|
|
||||||
|
list1.reserve(100);
|
||||||
|
test(list1.capacity() == 100);
|
||||||
|
test(list1[0] == 1);
|
||||||
|
test(list1[1] == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testIteration() {
|
||||||
|
// TODO : Implement this
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
319
test/tests/containers/TestMap.h
Normal file
319
test/tests/containers/TestMap.h
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||||
|
*********************************************************************************
|
||||||
|
* *
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. *
|
||||||
|
* In no event will the authors be held liable for any damages arising from the *
|
||||||
|
* use of this software. *
|
||||||
|
* *
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, *
|
||||||
|
* including commercial applications, and to alter it and redistribute it *
|
||||||
|
* freely, subject to the following restrictions: *
|
||||||
|
* *
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||||
|
* that you wrote the original software. If you use this software in a *
|
||||||
|
* product, an acknowledgment in the product documentation would be *
|
||||||
|
* appreciated but is not required. *
|
||||||
|
* *
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||||
|
* misrepresented as being the original software. *
|
||||||
|
* *
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TEST_MAP_H
|
||||||
|
#define TEST_MAP_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "Test.h"
|
||||||
|
#include "containers/Map.h"
|
||||||
|
#include "memory/DefaultAllocator.h"
|
||||||
|
|
||||||
|
/// Reactphysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Class TestMap
|
||||||
|
/**
|
||||||
|
* Unit test for the Map class
|
||||||
|
*/
|
||||||
|
class TestMap : public Test {
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
// ---------- Atributes ---------- //
|
||||||
|
|
||||||
|
DefaultAllocator mAllocator;
|
||||||
|
|
||||||
|
public :
|
||||||
|
|
||||||
|
// ---------- Methods ---------- //
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
TestMap(const std::string& name) : Test(name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the tests
|
||||||
|
void run() {
|
||||||
|
|
||||||
|
testConstructors();
|
||||||
|
testReserve();
|
||||||
|
testAddRemoveClear();
|
||||||
|
testContainsKey();
|
||||||
|
testIndexing();
|
||||||
|
testEquality();
|
||||||
|
testAssignment();
|
||||||
|
testIteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConstructors() {
|
||||||
|
|
||||||
|
// ----- Constructors ----- //
|
||||||
|
|
||||||
|
Map<int, std::string> map1(mAllocator);
|
||||||
|
test(map1.capacity() == 0);
|
||||||
|
test(map1.size() == 0);
|
||||||
|
|
||||||
|
Map<int, std::string> map2(mAllocator, 100);
|
||||||
|
test(map2.capacity() >= 100);
|
||||||
|
test(map2.size() == 0);
|
||||||
|
|
||||||
|
// ----- Copy Constructors ----- //
|
||||||
|
/*
|
||||||
|
Map<int, std::string> map3(map1);
|
||||||
|
test(map3.capacity() == map1.capacity());
|
||||||
|
test(map3.size() == map1.size());
|
||||||
|
|
||||||
|
Map<int, int> map4(mAllocator);
|
||||||
|
map4.add(std::make_pair(1, 10));
|
||||||
|
map4.add(std::make_pair(2, 20));
|
||||||
|
map4.add(std::make_pair(3, 30));
|
||||||
|
test(map4.capacity() >= 3);
|
||||||
|
test(map4.size() == 3);
|
||||||
|
|
||||||
|
Map<int, int> map5(map4);
|
||||||
|
test(map5.capacity() == map4.capacity());
|
||||||
|
test(map5.size() == map4.size());
|
||||||
|
test(map5[1] == 10);
|
||||||
|
test(map5[2] == 20);
|
||||||
|
test(map5[3] == 30);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void testReserve() {
|
||||||
|
|
||||||
|
Map<int, std::string> map1(mAllocator);
|
||||||
|
map1.reserve(15);
|
||||||
|
test(map1.capacity() >= 15);
|
||||||
|
map1.add(std::make_pair(1, "test1"));
|
||||||
|
map1.add(std::make_pair(2, "test2"));
|
||||||
|
test(map1.capacity() >= 15);
|
||||||
|
|
||||||
|
map1.reserve(10);
|
||||||
|
test(map1.capacity() >= 15);
|
||||||
|
|
||||||
|
map1.reserve(100);
|
||||||
|
test(map1.capacity() >= 100);
|
||||||
|
test(map1[1] == "test1");
|
||||||
|
test(map1[2] == "test2");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAddRemoveClear() {
|
||||||
|
|
||||||
|
// ----- Test add() ----- //
|
||||||
|
|
||||||
|
Map<int, int> map1(mAllocator);
|
||||||
|
map1.add(std::make_pair(1, 10));
|
||||||
|
map1.add(std::make_pair(8, 80));
|
||||||
|
map1.add(std::make_pair(13, 130));
|
||||||
|
test(map1[1] == 10);
|
||||||
|
test(map1[8] == 80);
|
||||||
|
test(map1[13] == 130);
|
||||||
|
test(map1.size() == 3);
|
||||||
|
|
||||||
|
Map<int, int> map2(mAllocator, 15);
|
||||||
|
for (int i = 0; i < 1000000; i++) {
|
||||||
|
map2.add(std::make_pair(i, i * 100));
|
||||||
|
}
|
||||||
|
bool isValid = true;
|
||||||
|
for (int i = 0; i < 1000000; i++) {
|
||||||
|
if (map2[i] != i * 100) isValid = false;
|
||||||
|
}
|
||||||
|
test(isValid);
|
||||||
|
|
||||||
|
map1.remove(1);
|
||||||
|
map1.add(std::make_pair(1, 10));
|
||||||
|
test(map1.size() == 3);
|
||||||
|
test(map1[1] == 10);
|
||||||
|
|
||||||
|
// ----- Test remove() ----- //
|
||||||
|
|
||||||
|
map1.remove(1);
|
||||||
|
test(!map1.containsKey(1));
|
||||||
|
test(map1.containsKey(8));
|
||||||
|
test(map1.containsKey(13));
|
||||||
|
test(map1.size() == 2);
|
||||||
|
|
||||||
|
map1.remove(13);
|
||||||
|
test(!map1.containsKey(8));
|
||||||
|
test(map1.containsKey(13));
|
||||||
|
test(map1.size() == 1);
|
||||||
|
|
||||||
|
map1.remove(8);
|
||||||
|
test(!map1.containsKey(8));
|
||||||
|
test(map1.size() == 0);
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
for (int i = 0; i < 1000000; i++) {
|
||||||
|
map2.remove(i);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 1000000; i++) {
|
||||||
|
if (map2.containsKey(i)) isValid = false;
|
||||||
|
}
|
||||||
|
test(isValid);
|
||||||
|
test(map2.size() == 0);
|
||||||
|
|
||||||
|
Map<int, int> map3(mAllocator);
|
||||||
|
for (int i=0; i < 1000000; i++) {
|
||||||
|
map3.add(std::make_pair(i, i * 10));
|
||||||
|
map3.remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Test clear() ----- //
|
||||||
|
|
||||||
|
Map<int, int> map4(mAllocator);
|
||||||
|
map4.add(std::make_pair(2, 20));
|
||||||
|
map4.add(std::make_pair(4, 40));
|
||||||
|
map4.add(std::make_pair(6, 60));
|
||||||
|
map4.clear();
|
||||||
|
test(map4.size() == 0);
|
||||||
|
map4.add(std::make_pair(2, 20));
|
||||||
|
test(map4.size() == 1);
|
||||||
|
test(map4[2] == 20);
|
||||||
|
map4.clear();
|
||||||
|
test(map4.size() == 0);
|
||||||
|
|
||||||
|
Map<int, int> map5(mAllocator);
|
||||||
|
map5.clear();
|
||||||
|
test(map5.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testContainsKey() {
|
||||||
|
|
||||||
|
Map<int, int> map1(mAllocator);
|
||||||
|
|
||||||
|
test(!map1.containsKey(2));
|
||||||
|
test(!map1.containsKey(4));
|
||||||
|
test(!map1.containsKey(6));
|
||||||
|
|
||||||
|
map1.add(std::make_pair(2, 20));
|
||||||
|
map1.add(std::make_pair(4, 40));
|
||||||
|
map1.add(std::make_pair(6, 60));
|
||||||
|
|
||||||
|
test(map1.containsKey(2));
|
||||||
|
test(map1.containsKey(4));
|
||||||
|
test(map1.containsKey(6));
|
||||||
|
|
||||||
|
map1.remove(4);
|
||||||
|
test(!map1.containsKey(4));
|
||||||
|
test(map1.containsKey(2));
|
||||||
|
test(map1.containsKey(6));
|
||||||
|
|
||||||
|
map1.clear();
|
||||||
|
test(!map1.containsKey(2));
|
||||||
|
test(!map1.containsKey(6));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testIndexing() {
|
||||||
|
|
||||||
|
Map<int, int> map1(mAllocator);
|
||||||
|
map1.add(std::make_pair(2, 20));
|
||||||
|
map1.add(std::make_pair(4, 40));
|
||||||
|
map1.add(std::make_pair(6, 60));
|
||||||
|
test(map1[2] == 20);
|
||||||
|
test(map1[4] == 40);
|
||||||
|
test(map1[6] == 60);
|
||||||
|
|
||||||
|
map1[2] = 10;
|
||||||
|
map1[4] = 20;
|
||||||
|
map1[6] = 30;
|
||||||
|
|
||||||
|
test(map1[2] == 10);
|
||||||
|
test(map1[4] == 20);
|
||||||
|
test(map1[6] == 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testEquality() {
|
||||||
|
|
||||||
|
Map<std::string, int> map1(mAllocator, 10);
|
||||||
|
Map<std::string, int> map2(mAllocator, 2);
|
||||||
|
|
||||||
|
test(map1 == map2);
|
||||||
|
|
||||||
|
map1.add(std::make_pair("a", 1));
|
||||||
|
map1.add(std::make_pair("b", 2));
|
||||||
|
map1.add(std::make_pair("c", 3));
|
||||||
|
|
||||||
|
map2.add(std::make_pair("a", 1));
|
||||||
|
map2.add(std::make_pair("b", 2));
|
||||||
|
map2.add(std::make_pair("c", 4));
|
||||||
|
|
||||||
|
test(map1 == map1);
|
||||||
|
test(map2 == map2);
|
||||||
|
test(map1 != map2);
|
||||||
|
|
||||||
|
map2["c"] = 3;
|
||||||
|
|
||||||
|
test(map1 == map2);
|
||||||
|
|
||||||
|
Map<std::string, int> map3(mAllocator);
|
||||||
|
map3.add(std::make_pair("a", 1));
|
||||||
|
|
||||||
|
test(map1 != map3);
|
||||||
|
test(map2 != map3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAssignment() {
|
||||||
|
|
||||||
|
Map<int, int> map1(mAllocator);
|
||||||
|
map1.add(std::make_pair(1, 3));
|
||||||
|
map1.add(std::make_pair(2, 6));
|
||||||
|
map1.add(std::make_pair(10, 30));
|
||||||
|
/*
|
||||||
|
Map<int, int> map2(mAllocator);
|
||||||
|
map2 = map1;
|
||||||
|
test(map2.size() == map1.size());
|
||||||
|
test(map2[1] == 3);
|
||||||
|
test(map2[2] == 6);
|
||||||
|
test(map2[10] == 30);
|
||||||
|
|
||||||
|
Map<int, int> map3(mAllocator, 100);
|
||||||
|
map3 = map1;
|
||||||
|
test(map3.size() == map1.size());
|
||||||
|
test(map3[1] == 3);
|
||||||
|
test(map3[2] == 6);
|
||||||
|
test(map3[10] == 30);
|
||||||
|
|
||||||
|
Map<int, int> map4(mAllocator);
|
||||||
|
map3 = map4;
|
||||||
|
test(map3.size() == 0);
|
||||||
|
*/
|
||||||
|
Map<int, int> map5(mAllocator);
|
||||||
|
map5.add(std::make_pair(7, 8));
|
||||||
|
map5.add(std::make_pair(19, 70));
|
||||||
|
map1 = map5;
|
||||||
|
test(map5.size() == map1.size());
|
||||||
|
test(map1[7] == 8);
|
||||||
|
test(map1[19] == 70);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testIteration() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -61,13 +61,16 @@ class TestTransform : public Test {
|
||||||
|
|
||||||
mIdentityTransform.setToIdentity();
|
mIdentityTransform.setToIdentity();
|
||||||
|
|
||||||
decimal sinA = sin(PI/8.0f);
|
Vector3 unitVec(1, 1, 1);
|
||||||
decimal cosA = cos(PI/8.0f);
|
unitVec.normalize();
|
||||||
mTransform1 = Transform(Vector3(4, 5, 6), Quaternion(sinA, sinA, sinA, cosA));
|
|
||||||
|
|
||||||
decimal sinB = sin(PI/3.0f);
|
decimal sinA = std::sin(PI/8.0f);
|
||||||
decimal cosB = cos(PI/3.0f);
|
decimal cosA = std::cos(PI/8.0f);
|
||||||
mTransform2 = Transform(Vector3(8, 45, -6), Quaternion(sinB, sinB, sinB, cosB));
|
mTransform1 = Transform(Vector3(4, 5, 6), Quaternion(sinA * unitVec, cosA));
|
||||||
|
|
||||||
|
decimal sinB = std::sin(PI/3.0f);
|
||||||
|
decimal cosB = std::cos(PI/3.0f);
|
||||||
|
mTransform2 = Transform(Vector3(8, 45, -6), Quaternion(sinB * unitVec, cosB));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the tests
|
/// Run the tests
|
||||||
|
|
Loading…
Reference in New Issue
Block a user