2009-08-21 20:21:05 +00:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
|
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2008-05-06 15:11:33 +00:00
|
|
|
/** @file hashtable.hpp Hash table support. */
|
2007-04-17 20:23:13 +00:00
|
|
|
|
2010-12-22 11:24:38 +00:00
|
|
|
#ifndef HASHTABLE_HPP
|
|
|
|
#define HASHTABLE_HPP
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2010-08-26 22:01:16 +00:00
|
|
|
#include "../core/math_func.hpp"
|
|
|
|
|
2006-05-27 16:12:16 +00:00
|
|
|
template <class Titem_>
|
|
|
|
struct CHashTableSlotT
|
|
|
|
{
|
|
|
|
typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable
|
|
|
|
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *m_pFirst;
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2019-04-10 21:07:06 +00:00
|
|
|
inline CHashTableSlotT() : m_pFirst(nullptr) {}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2006-11-18 19:20:47 +00:00
|
|
|
/** hash table slot helper - clears the slot by simple forgetting its items */
|
2015-08-08 13:19:38 +00:00
|
|
|
inline void Clear()
|
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
m_pFirst = nullptr;
|
2015-08-08 13:19:38 +00:00
|
|
|
}
|
2006-11-18 19:20:47 +00:00
|
|
|
|
2006-05-27 16:12:16 +00:00
|
|
|
/** hash table slot helper - linear search for item with given key through the given blob - const version */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline const Titem_ *Find(const Key &key) const
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
for (const Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
|
2006-05-27 16:12:16 +00:00
|
|
|
if (pItem->GetKey() == key) {
|
2009-03-15 00:32:18 +00:00
|
|
|
/* we have found the item, return it */
|
2006-11-14 13:42:50 +00:00
|
|
|
return pItem;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 21:07:06 +00:00
|
|
|
return nullptr;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** hash table slot helper - linear search for item with given key through the given blob - non-const version */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline Titem_ *Find(const Key &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
for (Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
|
2006-05-27 16:12:16 +00:00
|
|
|
if (pItem->GetKey() == key) {
|
2009-03-15 00:32:18 +00:00
|
|
|
/* we have found the item, return it */
|
2006-11-14 13:42:50 +00:00
|
|
|
return pItem;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 21:07:06 +00:00
|
|
|
return nullptr;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** hash table slot helper - add new item to the slot */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline void Attach(Titem_ &new_item)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2019-04-10 21:07:06 +00:00
|
|
|
assert(new_item.GetHashNext() == nullptr);
|
2006-05-27 16:12:16 +00:00
|
|
|
new_item.SetHashNext(m_pFirst);
|
|
|
|
m_pFirst = &new_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** hash table slot helper - remove item from a slot */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline bool Detach(Titem_ &item_to_remove)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
if (m_pFirst == &item_to_remove) {
|
|
|
|
m_pFirst = item_to_remove.GetHashNext();
|
2019-04-10 21:07:06 +00:00
|
|
|
item_to_remove.SetHashNext(nullptr);
|
2006-05-27 16:12:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *pItem = m_pFirst;
|
2011-02-25 21:53:43 +00:00
|
|
|
for (;;) {
|
2019-04-10 21:07:06 +00:00
|
|
|
if (pItem == nullptr) {
|
2006-05-27 16:12:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *pNextItem = pItem->GetHashNext();
|
2006-05-27 16:12:16 +00:00
|
|
|
if (pNextItem == &item_to_remove) break;
|
|
|
|
pItem = pNextItem;
|
|
|
|
}
|
|
|
|
pItem->SetHashNext(item_to_remove.GetHashNext());
|
2019-04-10 21:07:06 +00:00
|
|
|
item_to_remove.SetHashNext(nullptr);
|
2006-05-27 16:12:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** hash table slot helper - remove and return item from a slot */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline Titem_ *Detach(const Key &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2009-03-15 00:32:18 +00:00
|
|
|
/* do we have any items? */
|
2019-04-10 21:07:06 +00:00
|
|
|
if (m_pFirst == nullptr) {
|
|
|
|
return nullptr;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
2009-03-15 00:32:18 +00:00
|
|
|
/* is it our first item? */
|
2006-05-27 16:12:16 +00:00
|
|
|
if (m_pFirst->GetKey() == key) {
|
2015-08-08 10:06:24 +00:00
|
|
|
Titem_ &ret_item = *m_pFirst;
|
2006-05-27 16:12:16 +00:00
|
|
|
m_pFirst = m_pFirst->GetHashNext();
|
2019-04-10 21:07:06 +00:00
|
|
|
ret_item.SetHashNext(nullptr);
|
2006-11-14 13:42:50 +00:00
|
|
|
return &ret_item;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
2009-03-15 00:32:18 +00:00
|
|
|
/* find it in the following items */
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *pPrev = m_pFirst;
|
2019-04-10 21:07:06 +00:00
|
|
|
for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != nullptr; pPrev = pItem, pItem = pItem->GetHashNext()) {
|
2006-05-27 16:12:16 +00:00
|
|
|
if (pItem->GetKey() == key) {
|
2009-03-15 00:32:18 +00:00
|
|
|
/* we have found the item, unlink and return it */
|
2006-05-27 16:12:16 +00:00
|
|
|
pPrev->SetHashNext(pItem->GetHashNext());
|
2019-04-10 21:07:06 +00:00
|
|
|
pItem->SetHashNext(nullptr);
|
2006-11-14 13:42:50 +00:00
|
|
|
return pItem;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-10 21:07:06 +00:00
|
|
|
return nullptr;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* class CHashTableT<Titem, Thash_bits> - simple hash table
|
2006-09-04 20:40:33 +00:00
|
|
|
* of pointers allocated elsewhere.
|
|
|
|
*
|
|
|
|
* Supports: Add/Find/Remove of Titems.
|
|
|
|
*
|
|
|
|
* Your Titem must meet some extra requirements to be CHashTableT
|
|
|
|
* compliant:
|
|
|
|
* - its constructor/destructor (if any) must be public
|
|
|
|
* - if the copying of item requires an extra resource management,
|
|
|
|
* you must define also copy constructor
|
|
|
|
* - must support nested type (struct, class or typedef) Titem::Key
|
|
|
|
* that defines the type of key class for that item
|
|
|
|
* - must support public method:
|
|
|
|
* 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
|
2015-08-08 10:06:24 +00:00
|
|
|
* bool operator==(const Key &other) const;
|
2006-09-04 20:40:33 +00:00
|
|
|
*/
|
2006-05-27 16:12:16 +00:00
|
|
|
template <class Titem_, int Thash_bits_>
|
|
|
|
class CHashTableT {
|
|
|
|
public:
|
2006-11-14 12:02:36 +00:00
|
|
|
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
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
protected:
|
2010-08-01 19:22:34 +00:00
|
|
|
/**
|
|
|
|
* each slot contains pointer to the first item in the list,
|
2010-08-01 19:44:49 +00:00
|
|
|
* Titem contains pointer to the next item - GetHashNext(), SetHashNext()
|
|
|
|
*/
|
2006-05-27 16:12:16 +00:00
|
|
|
typedef CHashTableSlotT<Titem_> Slot;
|
|
|
|
|
2011-04-19 18:20:34 +00:00
|
|
|
Slot m_slots[Tcapacity]; // here we store our data (array of blobs)
|
|
|
|
int m_num_items; // item counter
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
public:
|
2009-03-15 00:32:18 +00:00
|
|
|
/* default constructor */
|
2011-12-20 17:57:56 +00:00
|
|
|
inline CHashTableT() : m_num_items(0)
|
2009-08-07 13:33:55 +00:00
|
|
|
{
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
/** static helper - return hash for the given key modulo number of slots */
|
2015-08-08 10:06:24 +00:00
|
|
|
inline static int CalcHash(const Tkey &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2023-05-08 17:01:06 +00:00
|
|
|
uint32_t hash = key.CalcHash();
|
2018-05-19 21:04:25 +00:00
|
|
|
hash -= (hash >> 17); // hash * 131071 / 131072
|
|
|
|
hash -= (hash >> 5); // * 31 / 32
|
|
|
|
hash &= (1 << Thash_bits) - 1; // modulo slots
|
2006-05-27 16:12:16 +00:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** static helper - return hash for the given item modulo number of slots */
|
2015-08-08 13:19:38 +00:00
|
|
|
inline static int CalcHash(const Titem_ &item)
|
|
|
|
{
|
|
|
|
return CalcHash(item.GetKey());
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
/** item count */
|
2015-08-08 13:19:38 +00:00
|
|
|
inline int Count() const
|
|
|
|
{
|
|
|
|
return m_num_items;
|
|
|
|
}
|
2006-05-27 16:12:16 +00:00
|
|
|
|
2006-11-18 19:20:47 +00:00
|
|
|
/** simple clear - forget all items - used by CSegmentCostCacheT.Flush() */
|
2015-08-08 13:19:38 +00:00
|
|
|
inline void Clear()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();
|
|
|
|
}
|
2006-11-18 19:20:47 +00:00
|
|
|
|
2006-05-27 16:12:16 +00:00
|
|
|
/** const item search */
|
2015-08-08 10:06:24 +00:00
|
|
|
const Titem_ *Find(const Tkey &key) const
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
int hash = CalcHash(key);
|
2015-08-08 10:06:24 +00:00
|
|
|
const Slot &slot = m_slots[hash];
|
2009-01-10 00:31:47 +00:00
|
|
|
const Titem_ *item = slot.Find(key);
|
2006-05-27 16:12:16 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** non-const item search */
|
2015-08-08 10:06:24 +00:00
|
|
|
Titem_ *Find(const Tkey &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
int hash = CalcHash(key);
|
2015-08-08 10:06:24 +00:00
|
|
|
Slot &slot = m_slots[hash];
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *item = slot.Find(key);
|
2006-05-27 16:12:16 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** non-const item search & optional removal (if found) */
|
2015-08-08 10:06:24 +00:00
|
|
|
Titem_ *TryPop(const Tkey &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
int hash = CalcHash(key);
|
2015-08-08 10:06:24 +00:00
|
|
|
Slot &slot = m_slots[hash];
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *item = slot.Detach(key);
|
2019-04-10 21:07:06 +00:00
|
|
|
if (item != nullptr) {
|
2006-05-27 16:12:16 +00:00
|
|
|
m_num_items--;
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** non-const item search & removal */
|
2024-01-03 21:33:38 +00:00
|
|
|
Titem_ &Pop(const Tkey &key)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2009-01-10 00:31:47 +00:00
|
|
|
Titem_ *item = TryPop(key);
|
2019-04-10 21:07:06 +00:00
|
|
|
assert(item != nullptr);
|
2006-11-14 13:42:50 +00:00
|
|
|
return *item;
|
2006-05-27 16:12:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** non-const item search & optional removal (if found) */
|
2015-08-08 10:06:24 +00:00
|
|
|
bool TryPop(Titem_ &item)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2015-08-08 10:06:24 +00:00
|
|
|
const Tkey &key = item.GetKey();
|
2006-05-27 16:12:16 +00:00
|
|
|
int hash = CalcHash(key);
|
2015-08-08 10:06:24 +00:00
|
|
|
Slot &slot = m_slots[hash];
|
2006-05-27 16:12:16 +00:00
|
|
|
bool ret = slot.Detach(item);
|
|
|
|
if (ret) {
|
|
|
|
m_num_items--;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** non-const item search & removal */
|
2015-08-08 10:06:24 +00:00
|
|
|
void Pop(Titem_ &item)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
2021-06-03 14:55:08 +00:00
|
|
|
[[maybe_unused]] bool ret = TryPop(item);
|
2006-05-27 16:12:16 +00:00
|
|
|
assert(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** add one item - copy it from the given item */
|
2015-08-08 10:06:24 +00:00
|
|
|
void Push(Titem_ &new_item)
|
2006-05-27 16:12:16 +00:00
|
|
|
{
|
|
|
|
int hash = CalcHash(new_item);
|
2015-08-08 10:06:24 +00:00
|
|
|
Slot &slot = m_slots[hash];
|
2019-04-10 21:07:06 +00:00
|
|
|
assert(slot.Find(new_item.GetKey()) == nullptr);
|
2006-05-27 16:12:16 +00:00
|
|
|
slot.Attach(new_item);
|
|
|
|
m_num_items++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* HASHTABLE_HPP */
|