1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QSET_H |
41 | #define QSET_H |
42 | |
43 | #include <QtCore/qhash.h> |
44 | #include <QtCore/qcontainertools_impl.h> |
45 | |
46 | #include <initializer_list> |
47 | #include <iterator> |
48 | |
49 | QT_BEGIN_NAMESPACE |
50 | |
51 | |
52 | template <class T> |
53 | class QSet |
54 | { |
55 | typedef QHash<T, QHashDummyValue> Hash; |
56 | |
57 | public: |
58 | inline QSet() noexcept {} |
59 | inline QSet(std::initializer_list<T> list) |
60 | : QSet(list.begin(), list.end()) {} |
61 | template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> |
62 | inline QSet(InputIterator first, InputIterator last) |
63 | { |
64 | QtPrivate::reserveIfForwardIterator(this, first, last); |
65 | for (; first != last; ++first) |
66 | insert(*first); |
67 | } |
68 | |
69 | // compiler-generated copy/move ctor/assignment operators are fine! |
70 | // compiler-generated destructor is fine! |
71 | |
72 | inline void swap(QSet<T> &other) noexcept { q_hash.swap(other.q_hash); } |
73 | |
74 | inline bool operator==(const QSet<T> &other) const |
75 | { return q_hash == other.q_hash; } |
76 | inline bool operator!=(const QSet<T> &other) const |
77 | { return q_hash != other.q_hash; } |
78 | |
79 | inline int size() const { return q_hash.size(); } |
80 | |
81 | inline bool isEmpty() const { return q_hash.isEmpty(); } |
82 | |
83 | inline int capacity() const { return q_hash.capacity(); } |
84 | inline void reserve(int size); |
85 | inline void squeeze() { q_hash.squeeze(); } |
86 | |
87 | inline void detach() { q_hash.detach(); } |
88 | inline bool isDetached() const { return q_hash.isDetached(); } |
89 | #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
90 | inline void setSharable(bool sharable) { q_hash.setSharable(sharable); } |
91 | #endif |
92 | |
93 | inline void clear() { q_hash.clear(); } |
94 | |
95 | inline bool remove(const T &value) { return q_hash.remove(value) != 0; } |
96 | |
97 | inline bool contains(const T &value) const { return q_hash.contains(value); } |
98 | |
99 | bool contains(const QSet<T> &set) const; |
100 | |
101 | class const_iterator; |
102 | |
103 | class iterator |
104 | { |
105 | typedef QHash<T, QHashDummyValue> Hash; |
106 | typename Hash::iterator i; |
107 | friend class const_iterator; |
108 | friend class QSet<T>; |
109 | |
110 | public: |
111 | #if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0) |
112 | typedef std::bidirectional_iterator_tag iterator_category; |
113 | #else |
114 | typedef std::forward_iterator_tag iterator_category; |
115 | #endif |
116 | typedef qptrdiff difference_type; |
117 | typedef T value_type; |
118 | typedef const T *pointer; |
119 | typedef const T &reference; |
120 | |
121 | inline iterator() {} |
122 | inline iterator(typename Hash::iterator o) : i(o) {} |
123 | inline iterator(const iterator &o) : i(o.i) {} |
124 | inline iterator &operator=(const iterator &o) { i = o.i; return *this; } |
125 | inline const T &operator*() const { return i.key(); } |
126 | inline const T *operator->() const { return &i.key(); } |
127 | inline bool operator==(const iterator &o) const { return i == o.i; } |
128 | inline bool operator!=(const iterator &o) const { return i != o.i; } |
129 | inline bool operator==(const const_iterator &o) const |
130 | { return i == o.i; } |
131 | inline bool operator!=(const const_iterator &o) const |
132 | { return i != o.i; } |
133 | inline iterator &operator++() { ++i; return *this; } |
134 | inline iterator operator++(int) { iterator r = *this; ++i; return r; } |
135 | #if QT_DEPRECATED_SINCE(5, 15) |
136 | inline QT_DEPRECATED_VERSION_5_15 iterator &operator--() { --i; return *this; } |
137 | inline QT_DEPRECATED_VERSION_5_15 iterator operator--(int) { iterator r = *this; --i; return r; } |
138 | inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j) const { return i + j; } |
139 | inline QT_DEPRECATED_VERSION_5_15 iterator operator-(int j) const { return i - j; } |
140 | friend inline QT_DEPRECATED_VERSION_5_15 iterator operator+(int j, iterator k) { return k + j; } |
141 | inline QT_DEPRECATED_VERSION_5_15 iterator &operator+=(int j) { i += j; return *this; } |
142 | inline QT_DEPRECATED_VERSION_5_15 iterator &operator-=(int j) { i -= j; return *this; } |
143 | #endif |
144 | }; |
145 | |
146 | class const_iterator |
147 | { |
148 | typedef QHash<T, QHashDummyValue> Hash; |
149 | typename Hash::const_iterator i; |
150 | friend class iterator; |
151 | friend class QSet<T>; |
152 | |
153 | public: |
154 | #if QT_DEPRECATED_WARNINGS_SINCE < QT_VERSION_CHECK(5, 15, 0) |
155 | typedef std::bidirectional_iterator_tag iterator_category; |
156 | #else |
157 | typedef std::forward_iterator_tag iterator_category; |
158 | #endif |
159 | typedef qptrdiff difference_type; |
160 | typedef T value_type; |
161 | typedef const T *pointer; |
162 | typedef const T &reference; |
163 | |
164 | inline const_iterator() {} |
165 | inline const_iterator(typename Hash::const_iterator o) : i(o) {} |
166 | inline const_iterator(const const_iterator &o) : i(o.i) {} |
167 | inline const_iterator(const iterator &o) |
168 | : i(o.i) {} |
169 | inline const_iterator &operator=(const const_iterator &o) { i = o.i; return *this; } |
170 | inline const T &operator*() const { return i.key(); } |
171 | inline const T *operator->() const { return &i.key(); } |
172 | inline bool operator==(const const_iterator &o) const { return i == o.i; } |
173 | inline bool operator!=(const const_iterator &o) const { return i != o.i; } |
174 | inline const_iterator &operator++() { ++i; return *this; } |
175 | inline const_iterator operator++(int) { const_iterator r = *this; ++i; return r; } |
176 | #if QT_DEPRECATED_SINCE(5, 15) |
177 | inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator--() { --i; return *this; } |
178 | inline QT_DEPRECATED_VERSION_5_15 const_iterator operator--(int) { const_iterator r = *this; --i; return r; } |
179 | inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j) const { return i + j; } |
180 | inline QT_DEPRECATED_VERSION_5_15 const_iterator operator-(int j) const { return i - j; } |
181 | friend inline QT_DEPRECATED_VERSION_5_15 const_iterator operator+(int j, const_iterator k) { return k + j; } |
182 | inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator+=(int j) { i += j; return *this; } |
183 | inline QT_DEPRECATED_VERSION_5_15 const_iterator &operator-=(int j) { i -= j; return *this; } |
184 | #endif |
185 | }; |
186 | |
187 | // STL style |
188 | inline iterator begin() { return q_hash.begin(); } |
189 | inline const_iterator begin() const noexcept { return q_hash.begin(); } |
190 | inline const_iterator cbegin() const noexcept { return q_hash.begin(); } |
191 | inline const_iterator constBegin() const noexcept { return q_hash.constBegin(); } |
192 | inline iterator end() { return q_hash.end(); } |
193 | inline const_iterator end() const noexcept { return q_hash.end(); } |
194 | inline const_iterator cend() const noexcept { return q_hash.end(); } |
195 | inline const_iterator constEnd() const noexcept { return q_hash.constEnd(); } |
196 | |
197 | #if QT_DEPRECATED_SINCE(5, 15) |
198 | typedef std::reverse_iterator<iterator> reverse_iterator; |
199 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; |
200 | |
201 | reverse_iterator QT_DEPRECATED_VERSION_5_15 rbegin() { return reverse_iterator(end()); } |
202 | reverse_iterator QT_DEPRECATED_VERSION_5_15 rend() { return reverse_iterator(begin()); } |
203 | const_reverse_iterator QT_DEPRECATED_VERSION_5_15 rbegin() const noexcept { return const_reverse_iterator(end()); } |
204 | const_reverse_iterator QT_DEPRECATED_VERSION_5_15 rend() const noexcept { return const_reverse_iterator(begin()); } |
205 | const_reverse_iterator QT_DEPRECATED_VERSION_5_15 crbegin() const noexcept { return const_reverse_iterator(end()); } |
206 | const_reverse_iterator QT_DEPRECATED_VERSION_5_15 crend() const noexcept { return const_reverse_iterator(begin()); } |
207 | #endif |
208 | |
209 | iterator erase(iterator i) |
210 | { return erase(m2c(i)); } |
211 | iterator erase(const_iterator i) |
212 | { |
213 | Q_ASSERT_X(isValidIterator(i), "QSet::erase" , "The specified const_iterator argument 'i' is invalid" ); |
214 | return q_hash.erase(reinterpret_cast<typename Hash::const_iterator &>(i)); |
215 | } |
216 | |
217 | // more Qt |
218 | typedef iterator Iterator; |
219 | typedef const_iterator ConstIterator; |
220 | inline int count() const { return q_hash.count(); } |
221 | inline iterator insert(const T &value) |
222 | { return static_cast<typename Hash::iterator>(q_hash.insert(value, QHashDummyValue())); } |
223 | iterator find(const T &value) { return q_hash.find(value); } |
224 | const_iterator find(const T &value) const { return q_hash.find(value); } |
225 | inline const_iterator constFind(const T &value) const { return find(value); } |
226 | QSet<T> &unite(const QSet<T> &other); |
227 | QSet<T> &intersect(const QSet<T> &other); |
228 | bool intersects(const QSet<T> &other) const; |
229 | QSet<T> &subtract(const QSet<T> &other); |
230 | |
231 | // STL compatibility |
232 | typedef T key_type; |
233 | typedef T value_type; |
234 | typedef value_type *pointer; |
235 | typedef const value_type *const_pointer; |
236 | typedef value_type &reference; |
237 | typedef const value_type &const_reference; |
238 | typedef qptrdiff difference_type; |
239 | typedef int size_type; |
240 | |
241 | inline bool empty() const { return isEmpty(); } |
242 | // comfort |
243 | inline QSet<T> &operator<<(const T &value) { insert(value); return *this; } |
244 | inline QSet<T> &operator|=(const QSet<T> &other) { unite(other); return *this; } |
245 | inline QSet<T> &operator|=(const T &value) { insert(value); return *this; } |
246 | inline QSet<T> &operator&=(const QSet<T> &other) { intersect(other); return *this; } |
247 | inline QSet<T> &operator&=(const T &value) |
248 | { QSet<T> result; if (contains(value)) result.insert(value); return (*this = result); } |
249 | inline QSet<T> &operator+=(const QSet<T> &other) { unite(other); return *this; } |
250 | inline QSet<T> &operator+=(const T &value) { insert(value); return *this; } |
251 | inline QSet<T> &operator-=(const QSet<T> &other) { subtract(other); return *this; } |
252 | inline QSet<T> &operator-=(const T &value) { remove(value); return *this; } |
253 | inline QSet<T> operator|(const QSet<T> &other) const |
254 | { QSet<T> result = *this; result |= other; return result; } |
255 | inline QSet<T> operator&(const QSet<T> &other) const |
256 | { QSet<T> result = *this; result &= other; return result; } |
257 | inline QSet<T> operator+(const QSet<T> &other) const |
258 | { QSet<T> result = *this; result += other; return result; } |
259 | inline QSet<T> operator-(const QSet<T> &other) const |
260 | { QSet<T> result = *this; result -= other; return result; } |
261 | |
262 | QList<T> values() const; |
263 | #if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0) |
264 | QT_DEPRECATED_X("Use values() instead." ) |
265 | QList<T> toList() const { return values(); } |
266 | QT_DEPRECATED_X("Use QSet<T>(list.begin(), list.end()) instead." ) |
267 | static QSet<T> fromList(const QList<T> &list); |
268 | #endif |
269 | |
270 | private: |
271 | Hash q_hash; |
272 | |
273 | static const_iterator m2c(iterator it) noexcept |
274 | { return const_iterator(typename Hash::const_iterator(it.i.i)); } |
275 | |
276 | bool isValidIterator(const iterator &i) const |
277 | { |
278 | return q_hash.isValidIterator(reinterpret_cast<const typename Hash::iterator&>(i)); |
279 | } |
280 | bool isValidIterator(const const_iterator &i) const noexcept |
281 | { |
282 | return q_hash.isValidIterator(reinterpret_cast<const typename Hash::const_iterator&>(i)); |
283 | } |
284 | }; |
285 | |
286 | #if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606 |
287 | template <typename InputIterator, |
288 | typename ValueType = typename std::iterator_traits<InputIterator>::value_type, |
289 | QtPrivate::IfIsInputIterator<InputIterator> = true> |
290 | QSet(InputIterator, InputIterator) -> QSet<ValueType>; |
291 | #endif |
292 | |
293 | template <typename T> |
294 | uint qHash(const QSet<T> &key, uint seed = 0) |
295 | noexcept(noexcept(qHashRangeCommutative(key.begin(), key.end(), seed))) |
296 | { |
297 | return qHashRangeCommutative(key.begin(), key.end(), seed); |
298 | } |
299 | |
300 | // inline function implementations |
301 | |
302 | template <class T> |
303 | Q_INLINE_TEMPLATE void QSet<T>::reserve(int asize) { q_hash.reserve(asize); } |
304 | |
305 | template <class T> |
306 | Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other) |
307 | { |
308 | if (!q_hash.isSharedWith(other.q_hash)) { |
309 | for (const T &e : other) |
310 | insert(e); |
311 | } |
312 | return *this; |
313 | } |
314 | |
315 | template <class T> |
316 | Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other) |
317 | { |
318 | QSet<T> copy1; |
319 | QSet<T> copy2; |
320 | if (size() <= other.size()) { |
321 | copy1 = *this; |
322 | copy2 = other; |
323 | } else { |
324 | copy1 = other; |
325 | copy2 = *this; |
326 | *this = copy1; |
327 | } |
328 | for (const auto &e : qAsConst(copy1)) { |
329 | if (!copy2.contains(e)) |
330 | remove(e); |
331 | } |
332 | return *this; |
333 | } |
334 | |
335 | template <class T> |
336 | Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const |
337 | { |
338 | const bool otherIsBigger = other.size() > size(); |
339 | const QSet &smallestSet = otherIsBigger ? *this : other; |
340 | const QSet &biggestSet = otherIsBigger ? other : *this; |
341 | const bool equalSeeds = q_hash.d->seed == other.q_hash.d->seed; |
342 | typename QSet::const_iterator i = smallestSet.cbegin(); |
343 | typename QSet::const_iterator e = smallestSet.cend(); |
344 | |
345 | if (Q_LIKELY(equalSeeds)) { |
346 | // If seeds are equal we take the fast path so no hash is recalculated. |
347 | while (i != e) { |
348 | if (*biggestSet.q_hash.findNode(*i, i.i.i->h) != biggestSet.q_hash.e) |
349 | return true; |
350 | ++i; |
351 | } |
352 | } else { |
353 | while (i != e) { |
354 | if (biggestSet.contains(*i)) |
355 | return true; |
356 | ++i; |
357 | } |
358 | } |
359 | |
360 | return false; |
361 | } |
362 | |
363 | template <class T> |
364 | Q_INLINE_TEMPLATE QSet<T> &QSet<T>::subtract(const QSet<T> &other) |
365 | { |
366 | if (q_hash.isSharedWith(other.q_hash)) { |
367 | clear(); |
368 | } else { |
369 | for (const auto &e : other) |
370 | remove(e); |
371 | } |
372 | return *this; |
373 | } |
374 | |
375 | template <class T> |
376 | Q_INLINE_TEMPLATE bool QSet<T>::contains(const QSet<T> &other) const |
377 | { |
378 | typename QSet<T>::const_iterator i = other.constBegin(); |
379 | while (i != other.constEnd()) { |
380 | if (!contains(*i)) |
381 | return false; |
382 | ++i; |
383 | } |
384 | return true; |
385 | } |
386 | |
387 | template <typename T> |
388 | Q_OUTOFLINE_TEMPLATE QList<T> QSet<T>::values() const |
389 | { |
390 | QList<T> result; |
391 | result.reserve(size()); |
392 | typename QSet<T>::const_iterator i = constBegin(); |
393 | while (i != constEnd()) { |
394 | result.append(*i); |
395 | ++i; |
396 | } |
397 | return result; |
398 | } |
399 | |
400 | #if QT_DEPRECATED_SINCE(5, 14) && QT_VERSION < QT_VERSION_CHECK(6,0,0) |
401 | |
402 | QT_WARNING_PUSH |
403 | QT_WARNING_DISABLE_DEPRECATED |
404 | |
405 | template <typename T> |
406 | Q_OUTOFLINE_TEMPLATE QSet<T> QList<T>::toSet() const |
407 | { |
408 | QSet<T> result; |
409 | result.reserve(size()); |
410 | for (int i = 0; i < size(); ++i) |
411 | result.insert(at(i)); |
412 | return result; |
413 | } |
414 | |
415 | template <typename T> |
416 | QSet<T> QSet<T>::fromList(const QList<T> &list) |
417 | { |
418 | return list.toSet(); |
419 | } |
420 | |
421 | template <typename T> |
422 | QList<T> QList<T>::fromSet(const QSet<T> &set) |
423 | { |
424 | return set.toList(); |
425 | } |
426 | |
427 | QT_WARNING_POP |
428 | |
429 | #endif |
430 | |
431 | Q_DECLARE_SEQUENTIAL_ITERATOR(Set) |
432 | |
433 | #if !defined(QT_NO_JAVA_STYLE_ITERATORS) |
434 | template <typename T> |
435 | class QMutableSetIterator |
436 | { |
437 | typedef typename QSet<T>::iterator iterator; |
438 | QSet<T> *c; |
439 | iterator i, n; |
440 | inline bool item_exists() const { return c->constEnd() != n; } |
441 | |
442 | public: |
443 | inline QMutableSetIterator(QSet<T> &container) |
444 | : c(&container) |
445 | { i = c->begin(); n = c->end(); } |
446 | inline QMutableSetIterator &operator=(QSet<T> &container) |
447 | { c = &container; i = c->begin(); n = c->end(); return *this; } |
448 | inline void toFront() { i = c->begin(); n = c->end(); } |
449 | inline void toBack() { i = c->end(); n = i; } |
450 | inline bool hasNext() const { return c->constEnd() != i; } |
451 | inline const T &next() { n = i++; return *n; } |
452 | inline const T &peekNext() const { return *i; } |
453 | inline void remove() |
454 | { if (c->constEnd() != n) { i = c->erase(n); n = c->end(); } } |
455 | inline const T &value() const { Q_ASSERT(item_exists()); return *n; } |
456 | inline bool findNext(const T &t) |
457 | { while (c->constEnd() != (n = i)) if (*i++ == t) return true; return false; } |
458 | #if QT_DEPRECATED_SINCE(5, 15) |
459 | inline QT_DEPRECATED_VERSION_5_15 bool hasPrevious() const { return c->constBegin() != i; } |
460 | inline QT_DEPRECATED_VERSION_5_15 const T &previous() { n = --i; return *n; } |
461 | inline QT_DEPRECATED_VERSION_5_15 const T &peekPrevious() const { iterator p = i; return *--p; } |
462 | inline QT_DEPRECATED_VERSION_5_15 bool findPrevious(const T &t) |
463 | { while (c->constBegin() != i) if (*(n = --i) == t) return true; |
464 | n = c->end(); return false; } |
465 | #endif |
466 | }; |
467 | #endif // QT_NO_JAVA_STYLE_ITERATORS |
468 | |
469 | QT_END_NAMESPACE |
470 | |
471 | #endif // QSET_H |
472 | |