612 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			612 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | #ifndef ORDEREDMAP_H
 | ||
|  | #define ORDEREDMAP_H
 | ||
|  | 
 | ||
|  | #include <QtGlobal>
 | ||
|  | #include <QHash>
 | ||
|  | #include <QLinkedList>
 | ||
|  | #include <QList>
 | ||
|  | #include <QPair>
 | ||
|  | 
 | ||
|  | template <typename Key> inline bool oMHashEqualToKey(const Key &key1, const Key &key2) | ||
|  | { | ||
|  |     // Key type must provide '==' operator
 | ||
|  |     return key1 == key2; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Ptr> inline bool oMHashEqualToKey(Ptr *key1, Ptr *key2) | ||
|  | { | ||
|  |     Q_ASSERT(sizeof(quintptr) == sizeof(Ptr *)); | ||
|  |     return quintptr(key1) == quintptr(key2); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Ptr> inline bool oMHashEqualToKey(const Ptr *key1, const Ptr *key2) | ||
|  | { | ||
|  |     Q_ASSERT(sizeof(quintptr) == sizeof(const Ptr *)); | ||
|  |     return quintptr(key1) == quintptr(key2); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | class OrderedMap | ||
|  | { | ||
|  |     class OMHash; | ||
|  | 
 | ||
|  |     typedef typename QLinkedList<Key>::iterator QllIterator; | ||
|  |     typedef typename QLinkedList<Key>::const_iterator QllConstIterator; | ||
|  |     typedef QPair<Value, QllIterator> OMHashValue; | ||
|  | 
 | ||
|  |     typedef typename OMHash::iterator OMHashIterator; | ||
|  |     typedef typename OMHash::const_iterator OMHashConstIterator; | ||
|  | 
 | ||
|  | public: | ||
|  | 
 | ||
|  |     class iterator; | ||
|  |     class const_iterator; | ||
|  | 
 | ||
|  |     typedef typename OrderedMap<Key, Value>::iterator Iterator; | ||
|  |     typedef typename OrderedMap<Key, Value>::const_iterator ConstIterator; | ||
|  | 
 | ||
|  |     explicit OrderedMap(); | ||
|  | 
 | ||
|  |     OrderedMap(const OrderedMap<Key, Value>& other); | ||
|  | 
 | ||
|  | #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
 | ||
|  |     OrderedMap(OrderedMap<Key, Value>&& other); | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     void clear(); | ||
|  | 
 | ||
|  |     bool contains(const Key &key) const; | ||
|  | 
 | ||
|  |     int count() const; | ||
|  | 
 | ||
|  |     bool empty() const; | ||
|  | 
 | ||
|  |     iterator insert(const Key &key, const Value &value); | ||
|  | 
 | ||
|  |     bool isEmpty() const; | ||
|  | 
 | ||
|  |     QList<Key> keys() const; | ||
|  | 
 | ||
|  |     int remove(const Key &key); | ||
|  | 
 | ||
|  |     int size() const; | ||
|  | 
 | ||
|  |     Value take(const Key &key); | ||
|  | 
 | ||
|  |     Value value(const Key &key) const; | ||
|  | 
 | ||
|  |     Value value(const Key &key, const Value &defaultValue) const; | ||
|  | 
 | ||
|  |     QList<Value> values() const; | ||
|  | 
 | ||
|  |     OrderedMap<Key, Value> & operator=(const OrderedMap<Key, Value>& other); | ||
|  | 
 | ||
|  | #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
 | ||
|  |     OrderedMap<Key, Value> & operator=(OrderedMap<Key, Value>&& other); | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     bool operator==(const OrderedMap<Key, Value> &other) const; | ||
|  | 
 | ||
|  |     bool operator!=(const OrderedMap<Key, Value> &other) const; | ||
|  | 
 | ||
|  |     Value& operator[](const Key &key); | ||
|  | 
 | ||
|  |     const Value operator[](const Key &key) const; | ||
|  | 
 | ||
|  |     iterator begin(); | ||
|  | 
 | ||
|  |     const_iterator begin() const; | ||
|  | 
 | ||
|  |     iterator end(); | ||
|  | 
 | ||
|  |     const_iterator end() const; | ||
|  | 
 | ||
|  |     iterator erase(iterator pos); | ||
|  | 
 | ||
|  |     iterator find(const Key& key); | ||
|  | 
 | ||
|  |     const_iterator find(const Key& key) const; | ||
|  | 
 | ||
|  |     class const_iterator; | ||
|  | 
 | ||
|  |     class iterator | ||
|  |     { | ||
|  |         QllIterator qllIter; | ||
|  |         OMHash *data; | ||
|  |         friend class const_iterator; | ||
|  |         friend class OrderedMap; | ||
|  | 
 | ||
|  |     public: | ||
|  |         iterator() : data(NULL) {} | ||
|  | 
 | ||
|  |         iterator(const QllIterator &qllIter, OMHash *data) : | ||
|  |             qllIter(qllIter), data(data) {} | ||
|  | 
 | ||
|  |         const Key & key() const | ||
|  |         { | ||
|  |             return *qllIter; | ||
|  |         } | ||
|  | 
 | ||
|  |         Value & value() const | ||
|  |         { | ||
|  |             OMHashIterator hit = data->find(*qllIter); | ||
|  |             OMHashValue &pair = hit.value(); | ||
|  |             return pair.first; | ||
|  |         } | ||
|  | 
 | ||
|  |         Value & operator*() const | ||
|  |         { | ||
|  |             return value(); | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator operator+(int i) const | ||
|  |         { | ||
|  |             QllIterator q = qllIter; | ||
|  |             q += i; | ||
|  | 
 | ||
|  |             return iterator(q, data); | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator operator-(int i) const | ||
|  |         { | ||
|  |             return operator +(- i); | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator& operator+=(int i) | ||
|  |         { | ||
|  |             qllIter += i; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator& operator-=(int i) | ||
|  |         { | ||
|  |             qllIter -= i; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator& operator++() | ||
|  |         { | ||
|  |             ++qllIter; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator operator++(int) | ||
|  |         { | ||
|  |             iterator it = *this; | ||
|  |             qllIter++; | ||
|  |             return it; | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator operator--() | ||
|  |         { | ||
|  |             --qllIter; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         iterator operator--(int) | ||
|  |         { | ||
|  |             iterator it = *this; | ||
|  |             qllIter--; | ||
|  |             return it; | ||
|  |         } | ||
|  | 
 | ||
|  |         bool operator ==(const iterator &other) const | ||
|  |         { | ||
|  |             return (qllIter == other.qllIter); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool operator !=(const iterator &other) const | ||
|  |         { | ||
|  |             return (qllIter != other.qllIter); | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  |     class const_iterator | ||
|  |     { | ||
|  | 
 | ||
|  |         QllConstIterator qllConstIter; | ||
|  |         const OMHash *data; | ||
|  | 
 | ||
|  |     public: | ||
|  |         const_iterator() : data(NULL) {} | ||
|  | 
 | ||
|  |         const_iterator(const iterator &i) : | ||
|  |             qllConstIter(i.qllIter), data(i.data) {} | ||
|  | 
 | ||
|  |         const_iterator(const QllConstIterator &qllConstIter, const OMHash* data) : | ||
|  |             qllConstIter(qllConstIter), data(data) {} | ||
|  | 
 | ||
|  |         const Key & key() const | ||
|  |         { | ||
|  |             return *qllConstIter; | ||
|  |         } | ||
|  | 
 | ||
|  |         const Value & value() const | ||
|  |         { | ||
|  |             OMHashConstIterator hit = data->find(*qllConstIter); | ||
|  |             const OMHashValue &pair = hit.value(); | ||
|  |             return pair.first; | ||
|  |         } | ||
|  | 
 | ||
|  |         const Value & operator*() const | ||
|  |         { | ||
|  |             return value(); | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator operator+(int i) const | ||
|  |         { | ||
|  |             QllConstIterator q = qllConstIter; | ||
|  |             q += i; | ||
|  | 
 | ||
|  |             return const_iterator(q, data); | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator operator-(int i) const | ||
|  |         { | ||
|  |             return operator +(- i); | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator& operator+=(int i) | ||
|  |         { | ||
|  |             qllConstIter += i; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator& operator-=(int i) | ||
|  |         { | ||
|  |             qllConstIter -= i; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator& operator++() | ||
|  |         { | ||
|  |             ++qllConstIter; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator operator++(int) | ||
|  |         { | ||
|  |             const_iterator it = *this; | ||
|  |             qllConstIter++; | ||
|  |             return it; | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator operator--() | ||
|  |         { | ||
|  |             --qllConstIter; | ||
|  |             return *this; | ||
|  |         } | ||
|  | 
 | ||
|  |         const_iterator operator--(int) | ||
|  |         { | ||
|  |             const_iterator it = *this; | ||
|  |             qllConstIter--; | ||
|  |             return it; | ||
|  |         } | ||
|  | 
 | ||
|  |         bool operator ==(const const_iterator &other) const | ||
|  |         { | ||
|  |             return (qllConstIter == other.qllConstIter); | ||
|  |         } | ||
|  | 
 | ||
|  |         bool operator !=(const const_iterator &other) const | ||
|  |         { | ||
|  |             return (qllConstIter != other.qllConstIter); | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  | private: | ||
|  | 
 | ||
|  |     class OMHash : public QHash<Key, OMHashValue > | ||
|  |     { | ||
|  |     public: | ||
|  |         bool operator == (const OMHash &other) const | ||
|  |         { | ||
|  |             if (size() != other.size()) { | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (QHash<Key, OMHashValue >::operator ==(other)) { | ||
|  |                 return true; | ||
|  |             } | ||
|  | 
 | ||
|  |             typename QHash<Key, OMHashValue >::const_iterator it1 = this->constBegin(); | ||
|  |             typename QHash<Key, OMHashValue >::const_iterator it2 = other.constBegin(); | ||
|  | 
 | ||
|  |             while(it1 != this->end()) { | ||
|  |                 OMHashValue v1 = it1.value(); | ||
|  |                 OMHashValue v2 = it2.value(); | ||
|  | 
 | ||
|  |                 if ((v1.first != v2.first) || !oMHashEqualToKey<Key>(it1.key(), it2.key())) { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 ++it1; | ||
|  |                 ++it2; | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  | private: | ||
|  |     void copy(const OrderedMap<Key, Value> &other); | ||
|  | 
 | ||
|  |     OMHash data; | ||
|  |     QLinkedList<Key> insertOrder; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | OrderedMap<Key, Value>::OrderedMap() {} | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | OrderedMap<Key, Value>::OrderedMap(const OrderedMap<Key, Value>& other) | ||
|  | { | ||
|  |     copy(other); | ||
|  | } | ||
|  | 
 | ||
|  | #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
 | ||
|  | template <typename Key, typename Value> | ||
|  | OrderedMap<Key, Value>::OrderedMap(OrderedMap<Key, Value>&& other) | ||
|  | { | ||
|  |     data = std::move(other.data); | ||
|  |     insertOrder = std::move(other.insertOrder); | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | void OrderedMap<Key, Value>::clear() | ||
|  | { | ||
|  |     data.clear(); | ||
|  |     insertOrder.clear(); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | bool OrderedMap<Key, Value>::contains(const Key &key) const | ||
|  | { | ||
|  |     return data.contains(key); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | int OrderedMap<Key, Value>::count() const | ||
|  | { | ||
|  |     return data.count(); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | bool OrderedMap<Key, Value>::empty() const | ||
|  | { | ||
|  |     return data.empty(); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::insert(const Key &key, const Value &value) | ||
|  | { | ||
|  |     OMHashIterator it = data.find(key); | ||
|  | 
 | ||
|  |     if (it == data.end()) { | ||
|  |         // New key
 | ||
|  |         QllIterator ioIter = insertOrder.insert(insertOrder.end(), key); | ||
|  |         OMHashValue pair(value, ioIter); | ||
|  |         data.insert(key, pair); | ||
|  |         return iterator(ioIter, &data); | ||
|  |     } | ||
|  | 
 | ||
|  |     OMHashValue pair = it.value(); | ||
|  |     // remove old reference
 | ||
|  |     insertOrder.erase(pair.second); | ||
|  |     // Add new reference
 | ||
|  |     QllIterator ioIter = insertOrder.insert(insertOrder.end(), key); | ||
|  |     pair.first = value; | ||
|  |     pair.second = ioIter; | ||
|  |     return iterator(ioIter, &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | bool OrderedMap<Key, Value>::isEmpty() const | ||
|  | { | ||
|  |     return data.isEmpty(); | ||
|  | } | ||
|  | 
 | ||
|  | template<typename Key, typename Value> | ||
|  | QList<Key> OrderedMap<Key, Value>::keys() const | ||
|  | { | ||
|  |     return QList<Key>::fromStdList(insertOrder.toStdList()); | ||
|  | } | ||
|  | 
 | ||
|  | template<typename Key, typename Value> | ||
|  | int OrderedMap<Key, Value>::remove(const Key &key) | ||
|  | { | ||
|  |     OMHashIterator it = data.find(key); | ||
|  |     if (it == data.end()) { | ||
|  |         return 0; | ||
|  |     } | ||
|  |     OMHashValue pair = it.value(); | ||
|  |     insertOrder.erase(pair.second); | ||
|  |     data.erase(it); | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | template<typename Key, typename Value> | ||
|  | int OrderedMap<Key, Value>::size() const | ||
|  | { | ||
|  |     return data.size(); | ||
|  | } | ||
|  | 
 | ||
|  | template<typename Key, typename Value> | ||
|  | void OrderedMap<Key, Value>::copy(const OrderedMap<Key, Value> &other) | ||
|  | { | ||
|  |     /* Since I'm storing iterators of QLinkedList, I simply cannot make
 | ||
|  |      * a trivial copy of the linked list. This is a limitation due to implicit | ||
|  |      * sharing used in Qt containers, due to which iterator active on one | ||
|  |      * QLL can change the data of another QLL even after creating a copy. | ||
|  |      * | ||
|  |      * Because of this, the old iterators have to be invalidated and new ones | ||
|  |      * have to be generated. | ||
|  |      */ | ||
|  |     insertOrder.clear(); | ||
|  |     // Copy hash
 | ||
|  |     data = other.data; | ||
|  | 
 | ||
|  |     QllConstIterator cit = other.insertOrder.begin(); | ||
|  |     for (; cit != other.insertOrder.end(); ++cit) { | ||
|  |         Key key = *cit; | ||
|  |         QllIterator ioIter = insertOrder.insert(insertOrder.end(), key); | ||
|  |         OMHashIterator it = data.find(key); | ||
|  |         (*it).second = ioIter; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | template<typename Key, typename Value> | ||
|  | Value OrderedMap<Key, Value>::take(const Key &key) | ||
|  | { | ||
|  |     OMHashIterator it = data.find(key); | ||
|  |     if (it == data.end()) { | ||
|  |         return Value(); | ||
|  |     } | ||
|  |     OMHashValue pair = it.value(); | ||
|  |     insertOrder.erase(pair.second); | ||
|  |     data.erase(it); | ||
|  |     return pair.first; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | Value OrderedMap<Key, Value>::value(const Key &key) const | ||
|  | { | ||
|  |     return data.value(key).first; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | Value OrderedMap<Key, Value>::value(const Key &key, const Value &defaultValue) const | ||
|  | { | ||
|  |     OMHashConstIterator it = data.constFind(key); | ||
|  |     if (it == data.end()) { | ||
|  |         return defaultValue; | ||
|  |     } | ||
|  |     OMHashValue pair = it.value(); | ||
|  |     return pair.first; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | QList<Value> OrderedMap<Key, Value>::values() const | ||
|  | { | ||
|  |     QList<Value> values; | ||
|  |     foreach (const Key &key, insertOrder.toStdList()) { | ||
|  |         OMHashValue v = data.value(key); | ||
|  |         values.append(v.first); | ||
|  |     } | ||
|  |     return values; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | OrderedMap<Key, Value> & OrderedMap<Key, Value>::operator=(const OrderedMap<Key, Value>& other) | ||
|  | { | ||
|  |     if (this != &other) { | ||
|  |         copy(other); | ||
|  |     } | ||
|  |     return *this; | ||
|  | } | ||
|  | 
 | ||
|  | #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
 | ||
|  | template <typename Key, typename Value> | ||
|  | OrderedMap<Key, Value> & OrderedMap<Key, Value>::operator=(OrderedMap<Key, Value>&& other) | ||
|  | { | ||
|  |     if (this != &other) { | ||
|  |         data = other.data; | ||
|  |         insertOrder = other.insertOrder; | ||
|  |     } | ||
|  |     return *this; | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | bool OrderedMap<Key, Value>::operator==(const OrderedMap<Key, Value> &other) const | ||
|  | { | ||
|  |     // 2 Ordered maps are equal if they have the same contents in the same order
 | ||
|  |     return ((data == other.data) && (insertOrder == other.insertOrder)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | bool OrderedMap<Key, Value>::operator!=(const OrderedMap<Key, Value> &other) const | ||
|  | { | ||
|  |     return ((data != other.data) || (insertOrder != other.insertOrder)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | Value& OrderedMap<Key, Value>::operator[](const Key &key) | ||
|  | { | ||
|  |     OMHashIterator it = data.find(key); | ||
|  |     if (it == data.end()) { | ||
|  |         insert(key, Value()); | ||
|  |         it = data.find(key); | ||
|  |     } | ||
|  |     OMHashValue &pair = it.value(); | ||
|  |     return pair.first; | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | const Value OrderedMap<Key, Value>::operator[](const Key &key) const | ||
|  | { | ||
|  |     return value(key); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::begin() | ||
|  | { | ||
|  |     return iterator(insertOrder.begin(), &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::begin() const | ||
|  | { | ||
|  |     return const_iterator(insertOrder.begin(), &data); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::end() | ||
|  | { | ||
|  |     return iterator(insertOrder.end(), &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::end() const | ||
|  | { | ||
|  |     return const_iterator(insertOrder.end(), &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::erase(iterator pos) | ||
|  | { | ||
|  |     OMHashIterator hit = data.find(*(pos.qllIter)); | ||
|  |     if (hit == data.end()) { | ||
|  |         return pos; | ||
|  |     } | ||
|  |     data.erase(hit); | ||
|  |     QllIterator ioIter = insertOrder.erase(pos.qllIter); | ||
|  | 
 | ||
|  |     return iterator(ioIter, &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::find(const Key& key) | ||
|  | { | ||
|  |     OMHashIterator hit = data.find(key); | ||
|  |     if (hit == data.end()) { | ||
|  |         return end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     return iterator(hit.value().second, &data); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Key, typename Value> | ||
|  | typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::find(const Key& key) const | ||
|  | { | ||
|  |     OMHashConstIterator hit = data.find(key); | ||
|  |     if (hit == data.end()) { | ||
|  |         return end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     return const_iterator(hit.value().second, &data); | ||
|  | } | ||
|  | 
 | ||
|  | #endif // ORDEREDMAP_H
 |