omg functional programming

Fri, 28 Feb 2020 19:24:33 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Fri, 28 Feb 2020 19:24:33 +0200
changeset 63
f7dd937667a5
parent 62
3e92760fe00a
child 64
f99d52b1646b

omg functional programming

CMakeLists.txt file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/functional.h file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Thu Feb 27 23:07:40 2020 +0200
+++ b/CMakeLists.txt	Fri Feb 28 19:24:33 2020 +0200
@@ -59,6 +59,7 @@
 	src/colors.h
 	src/document.h
 	src/documentmanager.h
+	src/functional.h
 	src/geometry.h
 	src/header.h
 	src/invert.h
--- a/src/document.cpp	Thu Feb 27 23:07:40 2020 +0200
+++ b/src/document.cpp	Fri Feb 28 19:24:33 2020 +0200
@@ -58,17 +58,12 @@
 	connect(this->ui.listView->selectionModel(), &QItemSelectionModel::selectionChanged,
 		[&](const QItemSelection& selected, const QItemSelection& deselected)
 	{
-		QSet<ldraw::Id> selectedIds;
-		QSet<ldraw::Id> deselectedIds;
-		for (const QModelIndex& index : selected.indexes())
+		auto resolveIndex = [this](const QModelIndex& index){ return this->model->resolve(index); };
+		auto resolve = [resolveIndex](const QItemSelection& selection)
 		{
-			selectedIds.insert(this->model->resolve(index));
-		}
-		for (const QModelIndex& index : deselected.indexes())
-		{
-			deselectedIds.insert(this->model->resolve(index));
-		}
-		this->renderer->handleSelectionChange(selectedIds, deselectedIds);
+			return fn::map<QSet<ldraw::Id>>(selection.indexes(), resolveIndex);
+		};
+		this->renderer->handleSelectionChange(resolve(selected), resolve(deselected));
 	});
 }
 
--- /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;
+	}
+}
--- a/src/main.h	Thu Feb 27 23:07:40 2020 +0200
+++ b/src/main.h	Fri Feb 28 19:24:33 2020 +0200
@@ -25,6 +25,7 @@
 #include "utility.h"
 #include "maths.h"
 #include "geometry.h"
+#include "functional.h"
 
 namespace settingGroups
 {

mercurial