diff --git a/src/core/qqtdictionary.cpp b/src/core/qqtdictionary.cpp index d77a6458..86d01122 100644 --- a/src/core/qqtdictionary.cpp +++ b/src/core/qqtdictionary.cpp @@ -62,7 +62,7 @@ void QQtDictionary::setChild ( const QList& list ) m_list = list; } -void QQtDictionary::setChild ( const QMap& map ) +void QQtDictionary::setChild ( const QQtOrderedMap& map ) { m_type = DictMap; m_map = map; @@ -359,7 +359,7 @@ QQtDictionary& QQtDictionary::operator [] ( const QString& key ) return m_map.operator [] ( key ); } -QQtDictionary& QQtDictionary::operator = ( const QMap& map ) +QQtDictionary& QQtDictionary::operator = ( const QQtOrderedMap& map ) { m_type = DictMap; m_map = map; @@ -533,13 +533,28 @@ void QQtDictionary::parseDictionaryToJsonValue ( const QQtDictionary& node, QJso QList& l = node.getList(); QJsonValue value; parseDictionaryToJsonValue ( l[i], value ); - array.append ( value ); + //array.append ( value ); + array.push_back ( value ); } result = array; break; } case DictMap: + { + //"name": {"a":"b", "a2":"b2", "a3":["b31", "b32"], "a4":{"a41":"b41", "a42":"b42"}, ...} + QJsonObject object; + for ( QQtOrderedMap::Iterator itor = node.getMap().begin(); itor != node.getMap().end(); itor++ ) + { + //QQtOrderedMap& m = node.getMap(); + const QString& key = itor.key(); + const QQtDictionary& srcvalue = itor.value(); + QJsonValue value; + parseDictionaryToJsonValue ( srcvalue, value ); + object.insert ( key, value ); + } + result = object; break; + } case DictMax: default: break; @@ -557,9 +572,9 @@ bool QQtDictionary::operator == ( const QQtDictionary& other ) const return false; } -QMap& QQtDictionary::getMap() const +QQtOrderedMap& QQtDictionary::getMap() const { - return ( QMap& ) m_map; + return ( QQtOrderedMap& ) m_map; } QList& QQtDictionary::getList() const diff --git a/src/core/qqtdictionary.h b/src/core/qqtdictionary.h index 4e34d0e5..1d7fe9c9 100644 --- a/src/core/qqtdictionary.h +++ b/src/core/qqtdictionary.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -12,13 +12,13 @@ * 遍历时 */ class QQtDictionary; -typedef QMap QQtDictionaryMap; -typedef QMapIterator QQtDictionaryMapIterator; -typedef QMutableMapIterator QQtDictionaryMutableMapIterator; +typedef QQtOrderedMap QQtDictionaryMap; +typedef QQtOrderedMap::Iterator QQtDictionaryMapIterator; +typedef QQtOrderedMap::ConstIterator QQtDictionaryMapConstIterator; typedef QList QQtDictionaryList; -typedef QListIterator QQtDictionaryListIterator; -typedef QMutableListIterator QQtDictionaryMutableListIterator; +typedef QList::Iterator QQtDictionaryListIterator; +typedef QList::ConstIterator QQtDictionaryListConstIterator; /** * @brief The QQtDictionary class @@ -30,8 +30,8 @@ typedef QMutableListIterator QQtDictionaryMutableListIterator; * 接受嵌套访问 操作方式 dict["cccc"][0]["eeeee"] * 通过重载函数来实现类型的变化,不建议使用中更改类型。 * 比json和xml的数据结构要庞大。toJson toXML fromJson fromXML - * QVariant 不能直接获取到真实数据,改变必须使用临时变量。 - * 而且,接口设计也不够灵活,存入和取出都不太方便。 + * QVariant 不能直接获取到真实数据,改变必须使用临时变量,而且,接口设计也不够灵活,存入和取出都不太方便。 + * QQtDictionary封装了QVariant,实现直接操作真实数据。提供大量操作符。存取数据方便快捷,类型多样。 */ class QQTSHARED_EXPORT QQtDictionary { @@ -72,7 +72,7 @@ public: /*获取全部数据*/ /*获取当前字典的全部数据*/ /*保存为[key]=[value]的*/ - QMap& getMap() const; + QQtOrderedMap& getMap() const; /*保存为index=[value]*/ QList& getList() const ; @@ -106,7 +106,7 @@ public: /*whole value list*/ void setChild ( const QList& list ); /*whole value map*/ - void setChild ( const QMap& map ); + void setChild ( const QQtOrderedMap& map ); /*自己本身没有孩子,添加一个个的孩子*/ /*index = int*/ @@ -145,7 +145,7 @@ public: QQtDictionary& operator [] ( const QString& key ); const QQtDictionary operator[] ( const QString& key ) const; - QQtDictionary& operator = ( const QMap& map ); + QQtDictionary& operator = ( const QQtOrderedMap& map ); QQtDictionary& operator = ( const QList& list ); QQtDictionary& operator = ( const QQtDictionary& other ); QQtDictionary& operator = ( const QVariant& value ); @@ -189,7 +189,7 @@ private: QList m_list; //[index] /*不是叶子映射,是个子字典,是个叶子,是个叶子的值组合*/ /*映射保存在这里,QStirng可以升级为QVariant*/ - QMap m_map; + QQtOrderedMap m_map; /*是个列表和子字典,这是错误的,不可能的*/ }; diff --git a/src/core/qqtorderedmap.cpp b/src/core/qqtorderedmap.cpp new file mode 100644 index 00000000..877d640e --- /dev/null +++ b/src/core/qqtorderedmap.cpp @@ -0,0 +1,387 @@ +#include + +#include + +#ifdef QT_QMAP_DEBUG +# include +# include +#endif + +const QQtOrderedMapDataBase QQtOrderedMapDataBase::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, { 0, 0, 0 }, 0 }; + +const QQtOrderedMapNodeBase* QQtOrderedMapNodeBase::nextNode() const +{ + const QQtOrderedMapNodeBase* n = this; + if ( n->right ) + { + n = n->right; + while ( n->left ) + n = n->left; + } + else + { + const QQtOrderedMapNodeBase* y = n->parent(); + while ( y && n == y->right ) + { + n = y; + y = n->parent(); + } + n = y; + } + return n; +} + +const QQtOrderedMapNodeBase* QQtOrderedMapNodeBase::previousNode() const +{ + const QQtOrderedMapNodeBase* n = this; + if ( n->left ) + { + n = n->left; + while ( n->right ) + n = n->right; + } + else + { + const QQtOrderedMapNodeBase* y = n->parent(); + while ( y && n == y->left ) + { + n = y; + y = n->parent(); + } + n = y; + } + return n; +} + + +void QQtOrderedMapDataBase::rotateLeft ( QQtOrderedMapNodeBase* x ) +{ + QQtOrderedMapNodeBase*& root = header.left; + QQtOrderedMapNodeBase* y = x->right; + x->right = y->left; + if ( y->left != 0 ) + y->left->setParent ( x ); + y->setParent ( x->parent() ); + if ( x == root ) + root = y; + else if ( x == x->parent()->left ) + x->parent()->left = y; + else + x->parent()->right = y; + y->left = x; + x->setParent ( y ); +} + + +void QQtOrderedMapDataBase::rotateRight ( QQtOrderedMapNodeBase* x ) +{ + QQtOrderedMapNodeBase*& root = header.left; + QQtOrderedMapNodeBase* y = x->left; + x->left = y->right; + if ( y->right != 0 ) + y->right->setParent ( x ); + y->setParent ( x->parent() ); + if ( x == root ) + root = y; + else if ( x == x->parent()->right ) + x->parent()->right = y; + else + x->parent()->left = y; + y->right = x; + x->setParent ( y ); +} + + +void QQtOrderedMapDataBase::rebalance ( QQtOrderedMapNodeBase* x ) +{ + QQtOrderedMapNodeBase*& root = header.left; + x->setColor ( QQtOrderedMapNodeBase::Red ); + while ( x != root && x->parent()->color() == QQtOrderedMapNodeBase::Red ) + { + if ( x->parent() == x->parent()->parent()->left ) + { + QQtOrderedMapNodeBase* y = x->parent()->parent()->right; + if ( y && y->color() == QQtOrderedMapNodeBase::Red ) + { + x->parent()->setColor ( QQtOrderedMapNodeBase::Black ); + y->setColor ( QQtOrderedMapNodeBase::Black ); + x->parent()->parent()->setColor ( QQtOrderedMapNodeBase::Red ); + x = x->parent()->parent(); + } + else + { + if ( x == x->parent()->right ) + { + x = x->parent(); + rotateLeft ( x ); + } + x->parent()->setColor ( QQtOrderedMapNodeBase::Black ); + x->parent()->parent()->setColor ( QQtOrderedMapNodeBase::Red ); + rotateRight ( x->parent()->parent() ); + } + } + else + { + QQtOrderedMapNodeBase* y = x->parent()->parent()->left; + if ( y && y->color() == QQtOrderedMapNodeBase::Red ) + { + x->parent()->setColor ( QQtOrderedMapNodeBase::Black ); + y->setColor ( QQtOrderedMapNodeBase::Black ); + x->parent()->parent()->setColor ( QQtOrderedMapNodeBase::Red ); + x = x->parent()->parent(); + } + else + { + if ( x == x->parent()->left ) + { + x = x->parent(); + rotateRight ( x ); + } + x->parent()->setColor ( QQtOrderedMapNodeBase::Black ); + x->parent()->parent()->setColor ( QQtOrderedMapNodeBase::Red ); + rotateLeft ( x->parent()->parent() ); + } + } + } + root->setColor ( QQtOrderedMapNodeBase::Black ); +} + +void QQtOrderedMapDataBase::freeNodeAndRebalance ( QQtOrderedMapNodeBase* z ) +{ + QQtOrderedMapNodeBase*& root = header.left; + QQtOrderedMapNodeBase* y = z; + QQtOrderedMapNodeBase* x; + QQtOrderedMapNodeBase* x_parent; + if ( y->left == 0 ) + { + x = y->right; + if ( y == mostLeftNode ) + { + if ( x ) + mostLeftNode = x; // It cannot have (left) children due the red black invariant. + else + mostLeftNode = y->parent(); + } + } + else + { + if ( y->right == 0 ) + { + x = y->left; + } + else + { + y = y->right; + while ( y->left != 0 ) + y = y->left; + x = y->right; + } + } + if ( y != z ) + { + z->left->setParent ( y ); + y->left = z->left; + if ( y != z->right ) + { + x_parent = y->parent(); + if ( x ) + x->setParent ( y->parent() ); + y->parent()->left = x; + y->right = z->right; + z->right->setParent ( y ); + } + else + { + x_parent = y; + } + if ( root == z ) + root = y; + else if ( z->parent()->left == z ) + z->parent()->left = y; + else + z->parent()->right = y; + y->setParent ( z->parent() ); + // Swap the colors + QQtOrderedMapNodeBase::Color c = y->color(); + y->setColor ( z->color() ); + z->setColor ( c ); + y = z; + } + else + { + x_parent = y->parent(); + if ( x ) + x->setParent ( y->parent() ); + if ( root == z ) + root = x; + else if ( z->parent()->left == z ) + z->parent()->left = x; + else + z->parent()->right = x; + } + if ( y->color() != QQtOrderedMapNodeBase::Red ) + { + while ( x != root && ( x == 0 || x->color() == QQtOrderedMapNodeBase::Black ) ) + { + if ( x == x_parent->left ) + { + QQtOrderedMapNodeBase* w = x_parent->right; + if ( w->color() == QQtOrderedMapNodeBase::Red ) + { + w->setColor ( QQtOrderedMapNodeBase::Black ); + x_parent->setColor ( QQtOrderedMapNodeBase::Red ); + rotateLeft ( x_parent ); + w = x_parent->right; + } + if ( ( w->left == 0 || w->left->color() == QQtOrderedMapNodeBase::Black ) && + ( w->right == 0 || w->right->color() == QQtOrderedMapNodeBase::Black ) ) + { + w->setColor ( QQtOrderedMapNodeBase::Red ); + x = x_parent; + x_parent = x_parent->parent(); + } + else + { + if ( w->right == 0 || w->right->color() == QQtOrderedMapNodeBase::Black ) + { + if ( w->left ) + w->left->setColor ( QQtOrderedMapNodeBase::Black ); + w->setColor ( QQtOrderedMapNodeBase::Red ); + rotateRight ( w ); + w = x_parent->right; + } + w->setColor ( x_parent->color() ); + x_parent->setColor ( QQtOrderedMapNodeBase::Black ); + if ( w->right ) + w->right->setColor ( QQtOrderedMapNodeBase::Black ); + rotateLeft ( x_parent ); + break; + } + } + else + { + QQtOrderedMapNodeBase* w = x_parent->left; + if ( w->color() == QQtOrderedMapNodeBase::Red ) + { + w->setColor ( QQtOrderedMapNodeBase::Black ); + x_parent->setColor ( QQtOrderedMapNodeBase::Red ); + rotateRight ( x_parent ); + w = x_parent->left; + } + if ( ( w->right == 0 || w->right->color() == QQtOrderedMapNodeBase::Black ) && + ( w->left == 0 || w->left->color() == QQtOrderedMapNodeBase::Black ) ) + { + w->setColor ( QQtOrderedMapNodeBase::Red ); + x = x_parent; + x_parent = x_parent->parent(); + } + else + { + if ( w->left == 0 || w->left->color() == QQtOrderedMapNodeBase::Black ) + { + if ( w->right ) + w->right->setColor ( QQtOrderedMapNodeBase::Black ); + w->setColor ( QQtOrderedMapNodeBase::Red ); + rotateLeft ( w ); + w = x_parent->left; + } + w->setColor ( x_parent->color() ); + x_parent->setColor ( QQtOrderedMapNodeBase::Black ); + if ( w->left ) + w->left->setColor ( QQtOrderedMapNodeBase::Black ); + rotateRight ( x_parent ); + break; + } + } + } + if ( x ) + x->setColor ( QQtOrderedMapNodeBase::Black ); + } + free ( y ); + --size; +} + +void QQtOrderedMapDataBase::recalcMostLeftNode() +{ + mostLeftNode = &header; + while ( mostLeftNode->left ) + mostLeftNode = mostLeftNode->left; +} + +static inline int qMapAlignmentThreshold() +{ + // malloc on 32-bit platforms should return pointers that are 8-byte + // aligned or more while on 64-bit platforms they should be 16-byte aligned + // or more + return 2 * sizeof ( void* ); +} + +static inline void* qMapAllocate ( int alloc, int alignment ) +{ + return alignment > qMapAlignmentThreshold() + ? qMallocAligned ( alloc, alignment ) + : ::malloc ( alloc ); +} + +static inline void qMapDeallocate ( QQtOrderedMapNodeBase* node, int alignment ) +{ + if ( alignment > qMapAlignmentThreshold() ) + qFreeAligned ( node ); + else + ::free ( node ); +} + +QQtOrderedMapNodeBase* QQtOrderedMapDataBase::createNode ( int alloc, int alignment, QQtOrderedMapNodeBase* parent, bool left ) +{ + QQtOrderedMapNodeBase* node = static_cast ( qMapAllocate ( alloc, alignment ) ); + Q_CHECK_PTR ( node ); + + memset ( node, 0, alloc ); + ++size; + + if ( parent ) + { + if ( left ) + { + parent->left = node; + if ( parent == mostLeftNode ) + mostLeftNode = node; + } + else + { + parent->right = node; + } + node->setParent ( parent ); + rebalance ( node ); + } + return node; +} + +void QQtOrderedMapDataBase::freeTree ( QQtOrderedMapNodeBase* root, int alignment ) +{ + if ( root->left ) + freeTree ( root->left, alignment ); + if ( root->right ) + freeTree ( root->right, alignment ); + qMapDeallocate ( root, alignment ); +} + +QQtOrderedMapDataBase* QQtOrderedMapDataBase::createData() +{ + QQtOrderedMapDataBase* d = new QQtOrderedMapDataBase; + + d->ref.initializeOwned(); + d->size = 0; + + d->header.p = 0; + d->header.left = 0; + d->header.right = 0; + d->mostLeftNode = & ( d->header ); + + return d; +} + +void QQtOrderedMapDataBase::freeData ( QQtOrderedMapDataBase* d ) +{ + delete d; +} diff --git a/src/core/qqtorderedmap.h b/src/core/qqtorderedmap.h new file mode 100644 index 00000000..9afd09b5 --- /dev/null +++ b/src/core/qqtorderedmap.h @@ -0,0 +1,1319 @@ +#ifndef QQTORDEREDMAP_H +#define QQTORDEREDMAP_H + +#include +#include +#include +#include + +#ifdef Q_MAP_DEBUG +#include +#endif + +#include +#include +#include + +#ifdef Q_COMPILER_INITIALIZER_LISTS +#include +#endif + +#include + +/* + QQtOrderedMap uses QQtOrderedMapLessThanKey() to compare keys. The default + implementation uses operator<(). For pointer types, + QQtOrderedMapLessThanKey() uses std::less (because operator<() on + pointers can be used only between pointers in the same array). +*/ + +template inline bool QQtOrderedMapLessThanKey ( const Key& key1, const Key& key2 ) +{ + return true; +} + +template inline bool QQtOrderedMapLessThanKey ( const Ptr* key1, const Ptr* key2 ) +{ + return true; +} + +struct QQtOrderedMapDataBase; +template struct QQtOrderedMapData; + +struct QQTSHARED_EXPORT QQtOrderedMapNodeBase +{ + quintptr p; + QQtOrderedMapNodeBase* left; + QQtOrderedMapNodeBase* right; + + enum Color { Red = 0, Black = 1 }; + enum { Mask = 3 }; // reserve the second bit as well + + const QQtOrderedMapNodeBase* nextNode() const; + QQtOrderedMapNodeBase* nextNode() { return const_cast ( const_cast ( this )->nextNode() ); } + const QQtOrderedMapNodeBase* previousNode() const; + QQtOrderedMapNodeBase* previousNode() { return const_cast ( const_cast ( this )->previousNode() ); } + + Color color() const { return Color ( p & 1 ); } + void setColor ( Color c ) { if ( c == Black ) p |= Black; else p &= ~Black; } + QQtOrderedMapNodeBase* parent() const { return reinterpret_cast ( p & ~Mask ); } + void setParent ( QQtOrderedMapNodeBase* pp ) { p = ( p & Mask ) | quintptr ( pp ); } + + template + static typename std::enable_if::isComplex>::type + callDestructorIfNecessary ( T& t ) Q_DECL_NOTHROW { Q_UNUSED ( t ); t.~T(); } // Q_UNUSED: silence MSVC unused 't' warning + template + static typename std::enable_if < !QTypeInfo::isComplex >::type + callDestructorIfNecessary ( T& ) Q_DECL_NOTHROW {} +}; + +template +struct QQtOrderedMapNode : public QQtOrderedMapNodeBase +{ + Key key; + T value; + + inline QQtOrderedMapNode* leftNode() const { return static_cast ( left ); } + inline QQtOrderedMapNode* rightNode() const { return static_cast ( right ); } + + inline const QQtOrderedMapNode* nextNode() const { return static_cast ( QQtOrderedMapNodeBase::nextNode() ); } + inline const QQtOrderedMapNode* previousNode() const { return static_cast ( QQtOrderedMapNodeBase::previousNode() ); } + inline QQtOrderedMapNode* nextNode() { return static_cast ( QQtOrderedMapNodeBase::nextNode() ); } + inline QQtOrderedMapNode* previousNode() { return static_cast ( QQtOrderedMapNodeBase::previousNode() ); } + + QQtOrderedMapNode* copy ( QQtOrderedMapData* d ) const; + + void destroySubTree() { + callDestructorIfNecessary ( key ); + callDestructorIfNecessary ( value ); + doDestroySubTree ( std::integral_constant < bool, QTypeInfo::isComplex || QTypeInfo::isComplex > () ); + } + + QQtOrderedMapNode* lowerBound ( const Key& key ); + QQtOrderedMapNode* upperBound ( const Key& key ); + +private: + void doDestroySubTree ( std::false_type ) {} + void doDestroySubTree ( std::true_type ) { + if ( left ) + leftNode()->destroySubTree(); + if ( right ) + rightNode()->destroySubTree(); + } + + QQtOrderedMapNode() Q_DECL_EQ_DELETE; + Q_DISABLE_COPY ( QQtOrderedMapNode ) +}; + +template +inline QQtOrderedMapNode* QQtOrderedMapNode::lowerBound ( const Key& akey ) +{ + QQtOrderedMapNode* n = this; + QQtOrderedMapNode* lastNode = Q_NULLPTR; + while ( n ) + { + if ( !QQtOrderedMapLessThanKey ( n->key, akey ) ) + { + lastNode = n; + n = n->leftNode(); + } + else + { + n = n->rightNode(); + } + } + return lastNode; +} + +template +inline QQtOrderedMapNode* QQtOrderedMapNode::upperBound ( const Key& akey ) +{ + QQtOrderedMapNode* n = this; + QQtOrderedMapNode* lastNode = Q_NULLPTR; + while ( n ) + { + if ( QQtOrderedMapLessThanKey ( akey, n->key ) ) + { + lastNode = n; + n = n->leftNode(); + } + else + { + n = n->rightNode(); + } + } + return lastNode; +} + + + +struct QQTSHARED_EXPORT QQtOrderedMapDataBase +{ + QtPrivate::RefCount ref; + int size; + QQtOrderedMapNodeBase header; + QQtOrderedMapNodeBase* mostLeftNode; + + void rotateLeft ( QQtOrderedMapNodeBase* x ); + void rotateRight ( QQtOrderedMapNodeBase* x ); + void rebalance ( QQtOrderedMapNodeBase* x ); + void freeNodeAndRebalance ( QQtOrderedMapNodeBase* z ); + void recalcMostLeftNode(); + + QQtOrderedMapNodeBase* createNode ( int size, int alignment, QQtOrderedMapNodeBase* parent, bool left ); + void freeTree ( QQtOrderedMapNodeBase* root, int alignment ); + + static const QQtOrderedMapDataBase shared_null; + + static QQtOrderedMapDataBase* createData(); + static void freeData ( QQtOrderedMapDataBase* d ); +}; + +template +struct QQtOrderedMapData : public QQtOrderedMapDataBase +{ + typedef QQtOrderedMapNode Node; + + Node* root() const { return static_cast ( header.left ); } + + // using reinterpret_cast because QQtOrderedMapDataBase::header is not + // actually a QQtOrderedMapNode. + const Node* end() const { return reinterpret_cast ( &header ); } + Node* end() { return reinterpret_cast ( &header ); } + const Node* begin() const { if ( root() ) return static_cast ( mostLeftNode ); return end(); } + Node* begin() { if ( root() ) return static_cast ( mostLeftNode ); return end(); } + + void deleteNode ( Node* z ); + Node* findNode ( const Key& akey ) const; + void nodeRange ( const Key& akey, Node** firstNode, Node** lastNode ); + + Node* createNode ( const Key& k, const T& v, Node* parent = Q_NULLPTR, bool left = false ) { + Node* n = static_cast ( QQtOrderedMapDataBase::createNode ( sizeof ( Node ), Q_ALIGNOF ( Node ), + parent, left ) ); + QT_TRY + { + new ( &n->key ) Key ( k ); + QT_TRY { + new ( &n->value ) T ( v ); + } QT_CATCH ( ... ) { + n->key.~Key(); + QT_RETHROW; + } + } QT_CATCH ( ... ) { + QQtOrderedMapDataBase::freeNodeAndRebalance ( n ); + QT_RETHROW; + } + return n; + } + + static QQtOrderedMapData* create() { + return static_cast ( createData() ); + } + + void destroy() { + if ( root() ) { + root()->destroySubTree(); + freeTree ( header.left, Q_ALIGNOF ( Node ) ); + } + freeData ( this ); + } +}; + +template +QQtOrderedMapNode* QQtOrderedMapNode::copy ( QQtOrderedMapData* d ) const +{ + QQtOrderedMapNode* n = d->createNode ( key, value ); + n->setColor ( color() ); + if ( left ) + { + n->left = leftNode()->copy ( d ); + n->left->setParent ( n ); + } + else + { + n->left = Q_NULLPTR; + } + if ( right ) + { + n->right = rightNode()->copy ( d ); + n->right->setParent ( n ); + } + else + { + n->right = Q_NULLPTR; + } + return n; +} + +template +void QQtOrderedMapData::deleteNode ( QQtOrderedMapNode* z ) +{ + QQtOrderedMapNodeBase::callDestructorIfNecessary ( z->key ); + QQtOrderedMapNodeBase::callDestructorIfNecessary ( z->value ); + freeNodeAndRebalance ( z ); +} + +template +QQtOrderedMapNode* QQtOrderedMapData::findNode ( const Key& akey ) const +{ + if ( Node* r = root() ) + { + Node* lb = r->lowerBound ( akey ); + if ( lb && !QQtOrderedMapLessThanKey ( akey, lb->key ) ) + return lb; + } + return Q_NULLPTR; +} + + +template +void QQtOrderedMapData::nodeRange ( const Key& akey, QQtOrderedMapNode** firstNode, QQtOrderedMapNode** lastNode ) +{ + Node* n = root(); + Node* l = end(); + while ( n ) + { + if ( QQtOrderedMapLessThanKey ( akey, n->key ) ) + { + l = n; + n = n->leftNode(); + } + else if ( QQtOrderedMapLessThanKey ( n->key, akey ) ) + { + n = n->rightNode(); + } + else + { + *firstNode = n->leftNode() ? n->leftNode()->lowerBound ( akey ) : Q_NULLPTR; + if ( !*firstNode ) + *firstNode = n; + *lastNode = n->rightNode() ? n->rightNode()->upperBound ( akey ) : Q_NULLPTR; + if ( !*lastNode ) + *lastNode = l; + return; + } + } + *firstNode = *lastNode = l; +} + + +template +class QQtOrderedMap +{ + typedef QQtOrderedMapNode Node; + + QQtOrderedMapData* d; + +public: +inline QQtOrderedMap() Q_DECL_NOTHROW : d ( static_cast *> ( const_cast ( &QQtOrderedMapDataBase::shared_null ) ) ) { } +#ifdef Q_COMPILER_INITIALIZER_LISTS + inline QQtOrderedMap ( std::initializer_list > list ) + : d ( static_cast *> ( const_cast ( &QQtOrderedMapDataBase::shared_null ) ) ) { + for ( typename std::initializer_list >::const_iterator it = list.begin(); it != list.end(); ++it ) + insert ( it->first, it->second ); + } +#endif + QQtOrderedMap ( const QQtOrderedMap& other ); + + inline ~QQtOrderedMap() { if ( !d->ref.deref() ) d->destroy(); } + + QQtOrderedMap& operator= ( const QQtOrderedMap& other ); +#ifdef Q_COMPILER_RVALUE_REFS + inline QQtOrderedMap ( QQtOrderedMap&& other ) Q_DECL_NOTHROW +: d ( other.d ) { + other.d = static_cast *> ( + const_cast ( &QQtOrderedMapDataBase::shared_null ) ); + } + + inline QQtOrderedMap& operator= ( QQtOrderedMap&& other ) Q_DECL_NOTHROW + { QQtOrderedMap moved ( std::move ( other ) ); swap ( moved ); return *this; } +#endif + inline void swap ( QQtOrderedMap& other ) Q_DECL_NOTHROW { qSwap ( d, other.d ); } + explicit QQtOrderedMap ( const typename std::map& other ); + std::map toStdMap() const; + + bool operator== ( const QQtOrderedMap& other ) const; + inline bool operator!= ( const QQtOrderedMap& other ) const { return ! ( *this == other ); } + + inline int size() const { return d->size; } + + inline bool isEmpty() const { return d->size == 0; } + + inline void detach() { if ( d->ref.isShared() ) detach_helper(); } + inline bool isDetached() const { return !d->ref.isShared(); } +#if !defined(QT_NO_UNSHARABLE_CONTAINERS) + inline void setSharable ( bool sharable ) { + if ( sharable == d->ref.isSharable() ) + return; + if ( !sharable ) + detach(); + // Don't call on shared_null + d->ref.setSharable ( sharable ); + } +#endif + inline bool isSharedWith ( const QQtOrderedMap& other ) const { return d == other.d; } + + void clear(); + + int remove ( const Key& key ); + T take ( const Key& key ); + + bool contains ( const Key& key ) const; + const Key key ( const T& value, const Key& defaultKey = Key() ) const; + const T value ( const Key& key, const T& defaultValue = T() ) const; + T& operator[] ( const Key& key ); + const T operator[] ( const Key& key ) const; + + QList uniqueKeys() const; + QList keys() const; + QList keys ( const T& value ) const; + QList values() const; + QList values ( const Key& key ) const; + int count ( const Key& key ) const; + + inline const Key& firstKey() const { Q_ASSERT ( !isEmpty() ); return constBegin().key(); } + inline const Key& lastKey() const { Q_ASSERT ( !isEmpty() ); return ( constEnd() - 1 ).key(); } + + inline T& first() { Q_ASSERT ( !isEmpty() ); return *begin(); } + inline const T& first() const { Q_ASSERT ( !isEmpty() ); return *constBegin(); } + inline T& last() { Q_ASSERT ( !isEmpty() ); return * ( end() - 1 ); } + inline const T& last() const { Q_ASSERT ( !isEmpty() ); return * ( constEnd() - 1 ); } + + class const_iterator; + + class iterator + { + friend class const_iterator; + Node* i; + + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef qptrdiff difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + + inline iterator() : i ( Q_NULLPTR ) { } + inline iterator ( Node* node ) : i ( node ) { } + + inline const Key& key() const { return i->key; } + inline T& value() const { return i->value; } + inline T& operator*() const { return i->value; } + inline T* operator->() const { return &i->value; } + inline bool operator== ( const iterator& o ) const { return i == o.i; } + inline bool operator!= ( const iterator& o ) const { return i != o.i; } + + inline iterator& operator++() { + i = i->nextNode(); + return *this; + } + inline iterator operator++ ( int ) { + iterator r = *this; + i = i->nextNode(); + return r; + } + inline iterator& operator--() { + i = i->previousNode(); + return *this; + } + inline iterator operator-- ( int ) { + iterator r = *this; + i = i->previousNode(); + return r; + } + inline iterator operator+ ( int j ) const + { iterator r = *this; if ( j > 0 ) while ( j-- ) ++r; else while ( j++ ) --r; return r; } + inline iterator operator- ( int j ) const { return operator+ ( -j ); } + inline iterator& operator+= ( int j ) { return *this = *this + j; } + inline iterator& operator-= ( int j ) { return *this = *this - j; } + +#ifndef QT_STRICT_ITERATORS + public: + inline bool operator== ( const const_iterator& o ) const + { return i == o.i; } + inline bool operator!= ( const const_iterator& o ) const + { return i != o.i; } +#endif + friend class QQtOrderedMap; + }; + friend class iterator; + + class const_iterator + { + friend class iterator; + const Node* i; + + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef qptrdiff difference_type; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + + Q_DECL_CONSTEXPR inline const_iterator() : i ( Q_NULLPTR ) { } + inline const_iterator ( const Node* node ) : i ( node ) { } +#ifdef QT_STRICT_ITERATORS + explicit inline const_iterator ( const iterator& o ) +#else + inline const_iterator ( const iterator& o ) +#endif + { i = o.i; } + + inline const Key& key() const { return i->key; } + inline const T& value() const { return i->value; } + inline const T& operator*() const { return i->value; } + inline const T* operator->() const { return &i->value; } + Q_DECL_CONSTEXPR inline bool operator== ( const const_iterator& o ) const { return i == o.i; } + Q_DECL_CONSTEXPR inline bool operator!= ( const const_iterator& o ) const { return i != o.i; } + + inline const_iterator& operator++() { + i = i->nextNode(); + return *this; + } + inline const_iterator operator++ ( int ) { + const_iterator r = *this; + i = i->nextNode(); + return r; + } + inline const_iterator& operator--() { + i = i->previousNode(); + return *this; + } + inline const_iterator operator-- ( int ) { + const_iterator r = *this; + i = i->previousNode(); + return r; + } + inline const_iterator operator+ ( int j ) const + { const_iterator r = *this; if ( j > 0 ) while ( j-- ) ++r; else while ( j++ ) --r; return r; } + inline const_iterator operator- ( int j ) const { return operator+ ( -j ); } + inline const_iterator& operator+= ( int j ) { return *this = *this + j; } + inline const_iterator& operator-= ( int j ) { return *this = *this - j; } + +#ifdef QT_STRICT_ITERATORS + private: + inline bool operator== ( const iterator& o ) const { return operator== ( const_iterator ( o ) ); } + inline bool operator!= ( const iterator& o ) const { return operator!= ( const_iterator ( o ) ); } +#endif + friend class QQtOrderedMap; + }; + friend class const_iterator; + + class key_iterator + { + const_iterator i; + + public: + typedef typename const_iterator::iterator_category iterator_category; + typedef typename const_iterator::difference_type difference_type; + typedef Key value_type; + typedef const Key* pointer; + typedef const Key& reference; + + key_iterator() = default; + explicit key_iterator ( const_iterator o ) : i ( o ) { } + + const Key& operator*() const { return i.key(); } + const Key* operator->() const { return &i.key(); } + bool operator== ( key_iterator o ) const { return i == o.i; } + bool operator!= ( key_iterator o ) const { return i != o.i; } + + inline key_iterator& operator++() { ++i; return *this; } + inline key_iterator operator++ ( int ) { return key_iterator ( i++ );} + inline key_iterator& operator--() { --i; return *this; } + inline key_iterator operator-- ( int ) { return key_iterator ( i-- ); } + const_iterator base() const { return i; } + }; + + + // STL style + inline iterator begin() { detach(); return iterator ( d->begin() ); } + inline const_iterator begin() const { return const_iterator ( d->begin() ); } + inline const_iterator constBegin() const { return const_iterator ( d->begin() ); } + inline const_iterator cbegin() const { return const_iterator ( d->begin() ); } + inline iterator end() { detach(); return iterator ( d->end() ); } + inline const_iterator end() const { return const_iterator ( d->end() ); } + inline const_iterator constEnd() const { return const_iterator ( d->end() ); } + inline const_iterator cend() const { return const_iterator ( d->end() ); } + inline key_iterator keyBegin() const { return key_iterator ( begin() ); } + inline key_iterator keyEnd() const { return key_iterator ( end() ); } + iterator erase ( iterator it ); + + // more Qt + typedef iterator Iterator; + typedef const_iterator ConstIterator; + inline int count() const { return d->size; } + iterator find ( const Key& key ); + const_iterator find ( const Key& key ) const; + const_iterator constFind ( const Key& key ) const; + iterator lowerBound ( const Key& key ); + const_iterator lowerBound ( const Key& key ) const; + iterator upperBound ( const Key& key ); + const_iterator upperBound ( const Key& key ) const; + iterator insert ( const Key& key, const T& value ); + iterator insert ( const_iterator pos, const Key& key, const T& value ); + iterator insertMulti ( const Key& key, const T& value ); + iterator insertMulti ( const_iterator pos, const Key& akey, const T& avalue ); + QQtOrderedMap& unite ( const QQtOrderedMap& other ); + + // STL compatibility + typedef Key key_type; + typedef T mapped_type; + typedef qptrdiff difference_type; + typedef int size_type; + inline bool empty() const { return isEmpty(); } + QPair equal_range ( const Key& akey ); + QPair equal_range ( const Key& akey ) const; + +#ifdef Q_MAP_DEBUG + void dump() const; +#endif + +private: + void detach_helper(); + bool isValidIterator ( const const_iterator& ci ) const { +#if defined(QT_DEBUG) && !defined(Q_MAP_NO_ITERATOR_DEBUG) + const QQtOrderedMapNodeBase* n = ci.i; + while ( n->parent() ) + n = n->parent(); + return n->left == d->root(); +#else + Q_UNUSED ( ci ); + return true; +#endif + } +}; + +template +inline QQtOrderedMap::QQtOrderedMap ( const QQtOrderedMap& other ) +{ + if ( other.d->ref.ref() ) + { + d = other.d; + } + else + { + d = QQtOrderedMapData::create(); + if ( other.d->header.left ) + { + d->header.left = static_cast ( other.d->header.left )->copy ( d ); + d->header.left->setParent ( &d->header ); + d->recalcMostLeftNode(); + } + } +} + +template +Q_INLINE_TEMPLATE QQtOrderedMap& QQtOrderedMap::operator= ( const QQtOrderedMap& other ) +{ + if ( d != other.d ) + { + QQtOrderedMap tmp ( other ); + tmp.swap ( *this ); + } + return *this; +} + +template +Q_INLINE_TEMPLATE void QQtOrderedMap::clear() +{ + *this = QQtOrderedMap(); +} + +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG ( "-Wreturn-stack-address" ) + +template +Q_INLINE_TEMPLATE const T QQtOrderedMap::value ( const Key& akey, const T& adefaultValue ) const +{ + Node* n = d->findNode ( akey ); + return n ? n->value : adefaultValue; +} + +QT_WARNING_POP + +template +Q_INLINE_TEMPLATE const T QQtOrderedMap::operator[] ( const Key& akey ) const +{ + return value ( akey ); +} + +template +Q_INLINE_TEMPLATE T& QQtOrderedMap::operator[] ( const Key& akey ) +{ + detach(); + Node* n = d->findNode ( akey ); + if ( !n ) + return *insert ( akey, T() ); + return n->value; +} + +template +Q_INLINE_TEMPLATE int QQtOrderedMap::count ( const Key& akey ) const +{ + Node* firstNode; + Node* lastNode; + d->nodeRange ( akey, &firstNode, &lastNode ); + + const_iterator ci_first ( firstNode ); + const const_iterator ci_last ( lastNode ); + int cnt = 0; + while ( ci_first != ci_last ) + { + ++cnt; + ++ci_first; + } + return cnt; +} + +template +Q_INLINE_TEMPLATE bool QQtOrderedMap::contains ( const Key& akey ) const +{ + return d->findNode ( akey ) != Q_NULLPTR; +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::insert ( const Key& akey, const T& avalue ) +{ + detach(); + Node* n = d->root(); + Node* y = d->end(); + Node* lastNode = Q_NULLPTR; + bool left = true; + while ( n ) + { + y = n; + if ( !QQtOrderedMapLessThanKey ( n->key, akey ) ) + { + lastNode = n; + left = true; + n = n->leftNode(); + } + else + { + left = false; + n = n->rightNode(); + } + } + if ( lastNode && !QQtOrderedMapLessThanKey ( akey, lastNode->key ) ) + { + lastNode->value = avalue; + return iterator ( lastNode ); + } + Node* z = d->createNode ( akey, avalue, y, left ); + return iterator ( z ); +} + +template +typename QQtOrderedMap::iterator QQtOrderedMap::insert ( const_iterator pos, const Key& akey, const T& avalue ) +{ + if ( d->ref.isShared() ) + return this->insert ( akey, avalue ); + + Q_ASSERT_X ( isValidIterator ( pos ), "QQtOrderedMap::insert", "The specified const_iterator argument 'it' is invalid" ); + + if ( pos == constEnd() ) + { + // Hint is that the Node is larger than (or equal to) the largest value. + Node* n = static_cast ( pos.i->left ); + if ( n ) + { + while ( n->right ) + n = static_cast ( n->right ); + + if ( !QQtOrderedMapLessThanKey ( n->key, akey ) ) + return this->insert ( akey, avalue ); // ignore hint + // This can be optimized by checking equal too. + // we can overwrite if previous node key is strictly smaller + // (or there is no previous node) + + Node* z = d->createNode ( akey, avalue, n, false ); // insert right most + return iterator ( z ); + } + return this->insert ( akey, avalue ); + } + else + { + // Hint indicates that the node should be less (or equal to) the hint given + // but larger than the previous value. + Node* next = const_cast ( pos.i ); + if ( QQtOrderedMapLessThanKey ( next->key, akey ) ) + return this->insert ( akey, avalue ); // ignore hint + + if ( pos == constBegin() ) + { + // There is no previous value + // Maybe overwrite left most value + if ( !QQtOrderedMapLessThanKey ( akey, next->key ) ) + { + next->value = avalue; // overwrite current iterator + return iterator ( next ); + } + // insert left most. + Node* z = d->createNode ( akey, avalue, begin().i, true ); + return iterator ( z ); + } + else + { + Node* prev = const_cast ( pos.i->previousNode() ); + if ( !QQtOrderedMapLessThanKey ( prev->key, akey ) ) + { + return this->insert ( akey, avalue ); // ignore hint + } + // Hint is ok + if ( !QQtOrderedMapLessThanKey ( akey, next->key ) ) + { + next->value = avalue; // overwrite current iterator + return iterator ( next ); + } + + // we need to insert (not overwrite) + if ( prev->right == Q_NULLPTR ) + { + Node* z = d->createNode ( akey, avalue, prev, false ); + return iterator ( z ); + } + if ( next->left == Q_NULLPTR ) + { + Node* z = d->createNode ( akey, avalue, next, true ); + return iterator ( z ); + } + Q_ASSERT ( false ); // We should have prev->right == Q_NULLPTR or next->left == Q_NULLPTR. + return this->insert ( akey, avalue ); + } + } +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::insertMulti ( const Key& akey, + const T& avalue ) +{ + detach(); + Node* y = d->end(); + Node* x = static_cast ( d->root() ); + bool left = true; + while ( x != Q_NULLPTR ) + { + left = !QQtOrderedMapLessThanKey ( x->key, akey ); + y = x; + x = left ? x->leftNode() : x->rightNode(); + } + Node* z = d->createNode ( akey, avalue, y, left ); + return iterator ( z ); +} + +template +typename QQtOrderedMap::iterator QQtOrderedMap::insertMulti ( const_iterator pos, const Key& akey, const T& avalue ) +{ + if ( d->ref.isShared() ) + return this->insertMulti ( akey, avalue ); + + Q_ASSERT_X ( isValidIterator ( pos ), "QQtOrderedMap::insertMulti", "The specified const_iterator argument 'pos' is invalid" ); + + if ( pos == constEnd() ) + { + // Hint is that the Node is larger than (or equal to) the largest value. + Node* n = static_cast ( pos.i->left ); + if ( n ) + { + while ( n->right ) + n = static_cast ( n->right ); + + if ( !QQtOrderedMapLessThanKey ( n->key, akey ) ) + return this->insertMulti ( akey, avalue ); // ignore hint + Node* z = d->createNode ( akey, avalue, n, false ); // insert right most + return iterator ( z ); + } + return this->insertMulti ( akey, avalue ); + } + else + { + // Hint indicates that the node should be less (or equal to) the hint given + // but larger than the previous value. + Node* next = const_cast ( pos.i ); + if ( QQtOrderedMapLessThanKey ( next->key, akey ) ) + return this->insertMulti ( akey, avalue ); // ignore hint + + if ( pos == constBegin() ) + { + // There is no previous value (insert left most) + Node* z = d->createNode ( akey, avalue, begin().i, true ); + return iterator ( z ); + } + else + { + Node* prev = const_cast ( pos.i->previousNode() ); + if ( !QQtOrderedMapLessThanKey ( prev->key, akey ) ) + return this->insertMulti ( akey, avalue ); // ignore hint + + // Hint is ok - do insert + if ( prev->right == Q_NULLPTR ) + { + Node* z = d->createNode ( akey, avalue, prev, false ); + return iterator ( z ); + } + if ( next->left == Q_NULLPTR ) + { + Node* z = d->createNode ( akey, avalue, next, true ); + return iterator ( z ); + } + Q_ASSERT ( false ); // We should have prev->right == Q_NULLPTR or next->left == Q_NULLPTR. + return this->insertMulti ( akey, avalue ); + } + } +} + + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::const_iterator QQtOrderedMap::constFind ( const Key& akey ) const +{ + Node* n = d->findNode ( akey ); + return const_iterator ( n ? n : d->end() ); +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::const_iterator QQtOrderedMap::find ( const Key& akey ) const +{ + return constFind ( akey ); +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::find ( const Key& akey ) +{ + detach(); + Node* n = d->findNode ( akey ); + return iterator ( n ? n : d->end() ); +} + +template +Q_INLINE_TEMPLATE QQtOrderedMap& QQtOrderedMap::unite ( const QQtOrderedMap& other ) +{ + QQtOrderedMap copy ( other ); + const_iterator it = copy.constEnd(); + const const_iterator b = copy.constBegin(); + while ( it != b ) + { + --it; + insertMulti ( it.key(), it.value() ); + } + return *this; +} + +template +QPair::iterator, typename QQtOrderedMap::iterator> QQtOrderedMap::equal_range ( const Key& akey ) +{ + detach(); + Node* firstNode, *lastNode; + d->nodeRange ( akey, &firstNode, &lastNode ); + return QPair ( iterator ( firstNode ), iterator ( lastNode ) ); +} + +template +QPair::const_iterator, typename QQtOrderedMap::const_iterator> +QQtOrderedMap::equal_range ( const Key& akey ) const +{ + Node* firstNode, *lastNode; + d->nodeRange ( akey, &firstNode, &lastNode ); + return qMakePair ( const_iterator ( firstNode ), const_iterator ( lastNode ) ); +} + +#ifdef Q_MAP_DEBUG +template +void QQtOrderedMap::dump() const +{ + const_iterator it = begin(); + qDebug ( "map dump:" ); + while ( it != end() ) + { + const QQtOrderedMapNodeBase* n = it.i; + int depth = 0; + while ( n && n != d->root() ) + { + ++depth; + n = n->parent(); + } + QByteArray space ( 4 * depth, ' ' ); + qDebug() << space << ( it.i->color() == Node::Red ? "Red " : "Black" ) << it.i << it.i->left << it.i->right + << it.key() << it.value(); + ++it; + } + qDebug ( "---------" ); +} +#endif + +template +Q_OUTOFLINE_TEMPLATE int QQtOrderedMap::remove ( const Key& akey ) +{ + detach(); + int n = 0; + while ( Node* node = d->findNode ( akey ) ) + { + d->deleteNode ( node ); + ++n; + } + return n; +} + +template +Q_OUTOFLINE_TEMPLATE T QQtOrderedMap::take ( const Key& akey ) +{ + detach(); + + Node* node = d->findNode ( akey ); + if ( node ) + { + T t = node->value; + d->deleteNode ( node ); + return t; + } + return T(); +} + +template +Q_OUTOFLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::erase ( iterator it ) +{ + if ( it == iterator ( d->end() ) ) + return it; + + Q_ASSERT_X ( isValidIterator ( const_iterator ( it ) ), "QQtOrderedMap::erase", "The specified iterator argument 'it' is invalid" ); + + if ( d->ref.isShared() ) + { + const_iterator oldBegin = constBegin(); + const_iterator old = const_iterator ( it ); + int backStepsWithSameKey = 0; + + while ( old != oldBegin ) + { + --old; + if ( QQtOrderedMapLessThanKey ( old.key(), it.key() ) ) + break; + ++backStepsWithSameKey; + } + + it = find ( old.key() ); // ensures detach + Q_ASSERT_X ( it != iterator ( d->end() ), "QQtOrderedMap::erase", "Unable to locate same key in erase after detach." ); + + while ( backStepsWithSameKey > 0 ) + { + ++it; + --backStepsWithSameKey; + } + } + + Node* n = it.i; + ++it; + d->deleteNode ( n ); + return it; +} + +template +Q_OUTOFLINE_TEMPLATE void QQtOrderedMap::detach_helper() +{ + QQtOrderedMapData* x = QQtOrderedMapData::create(); + if ( d->header.left ) + { + x->header.left = static_cast ( d->header.left )->copy ( x ); + x->header.left->setParent ( &x->header ); + } + if ( !d->ref.deref() ) + d->destroy(); + d = x; + d->recalcMostLeftNode(); +} + +template +Q_OUTOFLINE_TEMPLATE QList QQtOrderedMap::uniqueKeys() const +{ + QList res; + res.reserve ( size() ); // May be too much, but assume short lifetime + const_iterator i = begin(); + if ( i != end() ) + { + for ( ;; ) + { + const Key& aKey = i.key(); + res.append ( aKey ); + do + { + if ( ++i == end() ) + goto break_out_of_outer_loop; + } while ( !QQtOrderedMapLessThanKey ( aKey, i.key() ) ); // loop while (key == i.key()) + } + } +break_out_of_outer_loop: + return res; +} + +template +Q_OUTOFLINE_TEMPLATE QList QQtOrderedMap::keys() const +{ + QList res; + res.reserve ( size() ); + const_iterator i = begin(); + while ( i != end() ) + { + res.append ( i.key() ); + ++i; + } + return res; +} + +template +Q_OUTOFLINE_TEMPLATE QList QQtOrderedMap::keys ( const T& avalue ) const +{ + QList res; + const_iterator i = begin(); + while ( i != end() ) + { + if ( i.value() == avalue ) + res.append ( i.key() ); + ++i; + } + return res; +} + +template +Q_OUTOFLINE_TEMPLATE const Key QQtOrderedMap::key ( const T& avalue, const Key& defaultKey ) const +{ + const_iterator i = begin(); + while ( i != end() ) + { + if ( i.value() == avalue ) + return i.key(); + ++i; + } + + return defaultKey; +} + +template +Q_OUTOFLINE_TEMPLATE QList QQtOrderedMap::values() const +{ + QList res; + res.reserve ( size() ); + const_iterator i = begin(); + while ( i != end() ) + { + res.append ( i.value() ); + ++i; + } + return res; +} + +template +Q_OUTOFLINE_TEMPLATE QList QQtOrderedMap::values ( const Key& akey ) const +{ + QList res; + Node* n = d->findNode ( akey ); + if ( n ) + { + const_iterator it ( n ); + do + { + res.append ( *it ); + ++it; + } while ( it != constEnd() && !QQtOrderedMapLessThanKey ( akey, it.key() ) ); + } + return res; +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::const_iterator QQtOrderedMap::lowerBound ( const Key& akey ) const +{ + Node* lb = d->root() ? d->root()->lowerBound ( akey ) : Q_NULLPTR; + if ( !lb ) + lb = d->end(); + return const_iterator ( lb ); +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::lowerBound ( const Key& akey ) +{ + detach(); + Node* lb = d->root() ? d->root()->lowerBound ( akey ) : Q_NULLPTR; + if ( !lb ) + lb = d->end(); + return iterator ( lb ); +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::const_iterator +QQtOrderedMap::upperBound ( const Key& akey ) const +{ + Node* ub = d->root() ? d->root()->upperBound ( akey ) : Q_NULLPTR; + if ( !ub ) + ub = d->end(); + return const_iterator ( ub ); +} + +template +Q_INLINE_TEMPLATE typename QQtOrderedMap::iterator QQtOrderedMap::upperBound ( const Key& akey ) +{ + detach(); + Node* ub = d->root() ? d->root()->upperBound ( akey ) : Q_NULLPTR; + if ( !ub ) + ub = d->end(); + return iterator ( ub ); +} + +template +Q_OUTOFLINE_TEMPLATE bool QQtOrderedMap::operator== ( const QQtOrderedMap& other ) const +{ + if ( size() != other.size() ) + return false; + if ( d == other.d ) + return true; + + const_iterator it1 = begin(); + const_iterator it2 = other.begin(); + + while ( it1 != end() ) + { + if ( ! ( it1.value() == it2.value() ) || QQtOrderedMapLessThanKey ( it1.key(), it2.key() ) || QQtOrderedMapLessThanKey ( it2.key(), it1.key() ) ) + return false; + ++it2; + ++it1; + } + return true; +} + +template +Q_OUTOFLINE_TEMPLATE QQtOrderedMap::QQtOrderedMap ( const std::map& other ) +{ + d = QQtOrderedMapData::create(); + typename std::map::const_iterator it = other.end(); + while ( it != other.begin() ) + { + --it; + d->createNode ( ( *it ).first, ( *it ).second, d->begin(), true ); // insert on most left node. + } +} + +template +Q_OUTOFLINE_TEMPLATE std::map QQtOrderedMap::toStdMap() const +{ + std::map map; + const_iterator it = end(); + while ( it != begin() ) + { + --it; + map.insert ( map.begin(), std::pair ( it.key(), it.value() ) ); + } + return map; +} + +template +class QQtOrderedMultiMap : public QQtOrderedMap +{ +public: + QQtOrderedMultiMap() Q_DECL_NOTHROW {} +#ifdef Q_COMPILER_INITIALIZER_LISTS + inline QQtOrderedMultiMap ( std::initializer_list > list ) { + for ( typename std::initializer_list >::const_iterator it = list.begin(); it != list.end(); ++it ) + insert ( it->first, it->second ); + } +#endif + QQtOrderedMultiMap ( const QQtOrderedMap& other ) : QQtOrderedMap ( other ) {} +#ifdef Q_COMPILER_RVALUE_REFS +QQtOrderedMultiMap ( QQtOrderedMap&& other ) Q_DECL_NOTHROW : QQtOrderedMap ( std::move ( other ) ) {} +#endif + void swap ( QQtOrderedMultiMap& other ) Q_DECL_NOTHROW { QQtOrderedMap::swap ( other ); } + + inline typename QQtOrderedMap::iterator replace ( const Key& key, const T& value ) + { return QQtOrderedMap::insert ( key, value ); } + inline typename QQtOrderedMap::iterator insert ( const Key& key, const T& value ) + { return QQtOrderedMap::insertMulti ( key, value ); } + inline typename QQtOrderedMap::iterator insert ( typename QQtOrderedMap::const_iterator pos, const Key& key, const T& value ) + { return QQtOrderedMap::insertMulti ( pos, key, value ); } + + inline QQtOrderedMultiMap& operator+= ( const QQtOrderedMultiMap& other ) + { this->unite ( other ); return *this; } + inline QQtOrderedMultiMap operator+ ( const QQtOrderedMultiMap& other ) const + { QQtOrderedMultiMap result = *this; result += other; return result; } + + using QQtOrderedMap::contains; + using QQtOrderedMap::remove; + using QQtOrderedMap::count; + using QQtOrderedMap::find; + using QQtOrderedMap::constFind; + + bool contains ( const Key& key, const T& value ) const; + + int remove ( const Key& key, const T& value ); + + int count ( const Key& key, const T& value ) const; + + typename QQtOrderedMap::iterator find ( const Key& key, const T& value ) { + typename QQtOrderedMap::iterator i ( find ( key ) ); + typename QQtOrderedMap::iterator end ( this->end() ); + while ( i != end && !QQtOrderedMapLessThanKey ( key, i.key() ) ) { + if ( i.value() == value ) + return i; + ++i; + } + return end; + } + typename QQtOrderedMap::const_iterator find ( const Key& key, const T& value ) const { + typename QQtOrderedMap::const_iterator i ( constFind ( key ) ); + typename QQtOrderedMap::const_iterator end ( QQtOrderedMap::constEnd() ); + while ( i != end && !QQtOrderedMapLessThanKey ( key, i.key() ) ) { + if ( i.value() == value ) + return i; + ++i; + } + return end; + } + typename QQtOrderedMap::const_iterator constFind ( const Key& key, const T& value ) const + { return find ( key, value ); } +private: + T& operator[] ( const Key& key ); + const T operator[] ( const Key& key ) const; +}; + +template +Q_INLINE_TEMPLATE bool QQtOrderedMultiMap::contains ( const Key& key, const T& value ) const +{ + return constFind ( key, value ) != QQtOrderedMap::constEnd(); +} + +template +Q_INLINE_TEMPLATE int QQtOrderedMultiMap::remove ( const Key& key, const T& value ) +{ + int n = 0; + typename QQtOrderedMap::iterator i ( find ( key ) ); + typename QQtOrderedMap::iterator end ( QQtOrderedMap::end() ); + while ( i != end && !QQtOrderedMapLessThanKey ( key, i.key() ) ) + { + if ( i.value() == value ) + { + i = this->erase ( i ); + ++n; + } + else + { + ++i; + } + } + return n; +} + +template +Q_INLINE_TEMPLATE int QQtOrderedMultiMap::count ( const Key& key, const T& value ) const +{ + int n = 0; + typename QQtOrderedMap::const_iterator i ( constFind ( key ) ); + typename QQtOrderedMap::const_iterator end ( QQtOrderedMap::constEnd() ); + while ( i != end && !QQtOrderedMapLessThanKey ( key, i.key() ) ) + { + if ( i.value() == value ) + ++n; + ++i; + } + return n; +} + +Q_DECLARE_ASSOCIATIVE_ITERATOR ( QtOrderedMap ) +Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR ( QtOrderedMap ) + +#endif // QQTORDEREDMAP_H diff --git a/src/qqt_source.pri b/src/qqt_source.pri index 0f5cbb88..1c8b1245 100644 --- a/src/qqt_source.pri +++ b/src/qqt_source.pri @@ -36,10 +36,12 @@ contains (DEFINES, __WIN__) { #core SOURCES += \ $$PWD/core/qqtcore.cpp \ + $$PWD/core/qqtorderedmap.cpp \ $$PWD/core/qqtdictionary.cpp \ $$PWD/core/qqtobjectmanager.cpp HEADERS += \ $$PWD/core/qqtcore.h \ + $$PWD/core/qqtorderedmap.h \ $$PWD/core/qqtdictionary.h \ $$PWD/core/qqtobjectmanager.h