diff --git a/libs/image/tiles3/kis_tile_hash_table2.h b/libs/image/tiles3/kis_tile_hash_table2.h index 06c59338fe..f8d10fec2a 100644 --- a/libs/image/tiles3/kis_tile_hash_table2.h +++ b/libs/image/tiles3/kis_tile_hash_table2.h @@ -1,378 +1,379 @@ #ifndef KIS_TILEHASHTABLE_2_H #define KIS_TILEHASHTABLE_2_H #include "kis_shared.h" #include "kis_shared_ptr.h" #include "3rdparty/lock_free_map/concurrent_map.h" #include "kis_lockless_stack.h" #include "kis_tile.h" #include template class KisTileHashTableTraits2 { static constexpr bool isInherited = std::is_convertible::value; Q_STATIC_ASSERT_X(isInherited, "Template must inherit KisShared"); public: typedef T TileType; typedef KisSharedPtr TileTypeSP; typedef KisWeakSharedPtr TileTypeWSP; KisTileHashTableTraits2(); KisTileHashTableTraits2(KisMementoManager *mm); KisTileHashTableTraits2(const KisTileHashTableTraits2 &ht, KisMementoManager *mm); ~KisTileHashTableTraits2(); TileTypeSP insert(quint32 key, TileTypeSP value) { TileTypeSP::ref(&value, value.data()); TileTypeSP result = m_map.assign(key, value.data()); if (result.data()) { m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result.data())); } else { m_numTiles.fetchAndAddRelaxed(1); } if (!m_map.migrationInProcess()) { m_map.getGC().update(); } return result; } TileTypeSP erase(quint32 key) { TileTypeSP result = m_map.erase(key); if (result) { m_numTiles.fetchAndSubRelaxed(1); m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result.data())); } if (!m_map.migrationInProcess()) { m_map.getGC().update(); } return result; } TileTypeSP get(quint32 key) { TileTypeSP result(m_map.get(key)); if (!m_map.migrationInProcess()) { m_map.getGC().update(); } return result; } bool isEmpty() { return !m_numTiles.load(); } bool tileExists(qint32 col, qint32 row); /** * Returns a tile in position (col,row). If no tile exists, * returns null. * \param col column of the tile * \param row row of the tile */ TileTypeSP getExistingTile(qint32 col, qint32 row); /** * Returns a tile in position (col,row). If no tile exists, * creates a new one, attaches it to the list and returns. * \param col column of the tile * \param row row of the tile * \param newTile out-parameter, returns true if a new tile * was created */ TileTypeSP getTileLazy(qint32 col, qint32 row, bool& newTile); /** * Returns a tile in position (col,row). If no tile exists, * creates nothing, but returns shared default tile object * of the table. Be careful, this object has column and row * parameters set to (qint32_MIN, qint32_MIN). * \param col column of the tile * \param row row of the tile * \param existingTile returns true if the tile actually exists in the table * and it is not a lazily created default wrapper tile */ TileTypeSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile); void addTile(TileTypeSP tile); bool deleteTile(TileTypeSP tile); bool deleteTile(qint32 col, qint32 row); void clear(); void setDefaultTileData(KisTileData *defaultTileData); KisTileData* defaultTileData(); qint32 numTiles() { return m_numTiles.load(); } void debugPrintInfo(); void debugMaxListLength(qint32 &min, qint32 &max); ConcurrentMap &map() { return m_map; } private: static inline quint32 calculateHash(qint32 col, qint32 row); struct MemoryReclaimer { MemoryReclaimer(TileType *data) : d(data) {} void destroy() { TileTypeSP::deref(reinterpret_cast(this), d); this->MemoryReclaimer::~MemoryReclaimer(); delete this; } private: TileType *d; }; private: ConcurrentMap m_map; QAtomicInt m_numTiles; QReadWriteLock m_rwLock; KisLocklessStack m_stack; KisTileData *m_defaultTileData; KisMementoManager *m_mementoManager; }; template class KisTileHashTableIteratorTraits2 { public: typedef T TileType; typedef KisSharedPtr TileTypeSP; typedef typename ConcurrentMap::Iterator Iterator; KisTileHashTableIteratorTraits2(KisTileHashTableTraits2 *ht) : m_ht(ht) { m_iter.setMap(m_ht->map()); } void next() { m_iter.next(); } TileTypeSP tile() const { return TileTypeSP(m_iter.getValue()); } bool isDone() const { return !m_iter.isValid(); } void deleteCurrent() { m_ht->erase(m_iter.getKey()); next(); } void moveCurrentToHashTable(KisTileHashTableTraits2 *newHashTable) { TileTypeSP tile = m_iter.getValue(); next(); m_ht->deleteTile(tile); newHashTable->addTile(tile); } private: KisTileHashTableTraits2 *m_ht; typename ConcurrentMap::Iterator m_iter; }; template KisTileHashTableTraits2::KisTileHashTableTraits2() : m_numTiles(0), m_rwLock(QReadWriteLock::NonRecursive), m_defaultTileData(0), m_mementoManager(0) { } template KisTileHashTableTraits2::KisTileHashTableTraits2(KisMementoManager *mm) : KisTileHashTableTraits2() { m_mementoManager = mm; } template KisTileHashTableTraits2::KisTileHashTableTraits2(const KisTileHashTableTraits2 &ht, KisMementoManager *mm) : KisTileHashTableTraits2(mm) { setDefaultTileData(ht.m_defaultTileData); typename ConcurrentMap::Iterator iter(const_cast &>(ht.m_map)); while (iter.isValid()) { insert(iter.getKey(), iter.getValue()); iter.next(); } } template KisTileHashTableTraits2::~KisTileHashTableTraits2() { clear(); m_map.getGC().flush(); + setDefaultTileData(0); } template bool KisTileHashTableTraits2::tileExists(qint32 col, qint32 row) { return get(calculateHash(col, row)) != nullptr; } template typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getExistingTile(qint32 col, qint32 row) { quint32 idx = calculateHash(col, row); return get(idx); } template typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getTileLazy(qint32 col, qint32 row, bool &newTile) { newTile = false; TileTypeSP tile; quint32 idx = calculateHash(col, row); typename ConcurrentMap::Mutator mutator = m_map.insertOrFind(idx); if (!mutator.getValue()) { { QReadLocker guard(&m_rwLock); tile = new TileType(col, row, m_defaultTileData, m_mementoManager); } TileTypeSP::ref(&tile, tile.data()); TileTypeSP result = mutator.exchangeValue(tile.data()); if (result.data()) { m_map.getGC().enqueue(&MemoryReclaimer::destroy, new MemoryReclaimer(result.data())); } else { m_numTiles.fetchAndAddRelaxed(1); } newTile = true; tile = m_map.get(idx); } else { tile = mutator.getValue(); } if (!m_map.migrationInProcess()) { m_map.getGC().update(); } return tile; } template typename KisTileHashTableTraits2::TileTypeSP KisTileHashTableTraits2::getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile) { quint32 idx = calculateHash(col, row); TileTypeSP tile(m_map.get(idx)); existingTile = tile; if (!existingTile) { QReadLocker guard(&m_rwLock); tile = new TileType(col, row, m_defaultTileData, 0); } if (!m_map.migrationInProcess()) { m_map.getGC().update(); } return tile; } template void KisTileHashTableTraits2::addTile(TileTypeSP tile) { quint32 idx = calculateHash(tile->col(), tile->row()); insert(idx, tile); } template bool KisTileHashTableTraits2::deleteTile(TileTypeSP tile) { return deleteTile(tile->col(), tile->row()); } template bool KisTileHashTableTraits2::deleteTile(qint32 col, qint32 row) { quint32 idx = calculateHash(col, row); return erase(idx) != 0; } template void KisTileHashTableTraits2::clear() { typename ConcurrentMap::Iterator iter(m_map); while (iter.isValid()) { erase(iter.getKey()); iter.next(); } } template inline void KisTileHashTableTraits2::setDefaultTileData(KisTileData *defaultTileData) { QWriteLocker guard(&m_rwLock); if (m_defaultTileData) { m_defaultTileData->release(); m_defaultTileData = 0; } if (defaultTileData) { defaultTileData->acquire(); m_defaultTileData = defaultTileData; } } template inline KisTileData* KisTileHashTableTraits2::defaultTileData() { QReadLocker guard(&m_rwLock); return m_defaultTileData; } template void KisTileHashTableTraits2::debugPrintInfo() { } template void KisTileHashTableTraits2::debugMaxListLength(qint32 &min, qint32 &max) { } template quint32 KisTileHashTableTraits2::calculateHash(qint32 col, qint32 row) { std::size_t seed = 0; boost::hash_combine(seed, col); boost::hash_combine(seed, row); return seed; } typedef KisTileHashTableTraits2 KisTileHashTable; typedef KisTileHashTableIteratorTraits2 KisTileHashTableIterator; typedef KisTileHashTableIteratorTraits2 KisTileHashTableConstIterator; #endif // KIS_TILEHASHTABLE_2_H