| 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 == other._leftToRight; |
| 363 | } |
| 364 | |
| 365 | bool operator!=(const KBiAssociativeContainer<LeftContainer, RightContainer> &other) |
| 366 | { |
| 367 | return _leftToRight != 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 | * 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 | |