File indexing completed on 2025-01-05 03:59:20
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.net> 0003 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KBIHASH_P_H 0009 #define KBIHASH_P_H 0010 0011 #include <QHash> 0012 #include <QMap> 0013 0014 #include <QDebug> 0015 0016 template<typename LeftContainer, typename RightContainer> 0017 class KBiAssociativeContainer; 0018 0019 template<typename LeftContainer, typename RightContainer> 0020 QDebug operator<<(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container); 0021 0022 template<typename LeftContainer, typename RightContainer> 0023 QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container); 0024 0025 template<typename LeftContainer, typename RightContainer> 0026 QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &container); 0027 0028 0029 template<typename LeftContainer, typename RightContainer> 0030 class KBiAssociativeContainer 0031 { 0032 // We need to convert from a QHash::iterator or QMap::iterator 0033 // to a KBiAssociativeContainer::iterator (left or right) 0034 // Do do that we use this implicit ctor. We partially specialize 0035 // it for QHash and QMap types. 0036 // Our iterator inherits from this struct to get the implicit ctor, 0037 // and this struct must inherit from the QHash or QMap iterator. 0038 template<typename Container, typename T, typename U> 0039 struct _iterator_impl_ctor : public Container::iterator 0040 { 0041 _iterator_impl_ctor(typename Container::iterator it); 0042 }; 0043 0044 template<typename T, typename U> 0045 struct _iterator_impl_ctor<QHash<T, U>, T, U> : public QHash<T, U>::iterator 0046 { 0047 /* implicit */ _iterator_impl_ctor(const typename QHash<T, U>::iterator it) 0048 // Using internals here because I was too lazy to write my own iterator. 0049 : QHash<T, U>::iterator(it) 0050 { 0051 0052 } 0053 }; 0054 0055 template<typename T, typename U> 0056 struct _iterator_impl_ctor<QMap<T, U>, T, U> : public QMap<T, U>::iterator 0057 { 0058 /* implicit */ _iterator_impl_ctor(const typename QMap<T, U>::iterator it) 0059 // Using internals here because I was too lazy to write my own iterator. 0060 : QMap<T, U>::iterator(it) 0061 { 0062 0063 } 0064 }; 0065 public: 0066 using left_type = typename QMap<int, QPersistentModelIndex>::mapped_type; 0067 using right_type = typename QHash<QPersistentModelIndex, int>::mapped_type; 0068 0069 template <typename Container> 0070 class _iterator : public _iterator_impl_ctor<Container, typename Container::key_type, typename Container::mapped_type> 0071 { 0072 public: 0073 explicit inline _iterator(void *data) : Container::iterator(data) {} 0074 0075 /* implicit */ _iterator(const typename Container::iterator it) 0076 : _iterator_impl_ctor<Container, typename Container::key_type, typename Container::mapped_type>(it) 0077 { 0078 0079 } 0080 0081 inline const typename Container::mapped_type &value() const { 0082 return Container::iterator::value(); 0083 } 0084 inline const typename Container::mapped_type &operator*() const { 0085 return Container::iterator::operator*(); 0086 } 0087 inline const typename Container::mapped_type *operator->() const { 0088 return Container::iterator::operator->(); 0089 } 0090 0091 private: 0092 #ifndef Q_CC_MSVC 0093 using Container::iterator::operator*; 0094 using Container::iterator::operator->; 0095 using Container::iterator::value; 0096 #endif 0097 }; 0098 0099 using left_iterator = _iterator<QHash<QPersistentModelIndex, int> >; 0100 using left_const_iterator = typename QHash<QPersistentModelIndex, int>::const_iterator; 0101 using right_iterator = _iterator<QMap<int, QPersistentModelIndex> >; 0102 using right_const_iterator = typename QMap<int, QPersistentModelIndex>::const_iterator; 0103 0104 inline KBiAssociativeContainer() {} 0105 inline KBiAssociativeContainer(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) { 0106 *this = other; 0107 } 0108 0109 const KBiAssociativeContainer<LeftContainer, RightContainer> &operator=(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) { 0110 _leftToRight = other._leftToRight; _rightToLeft = other._rightToLeft; return *this; 0111 } 0112 0113 inline bool removeLeft(left_type t) { 0114 const right_type u = _leftToRight.take(t); 0115 return _rightToLeft.remove(u) != 0; 0116 } 0117 0118 inline bool removeRight(right_type u) { 0119 const left_type t = _rightToLeft.take(u); 0120 return _leftToRight.remove(t) != 0; 0121 } 0122 0123 inline right_type takeLeft(left_type t) { 0124 const right_type u = _leftToRight.take(t); 0125 _rightToLeft.remove(u); 0126 return u; 0127 } 0128 0129 inline left_type takeRight(right_type u) { 0130 const left_type t = _rightToLeft.take(u); 0131 _leftToRight.remove(t); 0132 return t; 0133 } 0134 0135 inline left_type rightToLeft(right_type u) const { 0136 return _rightToLeft.value(u); 0137 } 0138 0139 inline right_type leftToRight(left_type t) const { 0140 return _leftToRight.value(t); 0141 } 0142 0143 inline bool leftContains(left_type t) const { 0144 return _leftToRight.contains(t); 0145 } 0146 0147 inline bool rightContains(right_type u) const { 0148 return _rightToLeft.contains(u); 0149 } 0150 0151 inline int size() const { 0152 return _leftToRight.size(); 0153 } 0154 0155 inline int count() const { 0156 return _leftToRight.count(); 0157 } 0158 0159 inline int capacity() const { 0160 return _leftToRight.capacity(); 0161 } 0162 0163 void reserve(int size) { 0164 _leftToRight.reserve(size); _rightToLeft.reserve(size); 0165 } 0166 0167 inline void squeeze() { 0168 _leftToRight.squeeze(); _rightToLeft.squeeze(); 0169 } 0170 0171 inline void detach() { 0172 _leftToRight.detach(); _rightToLeft.detach(); 0173 } 0174 0175 inline bool isDetached() const { 0176 return _leftToRight.isDetached(); 0177 } 0178 0179 inline void setSharable(bool sharable) { 0180 _leftToRight.setSharable(sharable); _rightToLeft.setSharable(sharable); 0181 } 0182 0183 inline bool isSharedWith(const KBiAssociativeContainer<RightContainer, LeftContainer> &other) const { 0184 return _leftToRight.isSharedWith(other._leftToRight) && _rightToLeft.isSharedWith(other._leftToRight); 0185 } 0186 0187 void clear() { 0188 _leftToRight.clear(); _rightToLeft.clear(); 0189 } 0190 0191 QList<left_type> leftValues() const { 0192 return _leftToRight.keys(); 0193 } 0194 0195 QList<right_type> rightValues() const { 0196 return _rightToLeft.keys(); 0197 } 0198 0199 right_iterator eraseRight(right_iterator it) { 0200 Q_ASSERT(it != rightEnd()); 0201 _leftToRight.remove(it.value()); 0202 return _rightToLeft.erase(it); 0203 } 0204 0205 left_iterator eraseLeft(left_iterator it) { 0206 Q_ASSERT(it != leftEnd()); 0207 _rightToLeft.remove(it.value()); 0208 return _leftToRight.erase(it); 0209 } 0210 0211 left_iterator findLeft(left_type t) { 0212 return _leftToRight.find(t); 0213 } 0214 0215 left_const_iterator findLeft(left_type t) const { 0216 return _leftToRight.find(t); 0217 } 0218 0219 left_const_iterator constFindLeft(left_type t) const { 0220 return _leftToRight.constFind(t); 0221 } 0222 0223 right_iterator findRight(right_type u) { 0224 return _rightToLeft.find(u); 0225 } 0226 0227 right_const_iterator findRight(right_type u) const { 0228 return _rightToLeft.find(u); 0229 } 0230 0231 right_const_iterator constFindRight(right_type u) const { 0232 return _rightToLeft.find(u); 0233 } 0234 0235 left_iterator insert(left_type t, right_type u) { 0236 // biHash.insert(5, 7); // creates 5->7 in _leftToRight and 7->5 in _rightToLeft 0237 // biHash.insert(5, 9); // replaces 5->7 with 5->9 in _leftToRight and inserts 9->5 in _rightToLeft. 0238 // The 7->5 in _rightToLeft would be dangling, so we remove it before insertion. 0239 0240 // This means we need to hash u and t up to twice each. Could probably be done better using QHashNode. 0241 0242 if (_leftToRight.contains(t)) 0243 _rightToLeft.remove(_leftToRight.take(t)); 0244 if (_rightToLeft.contains(u)) 0245 _leftToRight.remove(_rightToLeft.take(u)); 0246 0247 _rightToLeft.insert(u, t); 0248 return _leftToRight.insert(t, u); 0249 } 0250 0251 0252 KBiAssociativeContainer<LeftContainer, RightContainer> &intersect(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) { 0253 typename KBiAssociativeContainer<RightContainer, LeftContainer>::left_iterator it = leftBegin(); 0254 while (it != leftEnd()) { 0255 if (!other.leftContains(it.key())) 0256 it = eraseLeft(it); 0257 else 0258 ++it; 0259 } 0260 return *this; 0261 } 0262 0263 KBiAssociativeContainer<LeftContainer, RightContainer> &subtract(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) { 0264 typename KBiAssociativeContainer<RightContainer, LeftContainer>::left_iterator it = leftBegin(); 0265 while (it != leftEnd()) { 0266 if (other._leftToRight.contains(it.key())) 0267 it = eraseLeft(it); 0268 else 0269 ++it; 0270 } 0271 return *this; 0272 } 0273 0274 KBiAssociativeContainer<LeftContainer, RightContainer> &unite(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) { 0275 typename LeftContainer::const_iterator it = other._leftToRight.constBegin(); 0276 const typename LeftContainer::const_iterator end = other._leftToRight.constEnd(); 0277 while (it != end) { 0278 const left_type key = it.key(); 0279 if (!_leftToRight.contains(key)) 0280 insert(key, it.value()); 0281 ++it; 0282 } 0283 return *this; 0284 } 0285 0286 void updateRight(left_iterator it, right_type u) { 0287 Q_ASSERT(it != leftEnd()); 0288 const left_type key = it.key(); 0289 _rightToLeft.remove(_leftToRight.value(key)); 0290 _leftToRight[key] = u; 0291 _rightToLeft[u] = key; 0292 } 0293 0294 void updateLeft(right_iterator it, left_type t) { 0295 Q_ASSERT(it != rightEnd()); 0296 const right_type key = it.key(); 0297 _leftToRight.remove(_rightToLeft.value(key)); 0298 _rightToLeft[key] = t; 0299 _leftToRight[t] = key; 0300 } 0301 0302 inline bool isEmpty() const { 0303 return _leftToRight.isEmpty(); 0304 } 0305 0306 right_type operator[](const left_type &t) const { 0307 return _leftToRight.operator[](t); 0308 } 0309 0310 bool operator==(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) const { 0311 return _leftToRight.operator == (other._leftToRight); 0312 } 0313 0314 bool operator!=(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) const { 0315 return _leftToRight.operator != (other._leftToRight); 0316 } 0317 0318 left_iterator toLeftIterator(right_iterator it) const { 0319 Q_ASSERT(it != rightEnd()); 0320 return _leftToRight.find(it.value()); 0321 } 0322 0323 right_iterator toRightIterator(left_iterator it) const { 0324 Q_ASSERT(it != leftEnd()); 0325 return _rightToLeft.find(it.value()); 0326 } 0327 0328 inline left_iterator leftBegin() { 0329 return _leftToRight.begin(); 0330 } 0331 0332 inline left_iterator leftEnd() { 0333 return _leftToRight.end(); 0334 } 0335 0336 inline left_const_iterator leftBegin() const { 0337 return _leftToRight.begin(); 0338 } 0339 0340 inline left_const_iterator leftEnd() const { 0341 return _leftToRight.end(); 0342 } 0343 0344 inline left_const_iterator leftConstBegin() const { 0345 return _leftToRight.constBegin(); 0346 } 0347 0348 inline left_const_iterator leftConstEnd() const { 0349 return _leftToRight.constEnd(); 0350 } 0351 0352 inline right_iterator rightBegin() { 0353 return _rightToLeft.begin(); 0354 } 0355 0356 inline right_iterator rightEnd() { 0357 return _rightToLeft.end(); 0358 } 0359 0360 inline right_const_iterator rightBegin() const { 0361 return _rightToLeft.begin(); 0362 } 0363 0364 inline right_const_iterator rightEnd() const { 0365 return _rightToLeft.end(); 0366 } 0367 inline right_const_iterator rightConstBegin() const { 0368 return _rightToLeft.constBegin(); 0369 } 0370 0371 inline right_const_iterator rightConstEnd() const { 0372 return _rightToLeft.constEnd(); 0373 } 0374 0375 static KBiAssociativeContainer<LeftContainer, RightContainer> fromHash(const QHash<left_type, right_type> &hash) { 0376 KBiAssociativeContainer<LeftContainer, RightContainer> container; 0377 typename QHash<left_type, right_type>::const_iterator it = hash.constBegin(); 0378 const typename QHash<left_type, right_type>::const_iterator end = hash.constEnd(); 0379 for ( ; it != end; ++it) 0380 container.insert(it.key(), it.value()); 0381 return container; 0382 } 0383 0384 static KBiAssociativeContainer<LeftContainer, RightContainer> fromMap(const QMap<left_type, right_type> &hash) { 0385 KBiAssociativeContainer<LeftContainer, RightContainer> container; 0386 typename QMap<left_type, right_type>::const_iterator it = hash.constBegin(); 0387 const typename QMap<left_type, right_type>::const_iterator end = hash.constEnd(); 0388 for ( ; it != end; ++it) 0389 container.insert(it.key(), it.value()); 0390 return container; 0391 } 0392 0393 friend QDataStream &operator<< <LeftContainer, RightContainer>(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &bihash); 0394 friend QDataStream &operator>> <LeftContainer, RightContainer>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &biHash); 0395 friend QDebug operator<< <LeftContainer, RightContainer>(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &biHash); 0396 protected: 0397 LeftContainer _leftToRight; 0398 RightContainer _rightToLeft; 0399 }; 0400 0401 template<typename LeftContainer, typename RightContainer> 0402 QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container) 0403 { 0404 return out << container._leftToRight; 0405 } 0406 0407 template<typename LeftContainer, typename RightContainer> 0408 QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer<LeftContainer, RightContainer> &container) 0409 { 0410 LeftContainer leftToRight; 0411 in >> leftToRight; 0412 typename LeftContainer::const_iterator it = leftToRight.constBegin(); 0413 const typename LeftContainer::const_iterator end = leftToRight.constEnd(); 0414 for (; it != end; ++it) 0415 container.insert(it.key(), it.value()); 0416 0417 return in; 0418 } 0419 0420 template<typename Container, typename T, typename U> 0421 struct _containerType 0422 { 0423 operator const char *(); 0424 }; 0425 0426 template<typename T, typename U> 0427 struct _containerType<QHash<T, U>, T, U> 0428 { 0429 operator const char *() 0430 { 0431 return "QHash"; 0432 } 0433 }; 0434 0435 template<typename T, typename U> 0436 struct _containerType<QMap<T, U>, T, U> 0437 { 0438 operator const char *() 0439 { 0440 return "QMap"; 0441 } 0442 }; 0443 0444 0445 template<typename Container> 0446 static const char * containerType() 0447 { 0448 return _containerType<Container, typename Container::key_type, typename Container::mapped_type>(); 0449 } 0450 0451 template<typename LeftContainer, typename RightContainer> 0452 QDebug operator<<(QDebug out, const KBiAssociativeContainer<LeftContainer, RightContainer> &container) 0453 { 0454 typename KBiAssociativeContainer<LeftContainer, RightContainer>::left_const_iterator it = container.leftConstBegin(); 0455 0456 const typename KBiAssociativeContainer<LeftContainer, RightContainer>::left_const_iterator end = container.leftConstEnd(); 0457 out.nospace() << "KBiAssociativeContainer<" << containerType<LeftContainer>() << ", " << containerType<RightContainer>() << ">" << "("; 0458 for (; it != end; ++it) 0459 out << "(" << it.key() << " <=> " << it.value() << ") "; 0460 0461 out << ")"; 0462 return out; 0463 } 0464 0465 /** 0466 * @brief KBiHash provides a bi-directional hash container 0467 * 0468 * @note This class is designed to make mapping easier in proxy model implementations. 0469 * 0470 * @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. 0471 */ 0472 template <typename T, typename U> 0473 struct KBiHash : public KBiAssociativeContainer<QHash<T, U>, QHash<U, T> > 0474 { 0475 KBiHash() 0476 : KBiAssociativeContainer<QHash<T, U>, QHash<U, T> > () 0477 { 0478 0479 } 0480 0481 KBiHash(const KBiAssociativeContainer<QHash<T, U>, QHash<U, T> > &container) 0482 : KBiAssociativeContainer<QHash<T, U>, QHash<U, T> > (container) 0483 { 0484 0485 } 0486 }; 0487 0488 template<typename T, typename U> 0489 QDebug operator<<(QDebug out, const KBiHash<T, U> &biHash) 0490 { 0491 typename KBiHash<T, U>::left_const_iterator it = biHash.leftConstBegin(); 0492 0493 const typename KBiHash<T, U>::left_const_iterator end = biHash.leftConstEnd(); 0494 out.nospace() << "KBiHash("; 0495 for (; it != end; ++it) 0496 out << "(" << it.key() << " <=> " << it.value() << ") "; 0497 0498 out << ")"; 0499 return out; 0500 } 0501 0502 template <typename T, typename U> 0503 struct KHash2Map : public KBiAssociativeContainer<QHash<T, U>, QMap<U, T> > 0504 { 0505 KHash2Map() 0506 : KBiAssociativeContainer<QHash<T, U>, QMap<U, T> > () 0507 { 0508 0509 } 0510 0511 KHash2Map(const KBiAssociativeContainer<QHash<T, U>, QMap<U, T> > &container) 0512 : KBiAssociativeContainer<QHash<T, U>, QMap<U, T> > (container) 0513 { 0514 0515 } 0516 0517 typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T> >::right_iterator rightLowerBound(const U &key) 0518 { 0519 return this->_rightToLeft.lowerBound(key); 0520 } 0521 0522 typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T> >::right_const_iterator rightLowerBound(const U &key) const 0523 { 0524 return this->_rightToLeft.lowerBound(key); 0525 } 0526 0527 typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T> >::right_iterator rightUpperBound(const U &key) 0528 { 0529 return this->_rightToLeft.upperBound(key); 0530 } 0531 0532 typename KBiAssociativeContainer<QHash<T, U>, QMap<U, T> >::right_const_iterator rightUpperBound(const U &key) const 0533 { 0534 return this->_rightToLeft.upperBound(key); 0535 } 0536 }; 0537 0538 template<typename T, typename U> 0539 QDebug operator<<(QDebug out, const KHash2Map<T, U> &container) 0540 { 0541 typename KHash2Map<T, U>::left_const_iterator it = container.leftConstBegin(); 0542 0543 const typename KHash2Map<T, U>::left_const_iterator end = container.leftConstEnd(); 0544 out.nospace() << "KHash2Map("; 0545 for (; it != end; ++it) 0546 out << "(" << it.key() << " <=> " << it.value() << ") "; 0547 0548 out << ")"; 0549 return out; 0550 } 0551 0552 #endif