mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
Replace implementation of CHashTableT with robin_hood hash map
This commit is contained in:
parent
e8e5143ef7
commit
fba05f3721
@ -10,104 +10,7 @@
|
||||
#ifndef HASHTABLE_HPP
|
||||
#define HASHTABLE_HPP
|
||||
|
||||
#include "../core/math_func.hpp"
|
||||
|
||||
template <class Titem_>
|
||||
struct CHashTableSlotT
|
||||
{
|
||||
typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable
|
||||
|
||||
Titem_ *m_pFirst;
|
||||
|
||||
inline CHashTableSlotT() : m_pFirst(nullptr) {}
|
||||
|
||||
/** hash table slot helper - clears the slot by simple forgetting its items */
|
||||
inline void Clear()
|
||||
{
|
||||
m_pFirst = nullptr;
|
||||
}
|
||||
|
||||
/** hash table slot helper - linear search for item with given key through the given blob - const version */
|
||||
inline const Titem_ *Find(const Key &key) const
|
||||
{
|
||||
for (const Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
|
||||
if (pItem->GetKey() == key) {
|
||||
/* we have found the item, return it */
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** hash table slot helper - linear search for item with given key through the given blob - non-const version */
|
||||
inline Titem_ *Find(const Key &key)
|
||||
{
|
||||
for (Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
|
||||
if (pItem->GetKey() == key) {
|
||||
/* we have found the item, return it */
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** hash table slot helper - add new item to the slot */
|
||||
inline void Attach(Titem_ &new_item)
|
||||
{
|
||||
assert(new_item.GetHashNext() == nullptr);
|
||||
new_item.SetHashNext(m_pFirst);
|
||||
m_pFirst = &new_item;
|
||||
}
|
||||
|
||||
/** hash table slot helper - remove item from a slot */
|
||||
inline bool Detach(Titem_ &item_to_remove)
|
||||
{
|
||||
if (m_pFirst == &item_to_remove) {
|
||||
m_pFirst = item_to_remove.GetHashNext();
|
||||
item_to_remove.SetHashNext(nullptr);
|
||||
return true;
|
||||
}
|
||||
Titem_ *pItem = m_pFirst;
|
||||
for (;;) {
|
||||
if (pItem == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Titem_ *pNextItem = pItem->GetHashNext();
|
||||
if (pNextItem == &item_to_remove) break;
|
||||
pItem = pNextItem;
|
||||
}
|
||||
pItem->SetHashNext(item_to_remove.GetHashNext());
|
||||
item_to_remove.SetHashNext(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** hash table slot helper - remove and return item from a slot */
|
||||
inline Titem_ *Detach(const Key &key)
|
||||
{
|
||||
/* do we have any items? */
|
||||
if (m_pFirst == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
/* is it our first item? */
|
||||
if (m_pFirst->GetKey() == key) {
|
||||
Titem_ &ret_item = *m_pFirst;
|
||||
m_pFirst = m_pFirst->GetHashNext();
|
||||
ret_item.SetHashNext(nullptr);
|
||||
return &ret_item;
|
||||
}
|
||||
/* find it in the following items */
|
||||
Titem_ *pPrev = m_pFirst;
|
||||
for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != nullptr; pPrev = pItem, pItem = pItem->GetHashNext()) {
|
||||
if (pItem->GetKey() == key) {
|
||||
/* we have found the item, unlink and return it */
|
||||
pPrev->SetHashNext(pItem->GetHashNext());
|
||||
pItem->SetHashNext(nullptr);
|
||||
return pItem;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
#include "../3rdparty/robin_hood/robin_hood.h"
|
||||
|
||||
/**
|
||||
* class CHashTableT<Titem, Thash_bits> - simple hash table
|
||||
@ -115,6 +18,8 @@ struct CHashTableSlotT
|
||||
*
|
||||
* Supports: Add/Find/Remove of Titems.
|
||||
*
|
||||
* Thash_bits_ is ignored but retained for upstream compatibility
|
||||
*
|
||||
* Your Titem must meet some extra requirements to be CHashTableT
|
||||
* compliant:
|
||||
* - its constructor/destructor (if any) must be public
|
||||
@ -126,93 +31,65 @@ struct CHashTableSlotT
|
||||
* const Key& GetKey() const; // return the item's key object
|
||||
*
|
||||
* In addition, the Titem::Key class must support:
|
||||
* - public method that calculates key's hash:
|
||||
* int CalcHash() const;
|
||||
* - public 'equality' operator to compare the key with another one
|
||||
* bool operator==(const Key &other) const;
|
||||
* - nested type (struct, class or typedef) Titem::Key::HashKey
|
||||
* that defines the hash key storage type, this may be the same as Titem::Key, and must be hashable and equality comparable
|
||||
* - public method that get the key storage type:
|
||||
* Titem::Key::HashKey GetHashKey() const;
|
||||
*/
|
||||
template <class Titem_, int Thash_bits_>
|
||||
template <class Titem_, int Thash_bits_ = 0>
|
||||
class CHashTableT {
|
||||
public:
|
||||
typedef Titem_ Titem; // make Titem_ visible from outside of class
|
||||
typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable
|
||||
static const int Thash_bits = Thash_bits_; // publish num of hash bits
|
||||
static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
|
||||
typedef typename Tkey::HashKey THashKey; // make Titem_::Key::HashKey a property of HashTable
|
||||
|
||||
protected:
|
||||
/**
|
||||
* each slot contains pointer to the first item in the list,
|
||||
* Titem contains pointer to the next item - GetHashNext(), SetHashNext()
|
||||
*/
|
||||
typedef CHashTableSlotT<Titem_> Slot;
|
||||
|
||||
Slot m_slots[Tcapacity]; // here we store our data (array of blobs)
|
||||
int m_num_items; // item counter
|
||||
private:
|
||||
robin_hood::unordered_map<THashKey, Titem *> data;
|
||||
|
||||
public:
|
||||
/* default constructor */
|
||||
inline CHashTableT() : m_num_items(0)
|
||||
inline CHashTableT()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
/** static helper - return hash for the given key modulo number of slots */
|
||||
inline static int CalcHash(const Tkey &key)
|
||||
{
|
||||
uint32_t hash = key.CalcHash();
|
||||
hash -= (hash >> 17); // hash * 131071 / 131072
|
||||
hash -= (hash >> 5); // * 31 / 32
|
||||
hash &= (1 << Thash_bits) - 1; // modulo slots
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** static helper - return hash for the given item modulo number of slots */
|
||||
inline static int CalcHash(const Titem_ &item)
|
||||
{
|
||||
return CalcHash(item.GetKey());
|
||||
}
|
||||
|
||||
public:
|
||||
/** item count */
|
||||
inline int Count() const
|
||||
{
|
||||
return m_num_items;
|
||||
return this->data.size();
|
||||
}
|
||||
|
||||
/** simple clear - forget all items - used by CSegmentCostCacheT.Flush() */
|
||||
inline void Clear()
|
||||
{
|
||||
for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();
|
||||
this->data.clear();
|
||||
}
|
||||
|
||||
/** const item search */
|
||||
const Titem_ *Find(const Tkey &key) const
|
||||
{
|
||||
int hash = CalcHash(key);
|
||||
const Slot &slot = m_slots[hash];
|
||||
const Titem_ *item = slot.Find(key);
|
||||
return item;
|
||||
auto iter = this->data.find(key.GetHashKey());
|
||||
if (iter != this->data.end()) return iter->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** non-const item search */
|
||||
Titem_ *Find(const Tkey &key)
|
||||
{
|
||||
int hash = CalcHash(key);
|
||||
Slot &slot = m_slots[hash];
|
||||
Titem_ *item = slot.Find(key);
|
||||
return item;
|
||||
auto iter = this->data.find(key.GetHashKey());
|
||||
if (iter != this->data.end()) return iter->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** non-const item search & optional removal (if found) */
|
||||
Titem_ *TryPop(const Tkey &key)
|
||||
{
|
||||
int hash = CalcHash(key);
|
||||
Slot &slot = m_slots[hash];
|
||||
Titem_ *item = slot.Detach(key);
|
||||
if (item != nullptr) {
|
||||
m_num_items--;
|
||||
auto iter = this->data.find(key.GetHashKey());
|
||||
if (iter != this->data.end()) {
|
||||
Titem_ *result = iter->second;
|
||||
this->data.erase(iter);
|
||||
return result;
|
||||
}
|
||||
return item;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** non-const item search & removal */
|
||||
@ -226,14 +103,12 @@ public:
|
||||
/** non-const item search & optional removal (if found) */
|
||||
bool TryPop(Titem_ &item)
|
||||
{
|
||||
const Tkey &key = item.GetKey();
|
||||
int hash = CalcHash(key);
|
||||
Slot &slot = m_slots[hash];
|
||||
bool ret = slot.Detach(item);
|
||||
if (ret) {
|
||||
m_num_items--;
|
||||
auto iter = this->data.find(item.GetKey().GetHashKey());
|
||||
if (iter != this->data.end()) {
|
||||
this->data.erase(iter);
|
||||
return true;
|
||||
}
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** non-const item search & removal */
|
||||
@ -246,11 +121,7 @@ public:
|
||||
/** add one item - copy it from the given item */
|
||||
void Push(Titem_ &new_item)
|
||||
{
|
||||
int hash = CalcHash(new_item);
|
||||
Slot &slot = m_slots[hash];
|
||||
assert(slot.Find(new_item.GetKey()) == nullptr);
|
||||
slot.Attach(new_item);
|
||||
m_num_items++;
|
||||
this->data[new_item.GetKey().GetHashKey()] = &new_item;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -61,15 +61,6 @@ struct OpenListNode {
|
||||
PathNode path;
|
||||
};
|
||||
|
||||
struct PairHash {
|
||||
public:
|
||||
template <typename T, typename U>
|
||||
std::size_t operator()(const std::pair<T, U> &x) const
|
||||
{
|
||||
return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
|
||||
}
|
||||
};
|
||||
|
||||
bool CheckIgnoreFirstTile(const PathNode *node);
|
||||
|
||||
struct AyStar;
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
/** Yapf Node Key that evaluates hash from (and compares) tile & exit dir. */
|
||||
struct CYapfNodeKeyExitDir {
|
||||
using HashKey = uint32_t;
|
||||
|
||||
TileIndex m_tile;
|
||||
Trackdir m_td;
|
||||
DiagDirection m_exitdir;
|
||||
@ -23,7 +25,7 @@ struct CYapfNodeKeyExitDir {
|
||||
m_exitdir = (m_td == INVALID_TRACKDIR) ? INVALID_DIAGDIR : TrackdirToExitdir(m_td);
|
||||
}
|
||||
|
||||
inline int CalcHash() const
|
||||
inline HashKey GetHashKey() const
|
||||
{
|
||||
return m_exitdir | (m_tile << 2);
|
||||
}
|
||||
@ -43,7 +45,9 @@ struct CYapfNodeKeyExitDir {
|
||||
|
||||
struct CYapfNodeKeyTrackDir : public CYapfNodeKeyExitDir
|
||||
{
|
||||
inline int CalcHash() const
|
||||
using HashKey = uint32_t;
|
||||
|
||||
inline HashKey GetHashKey() const
|
||||
{
|
||||
return m_td | (m_tile << 4);
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
/** key for cached segment cost for rail YAPF */
|
||||
struct CYapfRailSegmentKey
|
||||
{
|
||||
using HashKey = uint32_t;
|
||||
|
||||
uint32_t m_value;
|
||||
|
||||
inline CYapfRailSegmentKey(const CYapfNodeKeyTrackDir &node_key)
|
||||
@ -30,7 +32,7 @@ struct CYapfRailSegmentKey
|
||||
m_value = (((int)node_key.m_tile) << 4) | node_key.m_td;
|
||||
}
|
||||
|
||||
inline int32_t CalcHash() const
|
||||
inline HashKey GetHashKey() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ constexpr uint32_t MAX_NUMBER_OF_NODES = 65536;
|
||||
|
||||
/** Yapf Node Key that represents a single patch of interconnected water within a water region. */
|
||||
struct CYapfRegionPatchNodeKey {
|
||||
using HashKey = uint32_t;
|
||||
|
||||
WaterRegionPatchDesc m_water_region_patch;
|
||||
|
||||
inline void Set(const WaterRegionPatchDesc &water_region_patch)
|
||||
@ -30,8 +32,8 @@ struct CYapfRegionPatchNodeKey {
|
||||
m_water_region_patch = water_region_patch;
|
||||
}
|
||||
|
||||
inline uint32_t CalcHash() const { return CalculateWaterRegionPatchHash(m_water_region_patch); }
|
||||
inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return CalcHash() == other.CalcHash(); }
|
||||
inline uint32_t GetHashKey() const { return CalculateWaterRegionPatchHash(m_water_region_patch); }
|
||||
inline bool operator==(const CYapfRegionPatchNodeKey &other) const { return GetHashKey() == other.GetHashKey(); }
|
||||
};
|
||||
|
||||
inline uint ManhattanDistance(const CYapfRegionPatchNodeKey &a, const CYapfRegionPatchNodeKey &b)
|
||||
|
Loading…
Reference in New Issue
Block a user