Add Deque container

This commit is contained in:
Daniel Chappuis 2018-12-14 00:02:40 +01:00
parent 6e67b83ca4
commit 0c3f5ae5e6
5 changed files with 1015 additions and 0 deletions

View File

@ -160,6 +160,7 @@ SET (REACTPHYSICS3D_HEADERS
"src/containers/Map.h"
"src/containers/Set.h"
"src/containers/Pair.h"
"src/containers/Deque.h"
"src/utils/Profiler.h"
"src/utils/Logger.h"
)

673
src/containers/Deque.h Normal file
View File

@ -0,0 +1,673 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2018 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_DEQUE_H
#define REACTPHYSICS3D_DEQUE_H
// Libraries
#include "configuration.h"
#include "memory/MemoryAllocator.h"
#include <cassert>
#include <cmath>
#include <cstring>
#include <iterator>
#include <memory>
namespace reactphysics3d {
// Class Deque
/**
* This class represents a Deque. A Deque is a double ended queue. It is possible to
* push and pop items at both ends of the queue. Note that in the following code, the
* virtualIndex is the index of the items in the deque in range [0, mSize-1] where
* 0 is always the front item and mSize-1 the back item. There is a virtual index for
* each item that is in the deque. The allocatedIndex is the index of a allocated slot in the
* deque in range [0, (mNbChunks * CHUNK_NB_ITEMS)-1]. A given allocatedIndex corresponds to a slot
* in the deque that can be empty or contains an item.
*/
template<typename T>
class Deque {
private:
// -------------------- Constants -------------------- //
/// Number of items in a chunk
const uint CHUNK_NB_ITEMS = 17;
/// First item index in a chunk
const uint CHUNK_FIRST_ITEM_INDEX = CHUNK_NB_ITEMS / 2;
// -------------------- Attributes -------------------- //
/// Array of chunks
T** mChunks;
/// Number of current elements in the deque
size_t mSize;
/// Number of chunks
size_t mNbChunks;
/// Index of the chunk with the first element of the deque
size_t mFirstChunkIndex;
/// Index of the chunk with the last element of the deque
size_t mLastChunkIndex;
/// Index of the first element in the first chunk
uint8 mFirstItemIndex;
/// Index of the last element in the last chunk
uint8 mLastItemIndex;
/// Memory allocator
MemoryAllocator& mAllocator;
// -------------------- Methods -------------------- //
/// Return a reference to an item at the given virtual index in range [0; mSize-1]
T& getItem(size_t virtualIndex) const {
// If the virtual index is valid
if (virtualIndex < mSize) {
size_t chunkIndex = mFirstChunkIndex;
size_t itemIndex = mFirstItemIndex;
const size_t nbItemsFirstChunk = CHUNK_NB_ITEMS - mFirstItemIndex;
if (virtualIndex < nbItemsFirstChunk) {
itemIndex += virtualIndex;
}
else {
virtualIndex -= nbItemsFirstChunk;
chunkIndex++;
chunkIndex += virtualIndex / CHUNK_NB_ITEMS;
itemIndex = virtualIndex % CHUNK_NB_ITEMS;
}
return mChunks[chunkIndex][itemIndex];
}
else {
assert(false);
}
}
/// Add more chunks
void expandChunks(size_t atLeastNbChunks = 0) {
// If it is not necessary to expand the chunks
if (atLeastNbChunks > 0 && atLeastNbChunks <= mNbChunks) {
return;
}
size_t newNbChunks = mNbChunks == 0 ? 3 : 2 * mNbChunks - 1;
if (atLeastNbChunks > 0 && newNbChunks < atLeastNbChunks) {
newNbChunks = size_t(atLeastNbChunks / 2) * 2 + 1;
}
const size_t halfNbChunksToAdd = mNbChunks == 0 ? 1 : (mNbChunks - 1) / 2;
// Allocate memory for the new array of pointers to chunk
void* newMemory = mAllocator.allocate(newNbChunks * sizeof(T*));
assert(newMemory != nullptr);
T** newChunks = static_cast<T**>(newMemory);
// If chunks have already been allocated
if (mNbChunks > 0) {
// Copy the pointers to the previous chunks to the new allocated memory location
std::uninitialized_copy(mChunks, mChunks + mNbChunks, newChunks + halfNbChunksToAdd);
// Release the previously allocated memory
mAllocator.release(mChunks, mNbChunks * sizeof(T*));
}
mChunks = newChunks;
// If we need to allocate the first chunk (in the middle of the chunks array)
if (mNbChunks == 0) {
mChunks[newNbChunks / 2] = static_cast<T*>(mAllocator.allocate(sizeof(T) * CHUNK_NB_ITEMS));
assert(mChunks[newNbChunks / 2] != nullptr);
}
mNbChunks = newNbChunks;
// Allocate memory for each new chunk
for (size_t i=0; i < halfNbChunksToAdd; i++) {
// Allocate memory for the new chunk
mChunks[i] = static_cast<T*>(mAllocator.allocate(sizeof(T) * CHUNK_NB_ITEMS));
assert(mChunks[i] != nullptr);
mChunks[mNbChunks - 1 - i] = static_cast<T*>(mAllocator.allocate(sizeof(T) * CHUNK_NB_ITEMS));
assert(mChunks[mNbChunks - 1 -i] != nullptr);
}
// Update the first and last chunk index
mFirstChunkIndex += halfNbChunksToAdd;
mLastChunkIndex += halfNbChunksToAdd;
}
/*
/// Get the next item in the deque (return false if we have reached the end)
bool getNextItem(size_t& chunkIndex, size_t& itemIndex) const {
bool isValid = true;
// If we have reached the last item
if (chunkIndex == mLastChunkIndex && itemIndex == mLastItemIndex) {
isValid = false;
}
// If we were at the last item of the chunk
if (itemIndex == CHUNK_NB_ITEMS - 1) {
// Move to the next chunk
chunkIndex++;
itemIndex = 0;
}
else {
itemIndex++;
}
return isValid;
}
/// Get the previous item in the deque (return false if we have reached the front)
bool getPreviousItem(size_t& chunkIndex, size_t& itemIndex) const {
// If we have reached the first item
if (chunkIndex == mFirstChunkIndex && itemIndex == mFirstItemIndex) {
return false;
}
// If we were at the first item of the chunk
if (itemIndex == 0) {
// Move to the previous chunk
chunkIndex--;
itemIndex = CHUNK_NB_ITEMS - 1;
}
else {
itemIndex--;
}
return true;
}
/// Return true if the two chunk/item indices are currently valid for the state of the deque
bool areValidIndices(size_t chunkIndex, size_t itemIndex) const {
return chunkIndex >= mFirstChunkIndex && chunkIndex <= mLastChunkIndex &&
itemIndex >= mFirstItemIndex && itemIndex <= mLastItemIndex;
}
*/
public:
/// Class Iterator
/**
* This class represents an iterator for the Deque
*/
class Iterator {
private:
size_t mVirtualIndex;
const Deque<T>* mDeque;
public:
// Iterator traits
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = T const*;
using reference = T&;
using const_reference = const T&;
using iterator_category = std::random_access_iterator_tag;
/// Constructor
Iterator() = default;
/// Constructor
Iterator(const Deque<T>* deque, size_t virtualIndex) : mVirtualIndex(virtualIndex), mDeque(deque) {
}
/// Copy constructor
Iterator(const Iterator& it) : mVirtualIndex(it.mVirtualIndex), mDeque(it.mDeque) {
}
/// Deferencable
reference operator*() {
assert(mVirtualIndex < mDeque->mSize);
return mDeque->getItem(mVirtualIndex);
}
/// Const Deferencable
const_reference operator*() const {
assert(mVirtualIndex < mDeque->mSize);
return mDeque->getItem(mVirtualIndex);
}
/// Deferencable
const_pointer operator->() const {
assert(mVirtualIndex < mDeque->mSize);
return &(mDeque->getItem(mVirtualIndex));
}
/// Post increment (it++)
Iterator& operator++() {
assert(mVirtualIndex < mDeque->mSize);
mVirtualIndex++;
return *this;
}
/// Pre increment (++it)
Iterator operator++(int number) {
assert(mVirtualIndex < mDeque->mSize);
Iterator tmp = *this;
mVirtualIndex++;
return tmp;
}
/// Post decrement (it--)
Iterator& operator--() {
mVirtualIndex--;
return *this;
}
/// Pre decrement (--it)
Iterator operator--(int number) {
Iterator tmp = *this;
mVirtualIndex--;
return tmp;
}
/// Plus operator
Iterator operator+(const difference_type& n) {
return Iterator(mDeque, mVirtualIndex + n);
}
/// Plus operator
Iterator& operator+=(const difference_type& n) {
mVirtualIndex += n;
return *this;
}
/// Minus operator
Iterator operator-(const difference_type& n) {
return Iterator(mDeque, mVirtualIndex - n);
}
/// Minus operator
Iterator& operator-=(const difference_type& n) {
mVirtualIndex -= n;
return *this;
}
/// Difference operator
difference_type operator-(const Iterator& iterator) const {
return mVirtualIndex - iterator.mVirtualIndex;
}
/// Comparison operator
bool operator<(const Iterator& other) const {
return mVirtualIndex < other.mVirtualIndex;
}
/// Comparison operator
bool operator>(const Iterator& other) const {
return mVirtualIndex > other.mVirtualIndex;
}
/// Comparison operator
bool operator<=(const Iterator& other) const {
return mVirtualIndex <= other.mVirtualIndex;
}
/// Comparison operator
bool operator>=(const Iterator& other) const {
return mVirtualIndex >= other.mVirtualIndex;
}
/// Equality operator (it == end())
bool operator==(const Iterator& iterator) const {
return mVirtualIndex == iterator.mVirtualIndex;
}
/// Inequality operator (it != end())
bool operator!=(const Iterator& iterator) const {
return !(*this == iterator);
}
/// Frienship
friend class Deque;
};
// -------------------- Methods -------------------- //
/// Constructor
Deque(MemoryAllocator& allocator)
: mChunks(nullptr), mSize(0), mNbChunks(0), mFirstChunkIndex(1),
mLastChunkIndex(1), mFirstItemIndex(CHUNK_FIRST_ITEM_INDEX),
mLastItemIndex(CHUNK_FIRST_ITEM_INDEX), mAllocator(allocator) {
// Allocate memory for the chunks array
expandChunks();
}
/// Copy constructor
Deque(const Deque<T>& deque)
: mSize(0), mNbChunks(0), mFirstChunkIndex(1),
mLastChunkIndex(1), mFirstItemIndex(CHUNK_FIRST_ITEM_INDEX),
mLastItemIndex(CHUNK_FIRST_ITEM_INDEX), mAllocator(deque.mAllocator) {
// Allocate memory for the array of chunks
expandChunks(deque.mNbChunks);
if (deque.mSize > 0) {
const size_t dequeHalfSize1 = std::ceil(deque.mSize / 2.0f);
const size_t dequeHalfSize2 = deque.mSize - dequeHalfSize1;
// Add the items into the deque
for(size_t i=0; i < dequeHalfSize1; i++) {
addFront(deque[dequeHalfSize1 - 1 - i]);
}
for(size_t i=0; i < dequeHalfSize2; i++) {
addBack(deque[dequeHalfSize1 + i]);
}
}
}
/// Destructor
~Deque() {
clear();
// Release each chunk
for (size_t i=0; i < mNbChunks; i++) {
mAllocator.release(static_cast<void*>(mChunks[i]), sizeof(T) * CHUNK_NB_ITEMS);
}
// Release the chunks array
mAllocator.release(static_cast<void*>(mChunks), sizeof(T*) * mNbChunks);
}
/// Add an element at the end of the deque
void addBack(const T& element) {
// If we need to add the item in a another chunk
if (mLastItemIndex == CHUNK_NB_ITEMS - 1) {
// If we need to add more chunks
if (mLastChunkIndex == mNbChunks - 1) {
// Add more chunks
expandChunks();
}
mLastItemIndex = 0;
mLastChunkIndex++;
}
else if (mSize != 0) {
mLastItemIndex++;
}
// Construct the element at its location in the chunk
new (static_cast<void*>(&(mChunks[mLastChunkIndex][mLastItemIndex]))) T(element);
mSize++;
assert(mFirstChunkIndex >= 0 && mLastChunkIndex < mNbChunks);
assert(mFirstItemIndex >= 0 && mFirstItemIndex < CHUNK_NB_ITEMS);
assert(mLastItemIndex >= 0 && mLastItemIndex < CHUNK_NB_ITEMS);
assert(mFirstChunkIndex <= mLastChunkIndex);
}
/// Add an element at the front of the deque
void addFront(const T& element) {
// If we need to add the item in another chunk
if (mFirstItemIndex == 0) {
// If we need to add more chunks
if (mFirstChunkIndex == 0) {
// Add more chunks
expandChunks();
}
mFirstItemIndex = CHUNK_NB_ITEMS - 1;
mFirstChunkIndex--;
}
else if (mSize != 0) {
mFirstItemIndex--;
}
// Construct the element at its location in the chunk
new (static_cast<void*>(&(mChunks[mFirstChunkIndex][mFirstItemIndex]))) T(element);
mSize++;
assert(mFirstChunkIndex >= 0 && mLastChunkIndex < mNbChunks);
assert(mFirstItemIndex >= 0 && mFirstItemIndex < CHUNK_NB_ITEMS);
assert(mLastItemIndex >= 0 && mLastItemIndex < CHUNK_NB_ITEMS);
assert(mFirstChunkIndex <= mLastChunkIndex);
}
/// Remove the first element of the deque
void popFront() {
if (mSize > 0) {
// Call the destructor of the first element
mChunks[mFirstChunkIndex][mFirstItemIndex].~T();
mSize--;
if (mSize == 0) {
mFirstChunkIndex = mNbChunks / 2;
mFirstItemIndex = CHUNK_FIRST_ITEM_INDEX;
mLastChunkIndex = mFirstChunkIndex;
mLastItemIndex = CHUNK_FIRST_ITEM_INDEX;
}
else if (mFirstItemIndex == CHUNK_NB_ITEMS - 1){
mFirstChunkIndex++;
mFirstItemIndex = 0;
}
else {
mFirstItemIndex++;
}
assert(mFirstChunkIndex >= 0 && mLastChunkIndex < mNbChunks);
assert(mFirstItemIndex >= 0 && mFirstItemIndex < CHUNK_NB_ITEMS);
assert(mLastItemIndex >= 0 && mLastItemIndex < CHUNK_NB_ITEMS);
assert(mFirstChunkIndex <= mLastChunkIndex);
}
}
/// Remove the last element of the deque
void popBack() {
if (mSize > 0) {
// Call the destructor of the last element
mChunks[mLastChunkIndex][mLastItemIndex].~T();
mSize--;
if (mSize == 0) {
mFirstChunkIndex = mNbChunks / 2;
mFirstItemIndex = CHUNK_FIRST_ITEM_INDEX;
mLastChunkIndex = mFirstChunkIndex;
mLastItemIndex = CHUNK_FIRST_ITEM_INDEX;
}
else if (mLastItemIndex == 0){
mLastChunkIndex--;
mLastItemIndex = CHUNK_NB_ITEMS - 1;
}
else {
mLastItemIndex--;
}
assert(mFirstChunkIndex >= 0 && mLastChunkIndex < mNbChunks);
assert(mFirstItemIndex >= 0 && mFirstItemIndex < CHUNK_NB_ITEMS);
assert(mLastItemIndex >= 0 && mLastItemIndex < CHUNK_NB_ITEMS);
assert(mFirstChunkIndex <= mLastChunkIndex);
}
}
/// Return a reference to the first item of the deque
const T& getFront() const {
if (mSize > 0) {
return mChunks[mFirstChunkIndex][mFirstItemIndex];
}
assert(false);
}
/// Return a reference to the last item of the deque
const T& getBack() const {
if (mSize > 0) {
return mChunks[mLastChunkIndex][mLastItemIndex];
}
assert(false);
}
/// Clear the elements of the deque
void clear() {
if (mSize > 0) {
// Call the destructor of every items
for (size_t i=0; i < mSize; i++) {
getItem(i).~T();
}
mSize = 0;
mFirstChunkIndex = mNbChunks / 2;
mLastChunkIndex = mFirstChunkIndex;
mFirstItemIndex = CHUNK_FIRST_ITEM_INDEX;
mLastItemIndex = CHUNK_FIRST_ITEM_INDEX;
}
}
/// Return the number of elements in the deque
size_t size() const {
return mSize;
}
/// Overloaded index operator
T& operator[](const uint index) {
assert(index < mSize);
return getItem(index);
}
/// Overloaded const index operator
const T& operator[](const uint index) const {
assert(index < mSize);
return getItem(index);
}
/// Overloaded equality operator
bool operator==(const Deque<T>& deque) const {
if (mSize != deque.mSize) return false;
for (size_t i=0; i < mSize; i++) {
if (getItem(i) != deque.getItem(i)) {
return false;
}
}
return true;
}
/// Overloaded not equal operator
bool operator!=(const Deque<T>& deque) const {
return !((*this) == deque);
}
/// Overloaded assignment operator
Deque<T>& operator=(const Deque<T>& deque) {
if (this != &deque) {
// Clear all the elements
clear();
if (deque.mSize > 0) {
// Number of used chunks
const size_t nbUsedChunks = deque.mLastChunkIndex - deque.mFirstChunkIndex + 1;
// Expand the chunk if necessary
expandChunks(nbUsedChunks);
const size_t dequeHalfSize1 = std::ceil(deque.mSize / 2.0f);
const size_t dequeHalfSize2 = deque.mSize - dequeHalfSize1;
// Add the items into the deque
for(size_t i=0; i < dequeHalfSize1; i++) {
addFront(deque[dequeHalfSize1 - 1 - i]);
}
for(size_t i=0; i < dequeHalfSize2; i++) {
addBack(deque[dequeHalfSize1 + i]);
}
}
}
return *this;
}
/// Return a begin iterator
Iterator begin() const {
return Iterator(this, 0);
}
/// Return a end iterator
Iterator end() const {
return Iterator(this, mSize);
}
};
}
#endif

