src/functional.h

changeset 299
cf9a854b56a9
parent 298
9ca53009bc5c
child 300
3a4b132b8353
equal deleted inserted replaced
298:9ca53009bc5c 299:cf9a854b56a9
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2020 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #pragma once
20 #include <algorithm>
21 #include <functional>
22 #include <QVector>
23 #include <QSet>
24 #include <QList>
25
26 namespace fn
27 {
28 template<typename C>
29 class InsertIterator;
30 }
31
32 /**
33 * Like std::back_inserter but calls x.insert(v) instead
34 */
35 template<typename C>
36 class fn::InsertIterator
37 {
38 public:
39 InsertIterator(C& container) :
40 container{container} {}
41 auto operator*()
42 {
43 return *this;
44 }
45 auto operator++()
46 {
47 return *this;
48 }
49 auto operator++(int)
50 {
51 return *this;
52 }
53 template<typename T>
54 auto operator=(T&& value)
55 {
56 this->container.insert(std::forward<T>(value));
57 return *this;
58 }
59 private:
60 C& container;
61 };
62
63 namespace fn
64 {
65 // Constructs a fn::InsertIterator
66 template<typename C>
67 InsertIterator<C> makeInsertIterator(C& container)
68 {
69 return InsertIterator<C>{container};
70 }
71
72 // Constructs a back_inserter for std::vector
73 template<typename T>
74 auto makeDefaultInserter(std::vector<T>& vec)
75 {
76 return std::back_inserter(vec);
77 }
78
79 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
80 // In Qt6 QVector is now a QList instead, so we need to disable this
81 // Constructs a back_inserter for QVector
82 template<typename T>
83 auto makeDefaultInserter(QVector<T>& vec)
84 {
85 return std::back_inserter(vec);
86 }
87 #endif
88
89 template<typename T>
90 auto makeDefaultInserter(QList<T>& vec)
91 {
92 return std::back_inserter(vec);
93 }
94
95 // Constructs an fn::InsertIterator for QSet
96 template<typename T>
97 auto makeDefaultInserter(QSet<T>& vec)
98 {
99 return InsertIterator(vec);
100 }
101
102 // Changes the value type of C
103 template<typename C, typename TT>
104 struct ChangeContainerValueType
105 {
106 };
107
108 // Changes the value type of std::vector
109 template<typename T, typename TT>
110 struct ChangeContainerValueType<std::vector<T>, TT>
111 {
112 using type = std::vector<TT>;
113 };
114
115 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
116 // Changes the value type of QVector
117 template<typename T, typename TT>
118 struct ChangeContainerValueType<QVector<T>, TT>
119 {
120 using type = QVector<TT>;
121 };
122 #endif
123
124 // Changes the value type of QSet
125 template<typename T, typename TT>
126 struct ChangeContainerValueType<QSet<T>, TT>
127 {
128 using type = QSet<TT>;
129 };
130
131 // Changes the value type of QList
132 template<typename T, typename TT>
133 struct ChangeContainerValueType<QList<T>, TT>
134 {
135 using type = QList<TT>;
136 };
137
138 // Changes the value type of C
139 template<typename C, typename TT>
140 using ChangeContainerValueType_t = typename ChangeContainerValueType<C, TT>::type;
141
142 /**
143 * \brief Applies \c function to all elements of \c container
144 * \param container Container to iterate
145 * \param function Function to apply
146 * \param Rt result type. If not provided, a suitable result type is deduced from inputs
147 * \returns mapped result container
148 */
149 template<typename Rt = void, typename C, typename Fn>
150 auto map(C&& container, Fn&& function)
151 {
152 using value_t = decltype(*std::declval<C>().begin());
153 using newvalue_t = std::result_of_t<Fn(value_t)>;
154 using result_t = std::conditional_t<
155 std::is_same_v<Rt, void>,
156 ChangeContainerValueType_t<std::remove_reference_t<C>, newvalue_t>,
157 Rt>;
158 result_t result;
159 result.reserve(std::end(container) - std::begin(container));
160 std::transform(std::begin(container), std::end(container), makeDefaultInserter(result), function);
161 return result;
162 }
163 }
164
165 template<typename T, typename Fn>
166 bool any(T&& container, Fn&& f)
167 {
168 for (auto&& x : container)
169 {
170 if (f(x))
171 {
172 return true;
173 }
174 }
175 return false;
176 }
177
178
179 template<typename T, typename Fn>
180 bool all(T&& container, Fn&& f)
181 {
182 for (auto&& x : container)
183 {
184 if (not f(x))
185 {
186 return false;
187 }
188 }
189 return true;
190 }

mercurial