src/functional.h

changeset 63
f7dd937667a5
child 106
128efb9d148b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/functional.h	Fri Feb 28 19:24:33 2020 +0200
@@ -0,0 +1,159 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2020 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include <algorithm>
+#include <functional>
+#include <QVector>
+#include <QSet>
+#include <QList>
+
+namespace fn
+{
+	template<typename C>
+	class InsertIterator;
+}
+
+/**
+ * Like std::back_inserter but calls x.insert(v) instead
+ */
+template<typename C>
+class fn::InsertIterator
+{
+public:
+	InsertIterator(C& container) :
+		container{container} {}
+	auto operator*()
+	{
+		return *this;
+	}
+	auto operator++()
+	{
+		return *this;
+	}
+	auto operator++(int)
+	{
+		return *this;
+	}
+	template<typename T>
+	auto operator=(T&& value)
+	{
+		this->container.insert(std::forward<T>(value));
+		return *this;
+	}
+private:
+	C& container;
+};
+
+namespace fn
+{
+	// Constructs a fn::InsertIterator
+	template<typename C>
+	InsertIterator<C> makeInsertIterator(C& container)
+	{
+		return InsertIterator<C>{container};
+	}
+
+	// Constructs a back_inserter for std::vector
+	template<typename T>
+	auto makeDefaultInserter(std::vector<T>& vec)
+	{
+		return std::back_inserter(vec);
+	}
+
+	// Constructs a back_inserter for QVector
+	template<typename T>
+	auto makeDefaultInserter(QVector<T>& vec)
+	{
+		return std::back_inserter(vec);
+	}
+
+	// Constructs a back_inserter for QList
+	template<typename T>
+	auto makeDefaultInserter(QList<T>& vec)
+	{
+		return std::back_inserter(vec);
+	}
+
+	// Constructs an fn::InsertIterator for QSet
+	template<typename T>
+	auto makeDefaultInserter(QSet<T>& vec)
+	{
+		return InsertIterator(vec);
+	}
+
+	// Changes the value type of C
+	template<typename C, typename TT>
+	struct ChangeContainerValueType
+	{
+	};
+
+	// Changes the value type of std::vector
+	template<typename T, typename TT>
+	struct ChangeContainerValueType<std::vector<T>, TT>
+	{
+		using type = std::vector<TT>;
+	};
+
+	// Changes the value type of QVector
+	template<typename T, typename TT>
+	struct ChangeContainerValueType<QVector<T>, TT>
+	{
+		using type = QVector<TT>;
+	};
+
+	// Changes the value type of QSet
+	template<typename T, typename TT>
+	struct ChangeContainerValueType<QSet<T>, TT>
+	{
+		using type = QSet<TT>;
+	};
+
+	// Changes the value type of QList
+	template<typename T, typename TT>
+	struct ChangeContainerValueType<QList<T>, TT>
+	{
+		using type = QList<TT>;
+	};
+
+	// Changes the value type of C
+	template<typename C, typename TT>
+	using ChangeContainerValueType_t = typename ChangeContainerValueType<C, TT>::type;
+
+	/**
+	 * \brief Applies \c function to all elements of \c container
+	 * \param container Container to iterate
+	 * \param function Function to apply
+	 * \param Rt result type. If not provided, a suitable result type is deduced from inputs
+	 * \returns mapped result container
+	 */
+	template<typename Rt = void, typename C, typename Fn>
+	auto map(C&& container, Fn&& function)
+	{
+		using value_t = decltype(*std::declval<C>().begin());
+		using newvalue_t = std::result_of_t<Fn(value_t)>;
+		using result_t = std::conditional_t<
+			std::is_same_v<Rt, void>,
+			ChangeContainerValueType_t<std::remove_reference_t<C>, newvalue_t>,
+			Rt>;
+		result_t result;
+		result.reserve(std::end(container) - std::begin(container));
+		std::transform(std::begin(container), std::end(container), makeDefaultInserter(result), function);
+		return result;
+	}
+}

mercurial