File indexing completed on 2024-04-14 03:47:47

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