src/functional.h

Sun, 25 Jul 2021 16:29:08 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Sun, 25 Jul 2021 16:29:08 +0300
changeset 110
d922431eacf7
parent 106
128efb9d148b
child 123
e3fe3617b631
permissions
-rw-r--r--

stuff

/*
 *  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;
	}
}

template<typename T, typename Fn>
bool any(T&& container, Fn&& f)
{
	for (auto&& x : container)
	{
		if (f(x))
		{
			return true;
		}
	}
	return false;
}

template<typename T, typename Fn>
bool all(T&& container, Fn&& f)
{
	for (auto&& x : container)
	{
		if (not f(x))
		{
			return false;
		}
	}
	return true;
}

mercurial