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
 | 
