File indexing completed on 2024-05-26 04:28:05
0001 /* 0002 * SPDX-FileCopyrightText: 2004 C. Boemann <cbo@boemann.dk> 0003 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef KIS_TILEHASHTABLE_H_ 0009 #define KIS_TILEHASHTABLE_H_ 0010 0011 #include "kis_tile.h" 0012 0013 0014 0015 /** 0016 * This is a template for a hash table that stores tiles (or some other 0017 * objects resembling tiles). Actually, this object should only have 0018 * col()/row() methods and be able to answer setNext()/next() requests to 0019 * be stored here. It is used in KisTiledDataManager and 0020 * KisMementoManager. 0021 */ 0022 0023 template<class T> 0024 class KisTileHashTableTraits 0025 { 0026 public: 0027 typedef T TileType; 0028 typedef KisSharedPtr<T> TileTypeSP; 0029 typedef KisWeakSharedPtr<T> TileTypeWSP; 0030 0031 KisTileHashTableTraits(KisMementoManager *mm); 0032 KisTileHashTableTraits(const KisTileHashTableTraits<T> &ht, 0033 KisMementoManager *mm); 0034 0035 /* virtual? */ 0036 ~KisTileHashTableTraits(); 0037 0038 bool isEmpty() { 0039 return !m_numTiles; 0040 } 0041 0042 bool tileExists(qint32 col, qint32 row); 0043 0044 /** 0045 * Returns a tile in position (col,row). If no tile exists, 0046 * returns null. 0047 * \param col column of the tile 0048 * \param row row of the tile 0049 */ 0050 TileTypeSP getExistingTile(qint32 col, qint32 row); 0051 0052 /** 0053 * Returns a tile in position (col,row). If no tile exists, 0054 * creates a new one, attaches it to the list and returns. 0055 * \param col column of the tile 0056 * \param row row of the tile 0057 * \param newTile out-parameter, returns true if a new tile 0058 * was created 0059 */ 0060 TileTypeSP getTileLazy(qint32 col, qint32 row, bool& newTile); 0061 0062 /** 0063 * Returns a tile in position (col,row). If no tile exists, 0064 * creates nothing, but returns shared default tile object 0065 * of the table. Be careful, this object has column and row 0066 * parameters set to (qint32_MIN, qint32_MIN). 0067 * \param col column of the tile 0068 * \param row row of the tile 0069 * \param existingTile returns true if the tile actually exists in the table 0070 * and it is not a lazily created default wrapper tile 0071 */ 0072 TileTypeSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile); 0073 void addTile(TileTypeSP tile); 0074 bool deleteTile(TileTypeSP tile); 0075 bool deleteTile(qint32 col, qint32 row); 0076 0077 void clear(); 0078 0079 void setDefaultTileData(KisTileData *defaultTileData); 0080 KisTileData* defaultTileData() const; 0081 KisTileData* refAndFetchDefaultTileData() const; 0082 0083 qint32 numTiles() { 0084 return m_numTiles; 0085 } 0086 0087 void debugPrintInfo(); 0088 void debugMaxListLength(qint32 &min, qint32 &max); 0089 0090 private: 0091 0092 TileTypeSP getTileMinefieldWalk(qint32 col, qint32 row, qint32 idx); 0093 TileTypeSP getTile(qint32 col, qint32 row, qint32 idx); 0094 void linkTile(TileTypeSP tile, qint32 idx); 0095 bool unlinkTile(qint32 col, qint32 row, qint32 idx); 0096 0097 inline void setDefaultTileDataImp(KisTileData *defaultTileData); 0098 inline KisTileData* defaultTileDataImp() const; 0099 0100 static inline quint32 calculateHash(qint32 col, qint32 row); 0101 0102 inline qint32 debugChainLen(qint32 idx); 0103 void debugListLengthDistribution(); 0104 void sanityChecksumCheck(); 0105 private: 0106 template<class U, class LockerType> friend class KisTileHashTableIteratorTraits; 0107 0108 static const qint32 TABLE_SIZE = 1024; 0109 TileTypeSP *m_hashTable; 0110 qint32 m_numTiles; 0111 0112 KisTileData *m_defaultTileData; 0113 KisMementoManager *m_mementoManager; 0114 0115 mutable QReadWriteLock m_lock; 0116 }; 0117 0118 #include "kis_tile_hash_table_p.h" 0119 0120 0121 0122 /** 0123 * Walks through all tiles inside hash table 0124 * Note: You can't work with your hash table in a regular way 0125 * during iterating with this iterator, because HT is locked. 0126 * The only thing you can do is to delete current tile. 0127 * 0128 * LockerType defines if the iterator is constant or mutable. One should 0129 * pass either QReadLocker or QWriteLocker as a parameter. 0130 */ 0131 template<class T, class LockerType> 0132 class KisTileHashTableIteratorTraits 0133 { 0134 public: 0135 typedef T TileType; 0136 typedef KisSharedPtr<T> TileTypeSP; 0137 0138 KisTileHashTableIteratorTraits(KisTileHashTableTraits<T> *ht) 0139 : m_locker(&ht->m_lock) 0140 { 0141 m_hashTable = ht; 0142 m_index = nextNonEmptyList(0); 0143 if (m_index < KisTileHashTableTraits<T>::TABLE_SIZE) 0144 m_tile = m_hashTable->m_hashTable[m_index]; 0145 } 0146 0147 ~KisTileHashTableIteratorTraits() { 0148 } 0149 0150 void next() { 0151 if (m_tile) { 0152 m_tile = m_tile->next(); 0153 if (!m_tile) { 0154 qint32 idx = nextNonEmptyList(m_index + 1); 0155 if (idx < KisTileHashTableTraits<T>::TABLE_SIZE) { 0156 m_index = idx; 0157 m_tile = m_hashTable->m_hashTable[idx]; 0158 } else { 0159 //EOList reached 0160 m_index = -1; 0161 // m_tile.clear(); // already null 0162 } 0163 } 0164 } 0165 } 0166 0167 TileTypeSP tile() const { 0168 return m_tile; 0169 } 0170 bool isDone() const { 0171 return !m_tile; 0172 } 0173 0174 // disable the method if we didn't lock for writing 0175 template <class Helper = LockerType> 0176 typename std::enable_if<std::is_same<Helper, QWriteLocker>::value, void>::type 0177 deleteCurrent() { 0178 TileTypeSP tile = m_tile; 0179 next(); 0180 0181 const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); 0182 m_hashTable->unlinkTile(tile->col(), tile->row(), idx); 0183 } 0184 0185 // disable the method if we didn't lock for writing 0186 template <class Helper = LockerType> 0187 typename std::enable_if<std::is_same<Helper, QWriteLocker>::value, void>::type 0188 moveCurrentToHashTable(KisTileHashTableTraits<T> *newHashTable) { 0189 TileTypeSP tile = m_tile; 0190 next(); 0191 0192 const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); 0193 m_hashTable->unlinkTile(tile->col(), tile->row(), idx); 0194 0195 newHashTable->addTile(tile); 0196 } 0197 0198 protected: 0199 TileTypeSP m_tile; 0200 qint32 m_index; 0201 KisTileHashTableTraits<T> *m_hashTable; 0202 LockerType m_locker; 0203 0204 protected: 0205 qint32 nextNonEmptyList(qint32 startIdx) { 0206 qint32 idx = startIdx; 0207 0208 while (idx < KisTileHashTableTraits<T>::TABLE_SIZE && 0209 !m_hashTable->m_hashTable[idx]) { 0210 idx++; 0211 } 0212 0213 return idx; 0214 } 0215 private: 0216 Q_DISABLE_COPY(KisTileHashTableIteratorTraits) 0217 }; 0218 0219 0220 typedef KisTileHashTableTraits<KisTile> KisTileHashTable; 0221 typedef KisTileHashTableIteratorTraits<KisTile, QWriteLocker> KisTileHashTableIterator; 0222 typedef KisTileHashTableIteratorTraits<KisTile, QReadLocker> KisTileHashTableConstIterator; 0223 0224 #endif /* KIS_TILEHASHTABLE_H_ */