Commit af18266b authored by Andrey Kamakin's avatar Andrey Kamakin

Implemented all hash table functions.

Ref T8874
parent fc64efc9
......@@ -337,6 +337,13 @@ public:
return m_value != Value(ValueTraits::NullValue);
}
Key getKey() const
{
Q_ASSERT(isValid());
// Since we've forbidden concurrent inserts (for now), nonatomic would suffice here, but let's plan ahead:
return KeyTraits::dehash(m_hash);
}
Value getValue() const
{
Q_ASSERT(isValid());
......
......@@ -31,6 +31,26 @@ inline bool isPowerOf2(quint64 v)
return (v & (v - 1)) == 0;
}
inline quint32 avalanche(quint32 h)
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
inline quint32 deavalanche(quint32 h)
{
h ^= h >> 16;
h *= 0x7ed1b41d;
h ^= (h ^ (h >> 13)) >> 13;
h *= 0xa5cb9243;
h ^= h >> 16;
return h;
}
template <class T>
struct DefaultKeyTraits {
typedef T Key;
......@@ -40,7 +60,12 @@ struct DefaultKeyTraits {
static Hash hash(T key)
{
return std::hash<Hash>()(Hash(key));
return avalanche(Hash(key));
}
static Key dehash(Hash hash)
{
return (T) deavalanche(hash);
}
};
......
......@@ -6,6 +6,7 @@
#include "3rdparty/lock_free_map/concurrent_map.h"
#include "kis_memento_manager.h"
#include <functional>
template <class T>
class KisTileHashTableTraits2
......@@ -25,27 +26,30 @@ public:
TileTypeSP insert(qint32 key, TileTypeSP value)
{
m_rawPointerUsers.fetchAndAddOrdered(1);
m_rawPointerUsers.fetchAndAddRelaxed(1);
TileTypeSP::ref(&value, value.data());
TileType *result = m_map.assign(key, value.data());
if (result) {
MemoryReclaimer *tmp = new MemoryReclaimer(result);
QSBR::instance().enqueue(&MemoryReclaimer::destroy, tmp);
} else {
m_numTiles.fetchAndAddRelaxed(1);
}
TileTypeSP ptr(result);
m_rawPointerUsers.fetchAndSubOrdered(1);
m_rawPointerUsers.fetchAndSubRelaxed(1);
return ptr;
}
TileTypeSP erase(qint32 key)
{
m_rawPointerUsers.fetchAndAddOrdered(1);
m_rawPointerUsers.fetchAndAddRelaxed(1);
TileType *result = m_map.erase(key);
TileTypeSP ptr(result);
if (result) {
m_numTiles.fetchAndSubRelaxed(1);
MemoryReclaimer *tmp = new MemoryReclaimer(result);
QSBR::instance().enqueue(&MemoryReclaimer::destroy, tmp);
}
......@@ -54,52 +58,94 @@ public:
QSBR::instance().update(m_context);
}
m_rawPointerUsers.fetchAndSubOrdered(1);
m_rawPointerUsers.fetchAndSubRelaxed(1);
return ptr;
}
TileTypeSP get(qint32 key)
{
m_rawPointerUsers.fetchAndAddOrdered(1);
m_rawPointerUsers.fetchAndAddRelaxed(1);
TileTypeSP result(m_map.get(key));
m_rawPointerUsers.fetchAndSubOrdered(1);
m_rawPointerUsers.fetchAndSubRelaxed(1);
return result;
}
TileTypeSP getLazy(qint32 key)
TileTypeSP getLazy(qint32 key, TileTypeSP value)
{
m_rawPointerUsers.fetchAndAddOrdered(1);
m_rawPointerUsers.fetchAndAddRelaxed(1);
typename ConcurrentMap<qint32, TileType *>::Mutator iter = m_map.insertOrFind(key);
if (!iter.getValue()) {
TileTypeSP value(new TileType);
TileTypeSP::ref(&value, value.data());
if (iter.exchangeValue(value.data()) == value.data()) {
TileTypeSP::deref(&value, value.data());
} else {
m_numTiles.fetchAndAddRelaxed(1);
}
}
TileTypeSP result(iter.getValue());
m_rawPointerUsers.fetchAndSubOrdered(1);
m_rawPointerUsers.fetchAndSubRelaxed(1);
return result;
}
bool tileExists(qint32 key);
TileTypeSP getExistingTile(qint32 key);
TileTypeSP getTileLazy(qint32 key);
TileTypeSP getReadOnlyTileLazy(qint32 key, bool &existingTile);
void addTile(qint32 key, TileTypeSP value);
bool deleteTile(qint32 key);
bool isEmpty()
{
return !m_numTiles;
}
void setDefaultTileDataImp(KisTileData *defaultTileData);
KisTileData* defaultTileDataImp() const;
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() const;
qint32 numTiles()
{
return m_numTiles;
}
void debugPrintInfo();
void debugMaxListLength(qint32 &min, qint32 &max);
private:
static inline quint32 calculateHash(qint32 col, qint32 row);
struct MemoryReclaimer {
MemoryReclaimer(TileType *data) : d(data) {}
~MemoryReclaimer() = default;
......@@ -115,9 +161,11 @@ private:
TileType *d;
};
ConcurrentMap<qint32, TileType *> m_map;
private:
ConcurrentMap<qint32, TileType*> m_map;
QSBR::Context m_context;
QAtomicInt m_rawPointerUsers;
QAtomicInt m_numTiles;
KisTileData *m_defaultTileData;
KisMementoManager *m_mementoManager;
......@@ -125,7 +173,7 @@ private:
template <class T>
KisTileHashTableTraits2<T>::KisTileHashTableTraits2()
: m_context(QSBR::instance().createContext()), m_rawPointerUsers(0),
: m_context(QSBR::instance().createContext()), m_rawPointerUsers(0), m_numTiles(0),
m_defaultTileData(0), m_mementoManager(0)
{
}
......@@ -139,63 +187,90 @@ KisTileHashTableTraits2<T>::KisTileHashTableTraits2(KisMementoManager *mm)
template <class T>
KisTileHashTableTraits2<T>::KisTileHashTableTraits2(const KisTileHashTableTraits2<T> &ht, KisMementoManager *mm)
: KisTileHashTableTraits2(mm)
{
setDefaultTileData(ht.m_defaultTileData);
typename ConcurrentMap<qint32, TileType*>::Iterator iter(ht);
while (iter.isValid()) {
insert(iter.getKey(), iter.getValue());
iter.next();
}
}
template <class T>
KisTileHashTableTraits2<T>::~KisTileHashTableTraits2()
{
clear();
QSBR::instance().destroyContext(m_context);
}
template<class T>
bool KisTileHashTableTraits2<T>::tileExists(qint32 key)
bool KisTileHashTableTraits2<T>::tileExists(qint32 col, qint32 row)
{
return get(key) != nullptr;
return get(calculateHash(col, row)) != nullptr;
}
template <class T>
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getExistingTile(qint32 key)
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getExistingTile(qint32 col, qint32 row)
{
return get(key);
return get(calculateHash(col, row));
}
template <class T>
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getTileLazy(qint32 key)
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getTileLazy(qint32 col, qint32 row, bool &newTile)
{
return getLazy(key);
TileTypeSP tile(new TileType(col, row, m_defaultTileData, m_mementoManager));
return getLazy(calculateHash(col, row), tile);
}
template <class T>
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getReadOnlyTileLazy(qint32 key, bool &existingTile)
typename KisTileHashTableTraits2<T>::TileTypeSP KisTileHashTableTraits2<T>::getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile)
{
m_rawPointerUsers.fetchAndAddOrdered(1);
TileTypeSP tile(m_map.get(key));
m_rawPointerUsers.fetchAndAddRelaxed(1);
TileTypeSP tile(m_map.get(calculateHash(col, row)));
existingTile = tile;
if (!existingTile) {
tile = new TileType;
tile = new TileType(col, row, m_defaultTileData, 0);
}
m_rawPointerUsers.fetchAndSubOrdered(1);
m_rawPointerUsers.fetchAndSubRelaxed(1);
return tile;
}
template <class T>
void KisTileHashTableTraits2<T>::addTile(qint32 key, TileTypeSP value)
void KisTileHashTableTraits2<T>::addTile(TileTypeSP value)
{
insert(m_numTiles.load() + 1, value);
}
template <class T>
bool KisTileHashTableTraits2<T>::deleteTile(TileTypeSP tile)
{
insert(key, value);
return deleteTile(tile->col(), tile->row());
}
template <class T>
bool KisTileHashTableTraits2<T>::deleteTile(qint32 key)
bool KisTileHashTableTraits2<T>::deleteTile(qint32 col, qint32 row)
{
return erase(key) != nullptr;
return erase(calculateHash(col, row)) != nullptr;
}
template<class T>
inline void KisTileHashTableTraits2<T>::setDefaultTileDataImp(KisTileData *defaultTileData)
void KisTileHashTableTraits2<T>::clear()
{
typename ConcurrentMap<qint32, TileType*>::Iterator iter(m_map);
while (iter.isValid()) {
erase(iter.getKey());
iter.next();
}
}
template <class T>
inline void KisTileHashTableTraits2<T>::setDefaultTileData(KisTileData *defaultTileData)
{
m_rawPointerUsers.fetchAndAddRelaxed(1);
if (m_defaultTileData) {
m_defaultTileData->release();
m_defaultTileData = 0;
......@@ -205,10 +280,12 @@ inline void KisTileHashTableTraits2<T>::setDefaultTileDataImp(KisTileData *defau
defaultTileData->acquire();
m_defaultTileData = defaultTileData;
}
m_rawPointerUsers.fetchAndSubRelaxed(1);
}
template<class T>
inline KisTileData* KisTileHashTableTraits2<T>::defaultTileDataImp() const
template <class T>
inline KisTileData* KisTileHashTableTraits2<T>::defaultTileData() const
{
return m_defaultTileData;
}
......@@ -223,4 +300,10 @@ void KisTileHashTableTraits2<T>::debugMaxListLength(qint32 &min, qint32 &max)
{
}
template <class T>
quint32 KisTileHashTableTraits2<T>::calculateHash(qint32 col, qint32 row)
{
return ((row << 5) + (col & 0x1F)) & 0x3FF;
}
#endif // KIS_TILEHASHTABLE_2_H
......@@ -12,7 +12,9 @@ class Wrapper : public KisShared
{
public:
Wrapper() : m_member(0) {}
Wrapper(qint32 member) : m_member(member) {}
Wrapper(qint32 col, qint32 row,
KisTileData *defaultTileData, KisMementoManager* mm)
: m_member(col) {}
qint32 member()
{
......@@ -73,7 +75,7 @@ void LockFreeMapTest::testMainOperations()
break;
}
case 1: {
auto result = map.insert(i, KisSharedPtr<Wrapper>(new Wrapper(i)));
auto result = map.insert(i, KisSharedPtr<Wrapper>(new Wrapper(i, 0, 0, 0)));
if (result.data()) {
insertSum -= result->member();
}
......@@ -127,7 +129,7 @@ void LockFreeMapTest::testLazy()
QList<StressJob *> jobs;
KisTileHashTableTraits2<Wrapper> map;
auto func = [&](qint64 &eraseSum, qint64 &insertSum) {
auto func = [&](qint64 & eraseSum, qint64 & insertSum) {
for (qint32 i = 1; i < numCycles + 1; ++i) {
auto type = i % numTypes;
......@@ -140,7 +142,7 @@ void LockFreeMapTest::testLazy()
break;
}
case 1: {
auto result = map.getLazy(i);
auto result = map.getLazy(i, KisSharedPtr<Wrapper>(new Wrapper()));
if (result.data()) {
insertSum += result->member();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment