--- a/src/types/resourcevector.h Sun Mar 05 13:33:37 2017 +0200 +++ b/src/types/resourcevector.h Sun Mar 05 16:47:52 2017 +0200 @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once #include <QVector> /* @@ -25,18 +26,27 @@ class ResourceVector { public: + using Filter = std::function<bool(T*, int)>; + using Callback = std::function<void(T*, int)>; + ~ResourceVector(); void append(T) = delete; template<typename TT = T, typename... Args> - T* append(Args&&... args); - T** const begin() const; - T** const end() const; + TT* append(Args&&... args); + void assimilate(int position, T* resource); + T* const* begin() const; + T* const* end() const; + int indexOf(T* resource) const; template<typename TT = T, typename... Args> - T* insert(int position, Args&&... args); + TT* insert(int position, Args&&... args); + bool isEmpty() const; void clear(); void removeAt(int position); T* operator[](int position) const; int size() const; + void swap(int position1, int position2); + void merge(ResourceVector<T>& other, int position = -1, Filter filter = nullptr, Callback callback = nullptr); + const QVector<T*>& toQVector() const; private: QVector<T*> _data; @@ -59,17 +69,18 @@ */ template<typename T> template<typename TT, typename... Args> -T* ResourceVector<T>::append(Args&&... args) +TT* ResourceVector<T>::append(Args&&... args) { - _data.append(new TT {args...}); - return _data[size() - 1]; + TT* resource = new TT {args...}; + _data.append(resource); + return resource; } /* * Returns an iterator to the beginning of this vector. */ template<typename T> -T** const ResourceVector<T>::begin() const +T* const* ResourceVector<T>::begin() const { return _data.cbegin(); } @@ -78,7 +89,7 @@ * Returns an iterator to the end of this vector. */ template<typename T> -T** const ResourceVector<T>::end() const +T* const* ResourceVector<T>::end() const { return _data.cend(); } @@ -88,9 +99,11 @@ */ template<typename T> template<typename TT, typename... Args> -T* ResourceVector<T>::insert(int position, Args&&... args) +TT* ResourceVector<T>::insert(int position, Args&&... args) { - _data.insert(position, new TT {args...}); + TT* resource = new TT {args...}; + _data.insert(position, resource); + return resource; } /* @@ -111,7 +124,7 @@ template<typename T> void ResourceVector<T>::removeAt(int position) { - if (position < _data.size()) + if (position >= 0 and position < _data.size()) { delete _data[position]; _data.removeAt(position); @@ -128,7 +141,7 @@ template<typename T> T* ResourceVector<T>::operator[](int position) const { - if (position < _data.size()) + if (position >= 0 and position < _data.size()) return _data[position]; else throw std::domain_error {"index out of range"}; @@ -144,6 +157,96 @@ } /* + * Inserts an already existing resource into the vector. The resource is assumed to not be managed by anything else! + * Please think twice before using this method. + */ +template<typename T> +void ResourceVector<T>::assimilate(int position, T* resource) +{ + _data.insert(position, resource); +} + +/* + * Returns the index of the provided resource in the vector, or -1 if not found. + * This operation is of linear complexity O(n). + */ +template<typename T> +int ResourceVector<T>::indexOf(T* resource) const +{ + return _data.indexOf(resource); +} + +/* + * Swaps the locations of two resource in this vector. + */ +template<typename T> +void ResourceVector<T>::swap(int position1, int position2) +{ + if (position1 >= 0 and position2 >= 0 and position1 < size() and position2 < size()) + { + qSwap(_data[position1], _data[position2]); + } + else + { + throw std::domain_error {"index out of range"}; + } +} + +/* + * Returns whether or not the vector is empty. + */ +template<typename T> +bool ResourceVector<T>::isEmpty() const +{ + return size() == 0; +} + +/* + * Migrates resources from the provided resource vector to this one. + * - `position` indicates where to insert the new resources. Default is to the end. + * - `filter` specifies a filter function for the migration. Objects not passing the filter will not be migrated. + * - `callback` specifies a function that is called for each successfully migrated object. + */ +template<typename T> +void ResourceVector<T>::merge(ResourceVector<T>& other, int position, Filter filter, Callback callback) +{ + if (position < 0) + position = size(); + + if (filter == nullptr) + filter = [](T*, int){return true;}; + + if (callback == nullptr) + callback = [](T*, int){}; + + for (int i = 0; i < other.size();) + { + T* resource = other[i]; + + if (filter(resource, i)) + { + _data.insert(position, resource); + other._data.removeAt(i); + callback(resource, position); + position += 1; + } + else + { + i += 1; + } + } +} + +/* + * Returns the underlying vector. + */ +template<typename T> +const QVector<T*>& ResourceVector<T>::toQVector() const +{ + return _data; +} + +/* * countof() overload for resource vectors. Returns the amount of resources in the given vector. */ template<typename T>