Wed, 22 Sep 2021 13:28:53 +0300
Document model.h
/* * 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; }