View File

@ -18,6 +18,7 @@ SET (RP3D_TESTS_HEADERS
"tests/containers/TestList.h"
"tests/containers/TestMap.h"
"tests/containers/TestSet.h"
"tests/containers/TestDeque.h"
"tests/mathematics/TestMathematicsFunctions.h"
"tests/mathematics/TestMatrix2x2.h"
"tests/mathematics/TestMatrix3x3.h"

View File

@ -42,6 +42,7 @@
#include "tests/containers/TestList.h"
#include "tests/containers/TestMap.h"
#include "tests/containers/TestSet.h"
#include "tests/containers/TestDeque.h"
using namespace reactphysics3d;
@ -54,6 +55,7 @@ int main() {
testSuite.addTest(new TestList("List"));
testSuite.addTest(new TestMap("Map"));
testSuite.addTest(new TestSet("Set"));
testSuite.addTest(new TestDeque("Deque"));
// ---------- Mathematics tests ---------- //

View File

@ -0,0 +1,338 @@
/********************************************************************************
* 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_DEQUE_H
#define TEST_DEQUE_H
// Libraries
#include "Test.h"
#include "containers/Deque.h"
#include "memory/DefaultAllocator.h"
/// Reactphysics3D namespace
namespace reactphysics3d {
// Class TestDeque
/**
* Unit test for the Deque class
*/
class TestDeque : public Test {
private :
// ---------- Atributes ---------- //
DefaultAllocator mAllocator;
public :
// ---------- Methods ---------- //
/// Constructor
TestDeque(const std::string& name) : Test(name) {
}
/// Run the tests
void run() {
testConstructors();
testAddPopClear();
testAssignment();
testEquality();
testIterators();
}
void testConstructors() {
// ----- Constructors ----- //
Deque<int> deque1(mAllocator);
rp3d_test(deque1.size() == 0);
Deque<int> deque2(mAllocator);
deque2.addBack(1);
deque2.addBack(2);
deque2.addBack(3);
rp3d_test(deque2.size() == 3);
// ----- Copy Constructors ----- //
Deque<int> deque3(deque1);
rp3d_test(deque3.size() == 0);
Deque<int> deque4(deque2);
rp3d_test(deque4.size() == deque2.size());
Deque<int>::Iterator it3 = deque2.begin();
Deque<int>::Iterator it5 = deque4.begin();
for (uint i=0; i<deque2.size(); i++) {
rp3d_test((*it3) == (*it5));
++it3;
++it5;
}
// ----- Test capacity grow ----- //
Deque<std::string> deque5(mAllocator);
for (uint i=0; i<300; i++) {
deque5.addBack("test");
}
// ----- Test [] operator ----- //
Deque<int> deque6(deque2);
deque6.addBack(1);
rp3d_test(deque6[0] == 1);
deque6.addBack(2);
rp3d_test(deque6[0] == 1);
rp3d_test(deque6[1] == 2);
deque6.addFront(5);
rp3d_test(deque6[0] == 5);
rp3d_test(deque6[1] == 1);
rp3d_test(deque6[2] == 2);
deque6.addFront(7);
rp3d_test(deque6[0] == 7);
rp3d_test(deque6[1] == 5);
rp3d_test(deque6[2] == 1);
rp3d_test(deque6[3] == 2);
deque6.popFront();
rp3d_test(deque6[0] == 5);
rp3d_test(deque6[1] == 1);
rp3d_test(deque6[2] == 2);
}
void testAddPopClear() {
// ----- Test addBack() ----- //
Deque<int> deque1(mAllocator);
deque1.addBack(4);
rp3d_test(deque1.size() == 1);
rp3d_test(deque1.getBack() == 4);
rp3d_test(deque1.getFront() == 4);
deque1.addBack(9);
rp3d_test(deque1.size() == 2);
rp3d_test(deque1.getBack() == 9);
rp3d_test(deque1.getFront() == 4);
deque1.addBack(1);
rp3d_test(deque1.size() == 3);
rp3d_test(deque1.getBack() == 1);
rp3d_test(deque1.getFront() == 4);
// ----- Test addFront() ----- //
Deque<int> deque2(mAllocator);
deque2.addFront(4);
rp3d_test(deque2.size() == 1);
rp3d_test(deque2.getBack() == 4);
rp3d_test(deque2.getFront() == 4);
deque2.addFront(9);
rp3d_test(deque2.size() == 2);
rp3d_test(deque2.getBack() == 4);
rp3d_test(deque2.getFront() == 9);
deque2.addFront(1);
rp3d_test(deque2.size() == 3);
rp3d_test(deque2.getBack() == 4);
rp3d_test(deque2.getFront() == 1);
// ----- Test popFront() ----- //
deque1.popFront();
rp3d_test(deque1.size() == 2);
rp3d_test(deque1.getFront() == 9);
deque1.popFront();
rp3d_test(deque1.size() == 1);
rp3d_test(deque1.getFront() == 1);
deque1.popFront();
rp3d_test(deque1.size() == 0);
// ----- Test popBack() ----- //
deque2.popBack();
rp3d_test(deque2.size() == 2);
rp3d_test(deque2.getBack() == 9);
deque2.popBack();
rp3d_test(deque2.size() == 1);
rp3d_test(deque2.getBack() == 1);
deque2.popBack();
rp3d_test(deque2.size() == 0);
deque2.addBack(1);
deque2.addFront(2);
rp3d_test(deque2.getBack() == 1);
rp3d_test(deque2.getFront() == 2);
deque2.addBack(3);
deque2.addFront(4);
rp3d_test(deque2.getBack() == 3);
rp3d_test(deque2.getFront() == 4);
deque2.popBack();
deque2.popFront();
rp3d_test(deque2.getBack() == 1);
rp3d_test(deque2.getFront() == 2);
// ----- Test clear() ----- //
deque1.clear();
deque2.clear();
rp3d_test(deque1.size() == 0);
rp3d_test(deque2.size() == 0);
deque1.addBack(1);
deque1.addFront(2);
deque1.addBack(3);
deque1.addFront(4);
rp3d_test(deque1.getBack() == 3);
rp3d_test(deque1.getFront() == 4);
deque1.clear();
rp3d_test(deque1.size() == 0);
}
void testAssignment() {
Deque<int> deque1(mAllocator);
deque1.addBack(1);
deque1.addBack(2);
deque1.addBack(3);
Deque<int> deque2(mAllocator);
deque2.addFront(5);
deque2.addBack(6);
Deque<int> deque3(mAllocator);
Deque<int> deque4(mAllocator);
deque4.addBack(7);
deque4.addBack(9);
deque3 = deque2;
rp3d_test(deque2.size() == deque3.size());
rp3d_test(deque2.size() == 2);
rp3d_test(deque2.getBack() == deque3.getBack());
rp3d_test(deque2.getFront() == deque3.getFront());
deque4 = deque1;
rp3d_test(deque4.size() == deque1.size())
rp3d_test(deque4.size() == 3)
rp3d_test(deque4.getFront() == 1);
rp3d_test(deque4.getBack() == 3);
}
void testEquality() {
Deque<int> deque1(mAllocator);
deque1.addFront(1);
deque1.addBack(2);
deque1.addBack(3);
Deque<int> deque2(mAllocator);
deque2.addBack(1);
deque2.addBack(2);
Deque<int> deque3(mAllocator);
deque3.addBack(1);
deque3.addBack(2);
deque3.addBack(3);
Deque<int> deque4(mAllocator);
deque4.addFront(1);
deque4.addFront(5);
deque4.addFront(3);
Deque<int> deque5(mAllocator);
deque5.addFront(3);
deque5.addFront(2);
deque5.addFront(1);
rp3d_test(deque1 == deque1);
rp3d_test(deque1 != deque2);
rp3d_test(deque1 == deque3);
rp3d_test(deque1 != deque4);
rp3d_test(deque2 != deque4);
rp3d_test(deque1 == deque5);
}
void testIterators() {
Deque<int> deque1(mAllocator);
rp3d_test(deque1.begin() == deque1.end());
deque1.addBack(5);
deque1.addBack(6);
deque1.addBack(8);
deque1.addBack(-1);
Deque<int>::Iterator itBegin = deque1.begin();
Deque<int>::Iterator itEnd = deque1.end();
Deque<int>::Iterator it = deque1.begin();
rp3d_test(itBegin < itEnd);
rp3d_test(itBegin <= itEnd);
rp3d_test(itEnd > itBegin);
rp3d_test(itEnd >= itBegin);
rp3d_test(itBegin == it);
rp3d_test(*it == 5);
rp3d_test(*(it++) == 5);
rp3d_test(*it == 6);
rp3d_test(*(it--) == 6);
rp3d_test(*it == 5);
rp3d_test(*(++it) == 6);
rp3d_test(*it == 6);
rp3d_test(*(--it) == 5);
rp3d_test(*it == 5);
rp3d_test(it == itBegin);
it = deque1.end();
rp3d_test(it == itEnd);
it--;
rp3d_test(*it == -1);
it++;
rp3d_test(it == itEnd);
Deque<int> deque2(mAllocator);
for (auto it = deque1.begin(); it != deque1.end(); ++it) {
deque2.addBack(*it);
}
rp3d_test(deque1 == deque2);
it = itBegin;
rp3d_test(*(it + 2) == 8);
it += 2;
rp3d_test(*it == 8);
rp3d_test(*(it - 2) == 5);
it -= 2;
rp3d_test(*it == 5);
rp3d_test((itEnd - itBegin) == 4);
it = itBegin;
*it = 19;
rp3d_test(*it == 19);
}
};
}
#endif