1 | /* |
2 | |
3 | SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> |
4 | SPDX-FileContributor: Stephen Kelly <stephen@kdab.com> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #ifndef KBIHASH_P_H |
10 | #define KBIHASH_P_H |
11 | |
12 | #include <QHash> |
13 | #include <QMap> |
14 | |
15 | #include <QDebug> |
16 | |
17 | template<typename LeftContainer, typename RightContainer> |
18 | class KBiAssociativeContainer; |
19 | |
20 | template<typename LeftContainer, typename RightContainer> |
21 | QDebug operator<<(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container); |
22 | |
23 | template<typename LeftContainer, typename RightContainer> |
24 | QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container); |
25 | |
26 | template<typename LeftContainer, typename RightContainer> |
27 | QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &container); |
28 | |
29 | template<typename LeftContainer, typename RightContainer> |
30 | class KBiAssociativeContainer |
31 | { |
32 | // We need to convert from a QHash::iterator or QMap::iterator |
33 | // to a KBiAssociativeContainer::iterator (left or right) |
34 | // Do do that we use this implicit ctor. We partially specialize |
35 | // it for QHash and QMap types. |
36 | // Our iterator inherits from this struct to get the implicit ctor, |
37 | // and this struct must inherit from the QHash or QMap iterator. |
38 | template<typename Container, typename T, typename U> |
39 | struct _iterator_impl_ctor : public Container::iterator { |
40 | _iterator_impl_ctor(typename Container::iterator it); |
41 | }; |
42 | |
43 | template<typename T, typename U> |
44 | struct _iterator_impl_ctor<QHash<T, U>, T, U> : public QHash<T, U>::iterator { |
45 | /* implicit */ _iterator_impl_ctor(const typename QHash<T, U>::iterator it) |
46 | : QHash<T, U>::iterator(it) |
47 | { |
48 | } |
49 | }; |
50 | |
51 | template<typename T, typename U> |
52 | struct _iterator_impl_ctor<QMap<T, U>, T, U> : public QMap<T, U>::iterator { |
53 | /* implicit */ _iterator_impl_ctor(const typename QMap<T, U>::iterator it) |
54 | : QMap<T, U>::iterator(it) |
55 | { |
56 | } |
57 | }; |
58 | |
59 | public: |
60 | typedef typename RightContainer::mapped_type left_type; |
61 | typedef typename LeftContainer::mapped_type right_type; |
62 | |
63 | template<typename Container> |
64 | class _iterator : public _iterator_impl_ctor<Container, typename Container::key_type, typename Container::mapped_type> |
65 | { |
66 | public: |
67 | explicit inline _iterator(void *data) |
68 | : Container::iterator(data) |
69 | { |
70 | } |
71 | |
72 | /* implicit */ _iterator(const typename Container::iterator it) |
73 | : _iterator_impl_ctor<Container, typename Container::key_type, typename Container::mapped_type>(it) |
74 | { |
75 | } |
76 | |
77 | inline const typename Container::mapped_type &value() const |
78 | { |
79 | return Container::iterator::value(); |
80 | } |
81 | inline const typename Container::mapped_type &operator*() const |
82 | { |
83 | return Container::iterator::operator*(); |
84 | } |
85 | inline const typename Container::mapped_type *operator->() const |
86 | { |
87 | return Container::iterator::operator->(); |
88 | } |
89 | |
90 | private: |
91 | #ifndef Q_CC_MSVC |
92 | using Container::iterator::operator*; |
93 | using Container::iterator::operator->; |
94 | using Container::iterator::value; |
95 | #endif |
96 | }; |
97 | |
98 | typedef _iterator<LeftContainer> left_iterator; |
99 | typedef typename LeftContainer::const_iterator left_const_iterator; |
100 | typedef _iterator<RightContainer> right_iterator; |
101 | typedef typename RightContainer::const_iterator right_const_iterator; |
102 | |
103 | inline KBiAssociativeContainer() |
104 | { |
105 | } |
106 | inline KBiAssociativeContainer(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
107 | { |
108 | *this = other; |
109 | } |
110 | |
111 | const KBiAssociativeContainer<LeftContainer, RightContainer> &operator=(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
112 | { |
113 | _leftToRight = other._leftToRight; |
114 | _rightToLeft = other._rightToLeft; |
115 | return *this; |
116 | } |
117 | |
118 | inline bool removeLeft(left_type t) |
119 | { |
120 | const right_type u = _leftToRight.take(t); |
121 | return _rightToLeft.remove(u) != 0; |
122 | } |
123 | |
124 | inline bool removeRight(right_type u) |
125 | { |
126 | const left_type t = _rightToLeft.take(u); |
127 | return _leftToRight.remove(t) != 0; |
128 | } |
129 | |
130 | inline right_type takeLeft(left_type t) |
131 | { |
132 | const right_type u = _leftToRight.take(t); |
133 | _rightToLeft.remove(u); |
134 | return u; |
135 | } |
136 | |
137 | inline left_type takeRight(right_type u) |
138 | { |
139 | const left_type t = _rightToLeft.take(u); |
140 | _leftToRight.remove(t); |
141 | return t; |
142 | } |
143 | |
144 | inline left_type rightToLeft(right_type u) const |
145 | { |
146 | return _rightToLeft.value(u); |
147 | } |
148 | |
149 | inline right_type leftToRight(left_type t) const |
150 | { |
151 | return _leftToRight.value(t); |
152 | } |
153 | |
154 | inline bool leftContains(left_type t) const |
155 | { |
156 | return _leftToRight.contains(t); |
157 | } |
158 | |
159 | inline bool rightContains(right_type u) const |
160 | { |
161 | return _rightToLeft.contains(u); |
162 | } |
163 | |
164 | inline int size() const |
165 | { |
166 | return _leftToRight.size(); |
167 | } |
168 | |
169 | inline int count() const |
170 | { |
171 | return _leftToRight.count(); |
172 | } |
173 | |
174 | inline int capacity() const |
175 | { |
176 | return _leftToRight.capacity(); |
177 | } |
178 | |
179 | void reserve(int size) |
180 | { |
181 | _leftToRight.reserve(size); |
182 | _rightToLeft.reserve(size); |
183 | } |
184 | |
185 | inline void squeeze() |
186 | { |
187 | _leftToRight.squeeze(); |
188 | _rightToLeft.squeeze(); |
189 | } |
190 | |
191 | inline void detach() |
192 | { |
193 | _leftToRight.detach(); |
194 | _rightToLeft.detach(); |
195 | } |
196 | |
197 | inline bool isDetached() const |
198 | { |
199 | return _leftToRight.isDetached(); |
200 | } |
201 | |
202 | inline void setSharable(bool sharable) |
203 | { |
204 | _leftToRight.setSharable(sharable); |
205 | _rightToLeft.setSharable(sharable); |
206 | } |
207 | |
208 | inline bool isSharedWith(const KBiAssociativeContainer<RightContainer, LeftContainer> &other) const |
209 | { |
210 | return _leftToRight.isSharedWith(other._leftToRight) && _rightToLeft.isSharedWith(other._leftToRight); |
211 | } |
212 | |
213 | void clear() |
214 | { |
215 | _leftToRight.clear(); |
216 | _rightToLeft.clear(); |
217 | } |
218 | |
219 | QList<left_type> leftValues() const |
220 | { |
221 | return _leftToRight.keys(); |
222 | } |
223 | |
224 | QList<right_type> rightValues() const |
225 | { |
226 | return _rightToLeft.keys(); |
227 | } |
228 | |
229 | right_iterator eraseRight(right_iterator it) |
230 | { |
231 | Q_ASSERT(it != rightEnd()); |
232 | _leftToRight.remove(it.value()); |
233 | return _rightToLeft.erase(it); |
234 | } |
235 | |
236 | left_iterator eraseLeft(left_iterator it) |
237 | { |
238 | Q_ASSERT(it != leftEnd()); |
239 | _rightToLeft.remove(it.value()); |
240 | return _leftToRight.erase(it); |
241 | } |
242 | |
243 | left_iterator findLeft(left_type t) |
244 | { |
245 | return _leftToRight.find(t); |
246 | } |
247 | |
248 | left_const_iterator findLeft(left_type t) const |
249 | { |
250 | return _leftToRight.find(t); |
251 | } |
252 | |
253 | left_const_iterator constFindLeft(left_type t) const |
254 | { |
255 | return _leftToRight.constFind(t); |
256 | } |
257 | |
258 | right_iterator findRight(right_type u) |
259 | { |
260 | return _rightToLeft.find(u); |
261 | } |
262 | |
263 | right_const_iterator findRight(right_type u) const |
264 | { |
265 | return _rightToLeft.find(u); |
266 | } |
267 | |
268 | right_const_iterator constFindRight(right_type u) const |
269 | { |
270 | return _rightToLeft.find(u); |
271 | } |
272 | |
273 | left_iterator insert(left_type t, right_type u) |
274 | { |
275 | // biHash.insert(5, 7); // creates 5->7 in _leftToRight and 7->5 in _rightToLeft |
276 | // biHash.insert(5, 9); // replaces 5->7 with 5->9 in _leftToRight and inserts 9->5 in _rightToLeft. |
277 | // The 7->5 in _rightToLeft would be dangling, so we remove it before insertion. |
278 | |
279 | // This means we need to hash u and t up to twice each. Could probably be done better using QHashNode. |
280 | |
281 | if (_leftToRight.contains(t)) { |
282 | _rightToLeft.remove(_leftToRight.take(t)); |
283 | } |
284 | if (_rightToLeft.contains(u)) { |
285 | _leftToRight.remove(_rightToLeft.take(u)); |
286 | } |
287 | |
288 | _rightToLeft.insert(u, t); |
289 | return _leftToRight.insert(t, u); |
290 | } |
291 | |
292 | KBiAssociativeContainer<LeftContainer, RightContainer> &intersect(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
293 | { |
294 | typename KBiAssociativeContainer<RightContainer, LeftContainer>::left_iterator it = leftBegin(); |
295 | while (it != leftEnd()) { |
296 | if (!other.leftContains(it.key())) { |
297 | it = eraseLeft(it); |
298 | } else { |
299 | ++it; |
300 | } |
301 | } |
302 | return *this; |
303 | } |
304 | |
305 | KBiAssociativeContainer<LeftContainer, RightContainer> &subtract(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
306 | { |
307 | typename KBiAssociativeContainer<RightContainer, LeftContainer>::left_iterator it = leftBegin(); |
308 | while (it != leftEnd()) { |
309 | if (other._leftToRight.contains(it.key())) { |
310 | it = eraseLeft(it); |
311 | } else { |
312 | ++it; |
313 | } |
314 | } |
315 | return *this; |
316 | } |
317 | |
318 | KBiAssociativeContainer<LeftContainer, RightContainer> &unite(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
319 | { |
320 | typename LeftContainer::const_iterator it = other._leftToRight.constBegin(); |
321 | const typename LeftContainer::const_iterator end = other._leftToRight.constEnd(); |
322 | while (it != end) { |
323 | const left_type key = it.key(); |
324 | if (!_leftToRight.contains(key)) { |
325 | insert(t: key, u: it.value()); |
326 | } |
327 | ++it; |
328 | } |
329 | return *this; |
330 | } |
331 | |
332 | void updateRight(left_iterator it, right_type u) |
333 | { |
334 | Q_ASSERT(it != leftEnd()); |
335 | const left_type key = it.key(); |
336 | _rightToLeft.remove(_leftToRight.value(key)); |
337 | _leftToRight[key] = u; |
338 | _rightToLeft[u] = key; |
339 | } |
340 | |
341 | void updateLeft(right_iterator it, left_type t) |
342 | { |
343 | Q_ASSERT(it != rightEnd()); |
344 | const right_type key = it.key(); |
345 | _leftToRight.remove(_rightToLeft.value(key)); |
346 | _rightToLeft[key] = t; |
347 | _leftToRight[t] = key; |
348 | } |
349 | |
350 | inline bool isEmpty() const |
351 | { |
352 | return _leftToRight.isEmpty(); |
353 | } |
354 | |
355 | const right_type operator[](const left_type &t) const |
356 | { |
357 | return _leftToRight.operator[](t); |
358 | } |
359 | |
360 | bool operator==(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
361 | { |
362 | return _leftToRight.operator==(other._leftToRight); |
363 | } |
364 | |
365 | bool operator!=(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
366 | { |
367 | return _leftToRight.operator!=(other._leftToRight); |
368 | } |
369 | |
370 | left_iterator toLeftIterator(right_iterator it) const |
371 | { |
372 | Q_ASSERT(it != rightEnd()); |
373 | return _leftToRight.find(it.value()); |
374 | } |
375 | |
376 | right_iterator toRightIterator(left_iterator it) const |
377 | { |
378 | Q_ASSERT(it != leftEnd()); |
379 | return _rightToLeft.find(it.value()); |
380 | } |
381 | |
382 | inline left_iterator leftBegin() |
383 | { |
384 | return _leftToRight.begin(); |
385 | } |
386 | |
387 | inline left_iterator leftEnd() |
388 | { |
389 | return _leftToRight.end(); |
390 | } |
391 | |
392 | inline left_const_iterator leftBegin() const |
393 | { |
394 | return _leftToRight.begin(); |
395 | } |
396 | |
397 | inline left_const_iterator leftEnd() const |
398 | { |
399 | return _leftToRight.end(); |
400 | } |
401 | |
402 | inline left_const_iterator leftConstBegin() const |
403 | { |
404 | return _leftToRight.constBegin(); |
405 | } |
406 | |
407 | inline left_const_iterator leftConstEnd() const |
408 | { |
409 | return _leftToRight.constEnd(); |
410 | } |
411 | |
412 | inline right_iterator rightBegin() |
413 | { |
414 | return _rightToLeft.begin(); |
415 | } |
416 | |
417 | inline right_iterator rightEnd() |
418 | { |
419 | return _rightToLeft.end(); |
420 | } |
421 | |
422 | inline right_const_iterator rightBegin() const |
423 | { |
424 | return _rightToLeft.begin(); |
425 | } |
426 | |
427 | inline right_const_iterator rightEnd() const |
428 | { |
429 | return _rightToLeft.end(); |
430 | } |
431 | inline right_const_iterator rightConstBegin() const |
432 | { |
433 | return _rightToLeft.constBegin(); |
434 | } |
435 | |
436 | inline right_const_iterator rightConstEnd() const |
437 | { |
438 | return _rightToLeft.constEnd(); |
439 | } |
440 | |
441 | static KBiAssociativeContainer<LeftContainer, RightContainer> fromHash(const QHash<left_type, right_type> &hash) |
442 | { |
443 | KBiAssociativeContainer<LeftContainer, RightContainer> container; |
444 | typename QHash<left_type, right_type>::const_iterator it = hash.constBegin(); |
445 | const typename QHash<left_type, right_type>::const_iterator end = hash.constEnd(); |
446 | for (; it != end; ++it) { |
447 | container.insert(it.key(), it.value()); |
448 | } |
449 | return container; |
450 | } |
451 | |
452 | static KBiAssociativeContainer<LeftContainer, RightContainer> fromMap(const QMap<left_type, right_type> &hash) |
453 | { |
454 | KBiAssociativeContainer<LeftContainer, RightContainer> container; |
455 | typename QMap<left_type, right_type>::const_iterator it = hash.constBegin(); |
456 | const typename QMap<left_type, right_type>::const_iterator end = hash.constEnd(); |
457 | for (; it != end; ++it) { |
458 | container.insert(it.key(), it.value()); |
459 | } |
460 | return container; |
461 | } |
462 | |
463 | friend QDataStream &operator<<<LeftContainer, RightContainer>(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &bihash); |
464 | friend QDataStream &operator>><LeftContainer, RightContainer>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &biHash); |
465 | friend QDebug operator<<<LeftContainer, RightContainer>(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &biHash); |
466 | |
467 | protected: |
468 | LeftContainer _leftToRight; |
469 | RightContainer _rightToLeft; |
470 | }; |
471 | |
472 | template<typename LeftContainer, typename RightContainer> |
473 | QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container) |
474 | { |
475 | return out << container._leftToRight; |
476 | } |
477 | |
478 | template<typename LeftContainer, typename RightContainer> |
479 | QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &container) |
480 | { |
481 | LeftContainer leftToRight; |
482 | in >> leftToRight; |
483 | typename LeftContainer::const_iterator it = leftToRight.constBegin(); |
484 | const typename LeftContainer::const_iterator end = leftToRight.constEnd(); |
485 | for (; it != end; ++it) { |
486 | container.insert(it.key(), it.value()); |
487 | } |
488 | |
489 | return in; |
490 | } |
491 | |
492 | template<typename Container, typename T, typename U> |
493 | struct _containerType { |
494 | operator const char *(); |
495 | }; |
496 | |
497 | template<typename T, typename U> |
498 | struct _containerType<QHash<T, U>, T, U> { |
499 | operator const char *() |
500 | { |
501 | return "QHash" ; |
502 | } |
503 | }; |
504 | |
505 | template<typename T, typename U> |
506 | struct _containerType<QMap<T, U>, T, U> { |
507 | operator const char *() |
508 | { |
509 | return "QMap" ; |
510 | } |
511 | }; |
512 | |
513 | template<typename Container> |
514 | static const char *containerType() |
515 | { |
516 | return _containerType<Container, typename Container::key_type, typename Container::mapped_type>(); |
517 | } |
518 | |
519 | template<typename LeftContainer, typename RightContainer> |
520 | QDebug operator<<(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container) |
521 | { |
522 | typename KBiAssociativeContainer<LeftContainer, RightContainer>::left_const_iterator it = container.leftConstBegin(); |
523 | |
524 | const typename KBiAssociativeContainer<LeftContainer, RightContainer>::left_const_iterator end = container.leftConstEnd(); |
525 | out.nospace() << "KBiAssociativeContainer<" << containerType<LeftContainer>() << ", " << containerType<RightContainer>() << ">" |
526 | << "(" ; |
527 | for (; it != end; ++it) { |
528 | out << "(" << it.key() << " <=> " << it.value() << ") " ; |
529 | } |
530 | |
531 | out << ")" ; |
532 | return out; |
533 | } |
534 | |
535 | /** |
536 | * @brief KBiHash provides a bi-directional hash container |
537 | * |
538 | * @note This class is designed to make mapping easier in proxy model implementations. |
539 | * |
540 | * @todo Figure out whether to discard this and use boost::bimap instead, submit it Qt or keep it here and make more direct use of QHashNode. |
541 | */ |
542 | template<typename T, typename U> |
543 | struct KBiHash : public KBiAssociativeContainer<QHash<T, U>, QHash<U, T>> { |
544 | KBiHash() |
545 | : KBiAssociativeContainer<QHash<T, U>, QHash<U, T>>() |
546 | { |
547 | } |
548 | |
549 | KBiHash(const KBiAssociativeContainer<QHash<T, U>, QHash<U, T>> &container) |
550 | : KBiAssociativeContainer<QHash<T, U>, QHash<U, T>>(container) |
551 | { |
552 | } |
553 | }; |
554 | |
555 | template<typename T, typename U> |
556 | QDebug operator<<(QDebug out, const KBiHash<T, U> &biHash) |
557 | { |
558 | typename KBiHash<T, U>::left_const_iterator it = biHash.leftConstBegin(); |
559 | |
560 | const typename KBiHash<T, U>::left_const_iterator end = biHash.leftConstEnd(); |
561 | out.nospace() << "KBiHash(" ; |
562 | for (; it != end; ++it) { |
563 | out << "(" << it.key() << " <=> " << it.value() << ") " ; |
564 | } |
565 | |
566 | out << ")" ; |
567 | return out; |
568 | } |
569 | |
570 | template<typename T, typename U> |
571 | struct KHash2Map : public KBiAssociativeContainer<QHash<T, U>, QMap<U, T>> { |
572 | KHash2Map() |
573 | : KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>() |
574 | { |
575 | } |
576 | |
577 | KHash2Map(const KBiAssociativeContainer<QHash<T, U>, QMap<U, T>> &container) |
578 | : KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>(container) |
579 | { |
580 | } |
581 | |
582 | typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>::right_iterator rightLowerBound(const U &key) |
583 | { |
584 | return this->_rightToLeft.lowerBound(key); |
585 | } |
586 | |
587 | typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>::right_const_iterator rightLowerBound(const U &key) const |
588 | { |
589 | return this->_rightToLeft.lowerBound(key); |
590 | } |
591 | |
592 | typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>::right_iterator rightUpperBound(const U &key) |
593 | { |
594 | return this->_rightToLeft.upperBound(key); |
595 | } |
596 | |
597 | typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T>>::right_const_iterator rightUpperBound(const U &key) const |
598 | { |
599 | return this->_rightToLeft.upperBound(key); |
600 | } |
601 | }; |
602 | |
603 | template<typename T, typename U> |
604 | QDebug operator<<(QDebug out, const KHash2Map<T, U> &container) |
605 | { |
606 | typename KHash2Map<T, U>::left_const_iterator it = container.leftConstBegin(); |
607 | |
608 | const typename KHash2Map<T, U>::left_const_iterator end = container.leftConstEnd(); |
609 | out.nospace() << "KHash2Map(" ; |
610 | for (; it != end; ++it) { |
611 | out << "(" << it.key() << " <=> " << it.value() << ") " ; |
612 | } |
613 | |
614 | out << ")" ; |
615 | return out; |
616 | } |
617 | |
618 | #endif |
619 | |