/******************************************************************************** * 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_LIST_H #define REACTPHYSICS3D_LIST_H // Libraries #include "configuration.h" #include "memory/MemoryAllocator.h" #include #include #include #include namespace reactphysics3d { // Class List /** * This class represents a simple generic list with custom memory allocator. */ template class List { private: // -------------------- Attributes -------------------- // /// Buffer for the list elements void* mBuffer; /// Number of elements in the list size_t mSize; /// Number of allocated elements in the list size_t mCapacity; /// Memory allocator MemoryAllocator& mAllocator; 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 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(void* buffer, size_t index, size_t size) :mCurrentIndex(index), mBuffer(static_cast(buffer)), mSize(size) { } /// Copy constructor Iterator(const Iterator& it) :mCurrentIndex(it.mCurrentIndex), mBuffer(it.mBuffer), mSize(it.mSize) { } /// Deferencable reference operator*() { assert(mCurrentIndex >= 0 && mCurrentIndex < mSize); return mBuffer[mCurrentIndex]; } /// Const Deferencable const_reference operator*() const { assert(mCurrentIndex >= 0 && mCurrentIndex < mSize); return mBuffer[mCurrentIndex]; } /// Deferencable const_pointer operator->() const { assert(mCurrentIndex >= 0 && mCurrentIndex < mSize); return &(mBuffer[mCurrentIndex]); } /// Post increment (it++) Iterator& operator++() { assert(mCurrentIndex < mSize); mCurrentIndex++; return *this; } /// Pre increment (++it) Iterator operator++(int number) { assert(mCurrentIndex < mSize); 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; } /// Plus operator Iterator operator+(const difference_type& n) { return Iterator(mBuffer, mCurrentIndex + n, mSize); } /// Plus operator Iterator& operator+=(const difference_type& n) { mCurrentIndex += n; return *this; } /// Minus operator Iterator operator-(const difference_type& n) { return Iterator(mBuffer, mCurrentIndex - n, mSize); } /// Minus operator Iterator& operator-=(const difference_type& n) { mCurrentIndex -= n; return *this; } /// Difference operator difference_type operator-(const Iterator& iterator) const { return mCurrentIndex - iterator.mCurrentIndex; } /// Comparison operator bool operator<(const Iterator& other) const { return mCurrentIndex < other.mCurrentIndex; } /// Comparison operator bool operator>(const Iterator& other) const { return mCurrentIndex > other.mCurrentIndex; } /// Comparison operator bool operator<=(const Iterator& other) const { return mCurrentIndex <= other.mCurrentIndex; } /// Comparison operator bool operator>=(const Iterator& other) const { return mCurrentIndex >= other.mCurrentIndex; } /// 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[iterator.mCurrentIndex]); } /// Inequality operator (it != end()) bool operator!=(const Iterator& iterator) const { return !(*this == iterator); } /// Frienship friend class List; }; // -------------------- Methods -------------------- // /// Constructor List(MemoryAllocator& allocator, size_t capacity = 0) : mBuffer(nullptr), mSize(0), mCapacity(0), mAllocator(allocator) { if (capacity > 0) { // Allocate memory reserve(capacity); } } /// Copy constructor List(const List& list) : mBuffer(nullptr), mSize(0), mCapacity(0), mAllocator(list.mAllocator) { // All all the elements of the list to the current one addRange(list); } /// Destructor ~List() { // If elements have been allocated if (mCapacity > 0) { // Clear the list clear(true); } } /// Allocate memory for a given number of elements void reserve(size_t capacity) { if (capacity <= mCapacity) return; // Allocate memory for the new array void* newMemory = mAllocator.allocate(capacity * sizeof(T)); if (mBuffer != nullptr) { if (mSize > 0) { // Copy the elements to the new allocated memory location T* destination = static_cast(newMemory); T* items = static_cast(mBuffer); std::uninitialized_copy(items, items + mSize, destination); // Destruct the previous items for (size_t i=0; i(mBuffer) + mSize * sizeof(T)) T(element); mSize++; } /// Try to find a given item of the list and return an iterator /// pointing to that element if it exists in the list. Otherwise, /// this method returns the end() iterator Iterator find(const T& element) { for (uint i=0; i(mBuffer)[i]) { return Iterator(mBuffer, i, mSize); } } return end(); } /// Look for an element in the list and remove it Iterator remove(const T& element) { return remove(find(element)); } /// Remove an element from the list and return a iterator /// pointing to the element after the removed one (or end() if none) Iterator remove(const Iterator& it) { assert(it.mBuffer == mBuffer); return removeAt(it.mCurrentIndex); } /// Remove an element from the list at a given index and return an /// iterator pointing to the element after the removed one (or end() if none) Iterator removeAt(uint index) { assert(index >= 0 && index < mSize); // Call the destructor (static_cast(mBuffer)[index]).~T(); mSize--; if (index != mSize) { // Move the elements to fill in the empty slot char* dest = static_cast(mBuffer) + index * sizeof(T); char* src = dest + sizeof(T); std::memmove(static_cast(dest), static_cast(src), (mSize - index) * sizeof(T)); } // Return an iterator pointing to the element after the removed one return Iterator(mBuffer, index, mSize); } /// Append another list at the end of the current one void addRange(const List& list) { // If we need to allocate more memory if (mSize + list.size() > mCapacity) { // Allocate memory reserve(mSize + list.size()); } // Add the elements of the list to the current one for(uint i=0; i(mBuffer) + mSize * sizeof(T)) T(list[i]); mSize++; } } /// Clear the list void clear(bool releaseMemory = false) { // Call the destructor of each element for (uint i=0; i < mSize; i++) { (static_cast(mBuffer)[i]).~T(); } mSize = 0; // If we need to release all the allocated memory if (releaseMemory && mCapacity > 0) { // Release the memory allocated on the heap mAllocator.release(mBuffer, mCapacity * sizeof(T)); mBuffer = nullptr; mCapacity = 0; } } /// Return the number of elements in the list size_t size() const { return mSize; } /// Return the capacity of the list size_t capacity() const { return mCapacity; } /// Overloaded index operator T& operator[](const uint index) { assert(index >= 0 && index < mSize); return (static_cast(mBuffer)[index]); } /// Overloaded const index operator const T& operator[](const uint index) const { assert(index >= 0 && index < mSize); return (static_cast(mBuffer)[index]); } /// Overloaded equality operator bool operator==(const List& list) const { if (mSize != list.mSize) return false; T* items = static_cast(mBuffer); for (size_t i=0; i < mSize; i++) { if (items[i] != list[i]) { return false; } } return true; } /// Overloaded not equal operator bool operator!=(const List& list) const { return !((*this) == list); } /// Overloaded assignment operator List& operator=(const List& list) { if (this != &list) { // Clear all the elements clear(); // Add all the elements of the list to the current one addRange(list); } return *this; } /// Return a begin iterator Iterator begin() const { return Iterator(mBuffer, 0, mSize); } /// Return a end iterator Iterator end() const { return Iterator(mBuffer, mSize, mSize); } }; } #endif