src/types/resourcevector.h

changeset 1186
eae8b3bce545
parent 1185
c2e0db52ea07
child 1189
0509b2b5eaa6
--- 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>

mercurial