Working on containers

This commit is contained in:
Daniel Chappuis 2018-01-14 10:47:39 +01:00
parent 261ffef616
commit ceb27760cb
9 changed files with 1353 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View File

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