Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tile_hash_table_p.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2004 C. Boemann <cbo@boemann.dk>
3 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include <QtGlobal>
9#include "kis_debug.h"
10#include "kis_global.h"
11
12//#define SHARED_TILES_SANITY_CHECK
13
14
15template<class T>
17 : m_lock(QReadWriteLock::NonRecursive)
18{
20 Q_CHECK_PTR(m_hashTable);
21
22 m_numTiles = 0;
25}
26
27template<class T>
30 : m_lock(QReadWriteLock::NonRecursive)
32 QReadLocker locker(&ht.m_lock);
33
34 m_mementoManager = mm;
35 m_defaultTileData = 0;
36 setDefaultTileDataImp(ht.m_defaultTileData);
37
38 m_hashTable = new TileTypeSP [TABLE_SIZE];
39 Q_CHECK_PTR(m_hashTable);
40
41
42 TileTypeSP foreignTile;
43 TileTypeSP nativeTile;
44 TileTypeSP nativeTileHead;
45 for (qint32 i = 0; i < TABLE_SIZE; i++) {
46 nativeTileHead = 0;
47
48 foreignTile = ht.m_hashTable[i];
49 while (foreignTile) {
50 nativeTile = TileTypeSP(new TileType(*foreignTile, m_mementoManager));
51 nativeTile->setNext(nativeTileHead);
52 nativeTileHead = nativeTile;
53
54 foreignTile = foreignTile->next();
55 }
56
57 m_hashTable[i] = nativeTileHead;
58 }
59 m_numTiles = ht.m_numTiles;
61
62template<class T>
64{
65 clear();
66 delete[] m_hashTable;
67 setDefaultTileDataImp(0);
68}
69
70template<class T>
71quint32 KisTileHashTableTraits<T>::calculateHash(qint32 col, qint32 row)
73 return ((row << 5) + (col & 0x1F)) & 0x3FF;
76template<class T>
78KisTileHashTableTraits<T>::getTileMinefieldWalk(qint32 col, qint32 row, qint32 idx)
80 // WARNING: this function is here only for educational purposes! Don't
81 // use it! It causes race condition in a shared pointer copy-ctor
82 // when accessing m_hashTable!
83
93 TileTypeSP headTile = m_hashTable[idx];
94 TileTypeSP tile = headTile;
96 for (; tile; tile = tile->next()) {
97 if (tile->col() == col &&
98 tile->row() == row) {
99
100 if (m_hashTable[idx] != headTile) {
101 tile.clear();
104 break;
105 }
106 }
107
108 return tile;
109}
110
111template<class T>
113KisTileHashTableTraits<T>::getTile(qint32 col, qint32 row, qint32 idx)
114{
115 TileTypeSP tile = m_hashTable[idx];
116
117 for (; tile; tile = tile->next()) {
118 if (tile->col() == col &&
119 tile->row() == row) {
120
121 return tile;
122 }
123 }
124
125 return TileTypeSP();
126}
127
128template<class T>
130{
131 TileTypeSP firstTile = m_hashTable[idx];
132
133#ifdef SHARED_TILES_SANITY_CHECK
134 Q_ASSERT_X(!tile->next(), "KisTileHashTableTraits<T>::linkTile",
135 "A tile can't be shared by several hash tables, sorry.");
136#endif
137
138 tile->setNext(firstTile);
139 m_hashTable[idx] = tile;
140 m_numTiles++;
141}
142
143template<class T>
144bool KisTileHashTableTraits<T>::unlinkTile(qint32 col, qint32 row, qint32 idx)
145{
146 TileTypeSP tile = m_hashTable[idx];
147 TileTypeSP prevTile;
148
149 for (; tile; tile = tile->next()) {
150 if (tile->col() == col &&
151 tile->row() == row) {
152
153 if (prevTile)
154 prevTile->setNext(tile->next());
155 else
156 /* optimize here*/
157 m_hashTable[idx] = tile->next();
158
164 tile->setNext(TileTypeSP());
165 tile->notifyDetachedFromDataManager();
166 tile.clear();
167
168 m_numTiles--;
169 return true;
170 }
171 prevTile = tile;
172 }
173
174 return false;
175}
176
177template<class T>
179{
180 if (m_defaultTileData) {
181 m_defaultTileData->release();
182 m_defaultTileData = 0;
183 }
184
185 if (defaultTileData) {
186 defaultTileData->acquire();
187 m_defaultTileData = defaultTileData;
188 }
189}
190
191template<class T>
193{
194 return m_defaultTileData;
195}
196
197
198template<class T>
199bool KisTileHashTableTraits<T>::tileExists(qint32 col, qint32 row)
200{
201 return this->getExistingTile(col, row);
202}
203
204template<class T>
207{
208 const qint32 idx = calculateHash(col, row);
209
210 // NOTE: minefield walk is disabled due to supposed unsafety,
211 // see bug 391270
212
213 QReadLocker locker(&m_lock);
214 return getTile(col, row, idx);
215}
216
217template<class T>
220 bool& newTile)
221{
222 const qint32 idx = calculateHash(col, row);
223
224 // NOTE: minefield walk is disabled due to supposed unsafety,
225 // see bug 391270
226
227 newTile = false;
228 TileTypeSP tile;
229
230 {
231 QReadLocker locker(&m_lock);
232 tile = getTile(col, row, idx);
233 }
234
235 if (!tile) {
236 QWriteLocker locker(&m_lock);
237 tile = new TileType(col, row, m_defaultTileData, m_mementoManager);
238 linkTile(tile, idx);
239 newTile = true;
240 }
241
242 return tile;
243}
244
245template<class T>
247KisTileHashTableTraits<T>::getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile)
248{
249 const qint32 idx = calculateHash(col, row);
250
251 // NOTE: minefield walk is disabled due to supposed unsafety,
252 // see bug 391270
253
254 QReadLocker locker(&m_lock);
255
256 TileTypeSP tile = getTile(col, row, idx);
257 existingTile = tile;
258
259 if (!existingTile) {
260 tile = new TileType(col, row, m_defaultTileData, 0);
261 }
262
263 return tile;
264}
265
266template<class T>
268{
269 const qint32 idx = calculateHash(tile->col(), tile->row());
270
271 QWriteLocker locker(&m_lock);
272 linkTile(tile, idx);
273}
274
275template<class T>
276bool KisTileHashTableTraits<T>::deleteTile(qint32 col, qint32 row)
277{
278 const qint32 idx = calculateHash(col, row);
279
280 QWriteLocker locker(&m_lock);
281 return unlinkTile(col, row, idx);
282}
283
284template<class T>
286{
287 return deleteTile(tile->col(), tile->row());
288}
289
290template<class T>
292{
293 QWriteLocker locker(&m_lock);
294 TileTypeSP tile = TileTypeSP();
295 qint32 i;
296
297 for (i = 0; i < TABLE_SIZE; i++) {
298 tile = m_hashTable[i];
299
300 while (tile) {
301 TileTypeSP tmp = tile;
302 tile = tile->next();
303
308 tmp->setNext(TileTypeSP());
309 tmp->notifyDetachedFromDataManager();
310 tmp = 0;
311
312 m_numTiles--;
313 }
314
315 m_hashTable[i] = 0;
316 }
317
318 Q_ASSERT(!m_numTiles);
319}
320
321template<class T>
323{
324 QWriteLocker locker(&m_lock);
325 setDefaultTileDataImp(defaultTileData);
326}
327
328template<class T>
330{
331 QWriteLocker locker(&m_lock);
332 return defaultTileDataImp();
333}
334
335template <class T>
337{
338 QWriteLocker locker(&m_lock);
339 KisTileData *result = defaultTileDataImp();
340 result->ref();
341 return result;
342}
343
344
345/*************** Debugging stuff ***************/
346
347template<class T>
349{
350 if (!m_numTiles) return;
351
352 qInfo() << "==========================\n"
353 << "TileHashTable:"
354 << "\n def. data:\t\t" << m_defaultTileData
355 << "\n numTiles:\t\t" << m_numTiles;
356 debugListLengthDistribution();
357 qInfo() << "==========================\n";
358}
359
360template<class T>
362{
363 qint32 len = 0;
364 for (TileTypeSP it = m_hashTable[idx]; it; it = it->next(), len++) ;
365 return len;
366}
367
368template<class T>
370{
371 TileTypeSP tile;
372 qint32 maxLen = 0;
373 qint32 minLen = m_numTiles;
374 qint32 tmp = 0;
375
376 for (qint32 i = 0; i < TABLE_SIZE; i++) {
377 tmp = debugChainLen(i);
378 if (tmp > maxLen)
379 maxLen = tmp;
380 if (tmp < minLen)
381 minLen = tmp;
382 }
383
384 min = minLen;
385 max = maxLen;
386}
387
388template<class T>
390{
391 qint32 min, max;
392 qint32 arraySize;
393 qint32 tmp;
394
395 debugMaxListLength(min, max);
396 arraySize = max - min + 1;
397
398 qint32 *array = new qint32[arraySize];
399 memset(array, 0, sizeof(qint32)*arraySize);
400
401 for (qint32 i = 0; i < TABLE_SIZE; i++) {
402 tmp = debugChainLen(i);
403 array[tmp-min]++;
404 }
405
406 qInfo() << QString(" minChain: %1\n").arg(min);
407 qInfo() << QString(" maxChain: %1\n").arg(max);
408
409 qInfo() << " Chain size distribution:";
410 for (qint32 i = 0; i < arraySize; i++)
411 qInfo() << QString(" %1: %2").arg(i + min).arg(array[i]);
412
413 delete[] array;
414}
415
416template<class T>
418{
423 Q_ASSERT(!m_lock.tryLockForWrite());
424
425 TileTypeSP tile = 0;
426 qint32 exactNumTiles = 0;
427
428 for (qint32 i = 0; i < TABLE_SIZE; i++) {
429 tile = m_hashTable[i];
430 while (tile) {
431 exactNumTiles++;
432 tile = tile->next();
433 }
434 }
435
436 if (exactNumTiles != m_numTiles) {
437 dbgKrita << "Sanity check failed!";
438 dbgKrita << ppVar(exactNumTiles);
439 dbgKrita << ppVar(m_numTiles);
440 dbgKrita << "Wrong tiles checksum!";
441 Q_ASSERT(0); // not fatalKrita for a backtrace support
442 }
443}
KisMementoItemSP next() const
qint32 col() const
qint32 row() const
void setNext(KisMementoItemSP next)
bool ref() const
TileTypeSP getTileMinefieldWalk(qint32 col, qint32 row, qint32 idx)
KisTileData * refAndFetchDefaultTileData() const
static const qint32 TABLE_SIZE
TileTypeSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile)
TileTypeSP getExistingTile(qint32 col, qint32 row)
void addTile(TileTypeSP tile)
KisTileData * defaultTileData() const
bool deleteTile(TileTypeSP tile)
void debugMaxListLength(qint32 &min, qint32 &max)
void setDefaultTileData(KisTileData *defaultTileData)
static quint32 calculateHash(qint32 col, qint32 row)
bool tileExists(qint32 col, qint32 row)
KisTileHashTableTraits(KisMementoManager *mm)
qint32 debugChainLen(qint32 idx)
void setDefaultTileDataImp(KisTileData *defaultTileData)
KisTileData * defaultTileDataImp() const
TileTypeSP getTile(qint32 col, qint32 row, qint32 idx)
TileTypeSP getTileLazy(qint32 col, qint32 row, bool &newTile)
void linkTile(TileTypeSP tile, qint32 idx)
KisMementoManager * m_mementoManager
bool unlinkTile(qint32 col, qint32 row, qint32 idx)
#define dbgKrita
Definition kis_debug.h:45
#define ppVar(var)
Definition kis_debug.h:155
struct Tile * newTile(struct rect r)
Definition pixels.c:231