refactored HashTable, HashList, LinkedList

This commit is contained in:
hyung-hwan 2015-02-23 17:40:45 +00:00
parent 8c15d39d9a
commit 890097af66
3 changed files with 402 additions and 394 deletions

View File

@ -72,6 +72,10 @@ public:
typedef typename DatumList::Node Node; typedef typename DatumList::Node Node;
typedef HashList<T,MPOOL,HASHER,COMPARATOR> SelfType; typedef HashList<T,MPOOL,HASHER,COMPARATOR> SelfType;
typedef HashListHasher<T> DefaultHasher;
typedef HashListComparator<T> DefaultComparator;
typedef HashListResizer DefaultResizer;
HashList ( HashList (
Mmgr* mmgr = QSE_NULL, Mmgr* mmgr = QSE_NULL,
qse_size_t node_capacity = 10, qse_size_t node_capacity = 10,
@ -221,7 +225,46 @@ public:
return *this; return *this;
} }
bool isEmpty () const
{
return this->datum_list->isEmpty();
}
Node* getHeadNode () const
{
return this->datum_list->getHeadNode();
}
Node* getTaileNode () const
{
return this->datum_list->getTailNode();
}
protected: protected:
Node* find_node (const T& datum) const
{
qse_size_t hc, head, tail;
Node* np;
hc = this->hasher(datum) % this->node_capacity;
head = hc << 1; tail = head + 1;
np = this->nodes[head];
if (np)
{
do
{
T& t = np->value;
if (this->comparator(datum, t)) return np;
if (np == this->nodes[tail]) break;
np = np->getNextNode ();
}
while (1);
}
return QSE_NULL;
}
Node* insert_value (const T& datum, bool overwrite = true) Node* insert_value (const T& datum, bool overwrite = true)
{ {
qse_size_t hc, head, tail; qse_size_t hc, head, tail;
@ -269,46 +312,10 @@ protected:
return this->nodes[head]; return this->nodes[head];
} }
public:
Node* insert (const T& datum)
{
return this->insert_value (datum, false);
}
Node* upsert (const T& datum)
{
return this->insert_value (datum, true);
}
protected:
const Node* find_node (const T& datum) const
{
qse_size_t hc, head, tail;
Node* np;
hc = this->hasher(datum) % this->node_capacity;
head = hc << 1; tail = head + 1;
np = this->nodes[head];
if (np)
{
do
{
T& t = np->value;
if (datum == t) return np;
if (np == this->nodes[tail]) break;
np = np->getNextNode ();
}
while (1);
}
return QSE_NULL;
}
public: public:
Node* findNode (const T& datum) Node* findNode (const T& datum)
{ {
return (Node*)this->find_node (datum); return this->find_node (datum);
} }
const Node* findNode (const T& datum) const const Node* findNode (const T& datum) const
@ -330,14 +337,37 @@ public:
return &b->value; return &b->value;
} }
bool isEmpty () const /// The search() function returns the pointer to the existing node
/// containing the equal value to \a datum. If no node is found, it
/// return #QSE_NULL.
Node* search (const T& datum)
{ {
return this->datum_list->isEmpty(); return this->find_node (datum);
} }
bool contains (const T& datum) const /// The search() function returns the pointer to the existing node
/// containing the equal value to \a datum. If no node is found, it
/// return #QSE_NULL.
const Node* search (const T& datum) const
{ {
return this->findNode (datum) != QSE_NULL; return this->find_node (datum);
}
Node* insert (const T& datum)
{
return this->insert_value (datum, false);
}
Node* update (const T& datum)
{
Node* node = this->find_node (datum);
if (node) node->value = datum;
return node;
}
Node* upsert (const T& datum)
{
return this->insert_value (datum, true);
} }
int remove (const T& datum) int remove (const T& datum)
@ -392,16 +422,6 @@ public:
if (this->datum_list) this->datum_list->clear (); if (this->datum_list) this->datum_list->clear ();
} }
Node* getHeadNode () const
{
return this->datum_list->getHeadNode();
}
Node* getTaileNode () const
{
return this->datum_list->getTailNode();
}
typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur);
void traverse (TraverseCallback callback, Node* start) void traverse (TraverseCallback callback, Node* start)
@ -434,13 +454,13 @@ public:
protected: protected:
mutable qse_size_t node_capacity; mutable qse_size_t node_capacity;
mutable Node** nodes; mutable Node** nodes;
mutable DatumList* datum_list; mutable DatumList* datum_list;
mutable qse_size_t threshold; mutable qse_size_t threshold;
qse_size_t load_factor; qse_size_t load_factor;
HASHER hasher; HASHER hasher;
COMPARATOR comparator; COMPARATOR comparator;
RESIZER resizer; RESIZER resizer;
void rehash () void rehash ()
{ {

View File

@ -72,8 +72,13 @@ class HashTable: public Mmged
public: public:
typedef Couple<K,V> Pair; typedef Couple<K,V> Pair;
typedef LinkedList<Pair> Bucket; typedef LinkedList<Pair> Bucket;
typedef typename LinkedList<Pair>::Node BucketNode;
typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType; typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType;
typedef HashTableHasher<K> DefaultHasher;
typedef HashTableComparator<K> DefaultComparator;
typedef HashTableResizer DefaultResizer;
protected: protected:
Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs) const Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs) const
{ {
@ -84,7 +89,7 @@ protected:
b = (Bucket**) mm->callocate (QSE_SIZEOF(*b) * bs); b = (Bucket**) mm->callocate (QSE_SIZEOF(*b) * bs);
for (qse_size_t i = 0; i < bs; i++) for (qse_size_t i = 0; i < bs; i++)
{ {
b[i] = new(mm) Bucket (mm); b[i] = new(mm) Bucket (mm, this->bucket_mpb_size);
} }
} }
catch (...) catch (...)
@ -124,13 +129,14 @@ protected:
} }
public: public:
HashTable (Mmgr* mmgr, qse_size_t bucket_size = 10, qse_size_t load_factor = 75): Mmged(mmgr) HashTable (Mmgr* mmgr, qse_size_t bucket_size = 10, qse_size_t load_factor = 75, qse_size_t bucket_mpb_size = 0): Mmged(mmgr)
{ {
this->buckets = this->allocate_bucket (this->getMmgr(), bucket_size); this->buckets = this->allocate_bucket (this->getMmgr(), bucket_size);
this->bucket_size = bucket_size; this->bucket_size = bucket_size;
this->pair_count = 0; this->pair_count = 0;
this->load_factor = load_factor; this->load_factor = load_factor;
this->threshold = bucket_size * load_factor / 100; this->threshold = bucket_size * load_factor / 100;
this->bucket_mpb_size = bucket_mpb_size;
} }
HashTable (const SelfType& table): Mmged (table) HashTable (const SelfType& table): Mmged (table)
@ -140,11 +146,12 @@ public:
this->pair_count = 0; this->pair_count = 0;
this->load_factor = table.load_factor; this->load_factor = table.load_factor;
this->threshold = table.bucket_size * table.load_factor / 100; this->threshold = table.bucket_size * table.load_factor / 100;
this->bucket_mpb_size = table.bucket_mpb_size;
for (qse_size_t i = 0; i < table.bucket_size; i++) for (qse_size_t i = 0; i < table.bucket_size; i++)
{ {
Bucket* b = table.buckets[i]; Bucket* b = table.buckets[i];
typename Bucket::Node* np; BucketNode* np;
for (np = b->getHeadNode(); np; np = np->getNext()) for (np = b->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
@ -171,7 +178,7 @@ public:
for (qse_size_t i = 0; i < table.bucket_size; i++) for (qse_size_t i = 0; i < table.bucket_size; i++)
{ {
Bucket* b = table.buckets[i]; Bucket* b = table.buckets[i];
typename Bucket::Node* np; BucketNode* np;
for (np = b->getHeadNode(); np; np = np->getNext()) for (np = b->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
@ -185,6 +192,20 @@ public:
return *this; return *this;
} }
V& operator[] (const K& key)
{
Pair* pair = this->upsert (key);
QSE_ASSERT (pair != QSE_NULL);
return pair->value;
}
const V& operator[] (const K& key) const
{
Pair* pair = this->upsert (key);
QSE_ASSERT (pair != QSE_NULL);
return pair->value;
}
qse_size_t getSize () const qse_size_t getSize () const
{ {
return this->pair_count; return this->pair_count;
@ -218,111 +239,45 @@ public:
return this->buckets[index]; return this->buckets[index];
} }
#if 0 protected:
V& operator[] (const K& key) BucketNode* find_pair_node (const K& key, qse_size_t hc) const
{ {
qse_size_t hc = this->hasher(key) % this->bucket_size; BucketNode* np;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
if (this->comparator (key, e.key)) return e.value; if (this->comparator(key, e.key)) return np;
} }
return QSE_NULL;
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
// insert a new key if the key is not found
Pair& e2 = this->buckets[hc]->append (Pair(key));
this->pair_count++;
return e2.value;
} }
const V& operator[] (const K& key) const Pair* find_pair (const K& key, qse_size_t hc) const
{ {
qse_size_t hc = this->hasher(key) % this->bucket_size; BucketNode* np = this->find_pair_node (key, hc);
if (np) return &np->value;
Pair* pair = this->find_pair (key, hc); return QSE_NULL;
if (pair) return pair->value;
// insert a new key if the key is not found
Pair& new_pair = this->buckets[hc]->append (Pair(key));
this->pair_count++;
return new_pair.value;
} }
#endif
protected: template <typename MK, typename MCOMPARATOR>
template <typename MK, typename MHASHER, typename MCOMPARATOR> BucketNode* find_pair_node_with_custom_key (const MK& key, qse_size_t hc) const
Pair* find_pair_with_custom_key (const MK& key) const
{ {
MHASHER hash;
MCOMPARATOR is_equal; MCOMPARATOR is_equal;
qse_size_t hc = hash(key) % this->bucket_size; BucketNode* np;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
if (is_equal(key, e.key)) return &e; if (is_equal(key, e.key)) return np;
} }
return QSE_NULL; return QSE_NULL;
} }
public: template <typename MK, typename MCOMPARATOR>
/// \code Pair* find_pair_with_custom_key (const MK& key, qse_size_t hc) const
/// typedef QSE::HashTable<int,int,IntHasher> IntTable;
/// struct IntClass
/// {
/// IntClass (int x = 0): x (x) {}
/// int x;
/// };
/// struct IntClassHasher
/// {
/// qse_size_t operator() (const IntClass& v) const { return v.x; }
/// };
/// struct IntClassComparator
/// {
/// bool operator() (const IntClass& v, int y) const { return v.x == y; }
/// }
/// };
/// int main ()
/// {
/// IntTable int_list (NULL, 1000);
/// ...
/// IntTable::Pair* pair = int_list.findPairWithCustomKey<IntClass,IntClassHasher,IntClassComparator> (IntClass(50));
/// ...
/// }
/// \endcode
template <typename MK, typename MHASHER, typename MCOMPARATOR>
const Pair* findPairWithCustomKey (const MK& key) const
{ {
return this->find_pair_with_custom_key<MK,MHASHER,MCOMPARATOR> (key); BucketNode* np = this->find_pair_node_with_custom_key<MK,MCOMPARATOR> (key, hc);
} if (np) return &np->value;
template <typename MK, typename MHASHER, typename MCOMPARATOR>
Pair* findPairWithCustomKey (const MK& key)
{
return this->find_pair_with_custom_key<MK,MHASHER,MCOMPARATOR> (key);
}
protected:
Pair* find_pair (const K& key, qse_size_t hc)
{
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (this->comparator (key, e.key)) return &e;
}
return QSE_NULL; return QSE_NULL;
} }
@ -351,15 +306,15 @@ public:
return QSE_NULL; return QSE_NULL;
} }
V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node)
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
if (this->comparator (key, e.key)) if (this->comparator(key, e.key))
{ {
*hash_code = hc; *hash_code = hc;
*node = np; *node = np;
@ -370,15 +325,15 @@ public:
return QSE_NULL; return QSE_NULL;
} }
const V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) const const V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node) const
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
if (this->comparator (key, e.key)) if (this->comparator(key, e.key))
{ {
*hash_code = hc; *hash_code = hc;
*node = np; *node = np;
@ -389,27 +344,68 @@ public:
return QSE_NULL; return QSE_NULL;
} }
int put (const K& key, const V& value) /// \code
/// typedef QSE::HashTable<int,int,IntHasher> IntTable;
/// struct IntClass
/// {
/// IntClass (int x = 0): x (x) {}
/// int x;
/// };
/// struct IntClassHasher
/// {
/// qse_size_t operator() (const IntClass& v) const { return v.x; }
/// };
/// struct IntClassComparator
/// {
/// bool operator() (const IntClass& v, int y) const { return v.x == y; }
/// }
/// };
/// int main ()
/// {
/// IntTable int_list (NULL, 1000);
/// ...
/// IntTable::Pair* pair = int_list.findPairWithCustomKey<IntClass,IntClassHasher,IntClassComparator> (IntClass(50));
/// ...
/// }
/// \endcode
template <typename MK, typename MHASHER, typename MCOMPARATOR>
Pair* findPairWithCustomKey (const MK& key)
{ {
this->upsert (key, value); MHASHER hash;
return 0; return this->find_pair_with_custom_key<MK,MCOMPARATOR> (key, hash(key) % this->bucket_size);
} }
int putNew (const K& key, const V& value) template <typename MK, typename MHASHER, typename MCOMPARATOR>
const Pair* findPairWithCustomKey (const MK& key) const
{ {
return (this->insertNew(key,value) == QSE_NULL)? -1: 0; MHASHER hash;
return this->find_pair_with_custom_key<MK,MCOMPARATOR> (key, hash(key) % this->bucket_size);
} }
/// The search() function returns the pointer to a pair of the \a key.
/// If no pair is found, it returns #QSE_NULL.
Pair* search (const K& key)
{
return this->find_pair (key, this->hasher(key) % this->bucket_size);
}
/// The search() function returns the pointer to a pair of the \a key.
/// If no pair is found, it returns #QSE_NULL.
const Pair* search (const K& key) const
{
return this->find_pair (key, this->hasher(key) % this->bucket_size);
}
/// The insert() function inserts a new pair with a \a key with the default value.
/// if the key is not found in the table. It returns the pointer to the
/// new pair inserted. If the key is found, it returns #QSE_NULL
Pair* insert (const K& key) Pair* insert (const K& key)
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; Pair* pair = this->find_pair (key, hc);
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) if (pair) return QSE_NULL; // existing pair found.
{
Pair& e = np->value;
if (this->comparator (key, e.key)) return &e;
}
if (this->pair_count >= threshold) if (this->pair_count >= threshold)
{ {
@ -417,21 +413,21 @@ public:
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Pair& e = this->buckets[hc]->append (Pair(key)); // insert a new pair
Pair& new_pair = this->buckets[hc]->append (Pair(key));
this->pair_count++; this->pair_count++;
return &e; return &new_pair;
} }
/// The insert() function inserts a new pair with a \a key with a \a value.
/// if the key is not found in the table. It returns the pointer to the
/// new pair inserted. If the key is found, it returns #QSE_NULL
Pair* insert (const K& key, const V& value) Pair* insert (const K& key, const V& value)
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; Pair* pair = this->find_pair (key, hc);
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) if (pair) return QSE_NULL; // existing pair found.
{
Pair& e = np->value;
if (this->comparator (key, e.key)) return &e;
}
if (this->pair_count >= threshold) if (this->pair_count >= threshold)
{ {
@ -439,22 +435,32 @@ public:
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Pair& e = this->buckets[hc]->append (Pair(key,value)); // insert a new pair
Pair& new_pair = this->buckets[hc]->append (Pair(key, value));
this->pair_count++; this->pair_count++;
return &e; return &new_pair;
} }
#if 0 /// The update() function updates an existing pair of the \a key
Pair* upsert (const K& Key) /// with a \a value and returns a pointer to the pair. If the key
/// is not found, it returns #QSE_NULL.
Pair* update (const K& key, const V& value)
{
qse_size_t hc = this->hasher(key) % bucket_size;
Pair* pair = this->find_pair (key, hc);
if (pair) pair->value = value; // update the existing pair
return pair;
}
/// The upsert() function inserts a new pair with a \a key and a \a value
/// if the key is not found in the table. If it is found, it updated the
/// existing pair with a given \a value.
Pair* upsert (const K& key)
{ {
qse_size_t hc = this->hasher(key) % this->bucket_size; qse_size_t hc = this->hasher(key) % this->bucket_size;
Pair* pair = this->find_pair (key, hc); Pair* pair = this->find_pair (key, hc);
if (pair) if (pair) return pair; // return the existing pair
{
// don't change the existing value.
return pair
}
if (this->pair_count >= threshold) if (this->pair_count >= threshold)
{ {
@ -462,13 +468,15 @@ public:
hc = this->hasher(key) % this->bucket_size; hc = this->hasher(key) % this->bucket_size;
} }
// insert a new key if the key is not found // insert a new pair if the key is not found
Pair& new_pair = this->buckets[hc]->append (Pair(key)); Pair& new_pair = this->buckets[hc]->append (Pair(key));
this->pair_count++; this->pair_count++;
return &new_pair return &new_pair;
} }
#endif
/// The upsert() function inserts a new pair with a \a key and a \a value
/// if the key is not found in the table. If it is found, it updated the
/// existing pair with a given \a value.
Pair* upsert (const K& key, const V& value) Pair* upsert (const K& key, const V& value)
{ {
qse_size_t hc = this->hasher(key) % this->bucket_size; qse_size_t hc = this->hasher(key) % this->bucket_size;
@ -476,6 +484,7 @@ public:
Pair* pair = this->find_pair (key, hc); Pair* pair = this->find_pair (key, hc);
if (pair) if (pair)
{ {
// update the value of the existing pair
pair->value = value; pair->value = value;
return pair; return pair;
} }
@ -486,126 +495,14 @@ public:
hc = this->hasher(key) % this->bucket_size; hc = this->hasher(key) % this->bucket_size;
} }
// insert a new key if the key is not found // insert a new pair if the key is not found
Pair& new_pair = this->buckets[hc]->append (Pair(key,value)); Pair& new_pair = this->buckets[hc]->append (Pair(key, value));
this->pair_count++; this->pair_count++;
return &new_pair; return &new_pair;
/*
qse_size_t hc = this->hasher(key) % this->bucket_size;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (key == e.key)
{
e.value = value;
return &e.value;
}
}
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
Pair& e = this->buckets[hc]->append (Pair(key,value));
this->pair_count++;
return &e.value;
*/
} }
protected:
#if 0 int remove (qse_size_t hc, BucketNode* np)
V* insertNew (const K& key)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (key == e.key) return QSE_NULL;
}
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
Pair& e = this->buckets[hc]->append (Pair(key));
this->pair_count++;
return &e.value;
}
V* insertNew (const K& key, const V& value)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (key == e.key) return QSE_NULL;
}
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
Pair& e = this->buckets[hc]->append (Pair(key, value));
this->pair_count++;
return &e.value;
}
#endif
template <typename MK, typename MHASHER>
int removeWithCustomKey (const MK& key)
{
MHASHER h;
qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (key == e.key)
{
this->buckets[hc]->remove (np);
this->pair_count--;
return 0;
}
}
return -1;
}
int remove (const K& key)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (key == e.key)
{
this->buckets[hc]->remove (np);
this->pair_count--;
return 0;
}
}
return -1;
}
int remove (qse_size_t hc, typename Bucket::Node* np)
{ {
// //
// WARNING: this method should be used with extra care. // WARNING: this method should be used with extra care.
@ -615,59 +512,35 @@ public:
return 0; return 0;
} }
#if 0 public:
qse_size_t removeValue (const V& value) int remove (const K& key)
{
qse_size_t count = 0;
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
typename Bucket::Node* np, * np2;
np = this->buckets[i]->getHeadNode();
while (np != QSE_NULL)
{
Pair& e = np->value;
np2 = np->getNext ();
if (value == e.value)
{
this->remove (i, np);
count++;
}
np = np2;
}
}
return count;
}
#endif
bool containsKey (const K& key) const
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; BucketNode* np = this->find_pair_node (key, hc);
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) if (np)
{ {
Pair& e = np->value; this->remove (hc, np);
if (key == e.key) return true; return 0;
} }
return false; return -1;
} }
bool containsValue (const K& value) const template <typename MK, typename MHASHER, typename MCOMPARATOR>
int removeWithCustomKey (const MK& key)
{ {
for (qse_size_t i = 0; i < bucket_size; i++) MHASHER hash;
qse_size_t hc = hash(key) % this->bucket_size;
BucketNode* np = this->find_pair_node_with_custom_key<MK,MCOMPARATOR> (key, hc);
if (np)
{ {
typename Bucket::Node* np; this->remove (hc, np);
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) return 0;
{
Pair& e = np->value;
if (value == e.value) return true;
}
} }
return false; return -1;
} }
void clear (qse_size_t new_bucket_size = 0) void clear (qse_size_t new_bucket_size = 0)
@ -693,7 +566,7 @@ public:
{ {
for (qse_size_t i = 0; i < this->bucket_size; i++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
typename Bucket::Node* np; BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{ {
const Pair& e = np->value; const Pair& e = np->value;
@ -711,7 +584,7 @@ public:
{ {
for (qse_size_t i = 0; i < this->bucket_size; i++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
typename Bucket::Node* np; BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{ {
Pair& e = np->value; Pair& e = np->value;
@ -721,16 +594,17 @@ public:
return 0; return 0;
} }
protected: protected:
mutable qse_size_t pair_count; mutable qse_size_t pair_count;
mutable qse_size_t bucket_size; mutable qse_size_t bucket_size;
mutable Bucket** buckets; mutable Bucket** buckets;
mutable qse_size_t threshold; mutable qse_size_t threshold;
qse_size_t load_factor; qse_size_t load_factor;
HASHER hasher; qse_size_t bucket_mpb_size;
COMPARATOR comparator; HASHER hasher;
RESIZER resizer; COMPARATOR comparator;
RESIZER resizer;
void rehash () const void rehash () const
{ {
@ -742,7 +616,7 @@ protected:
for (qse_size_t i = 0; i < this->bucket_size; i++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
/* /*
typename Bucket::Node* np; BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{ {
const Pair& e = np->value; const Pair& e = np->value;
@ -756,10 +630,10 @@ protected:
// if the bucket uses a memory pool, this would not // if the bucket uses a memory pool, this would not
// work. fortunately, the hash table doesn't use it // work. fortunately, the hash table doesn't use it
// for a bucket. // for a bucket.
typename Bucket::Node* np = this->buckets[i]->getHeadNode(); BucketNode* np = this->buckets[i]->getHeadNode();
while (np) while (np)
{ {
typename Bucket::Node* next = np->getNext(); BucketNode* next = np->getNext();
const Pair& e = np->value; const Pair& e = np->value;
qse_size_t hc = this->hasher(e.key) % new_bucket_size; qse_size_t hc = this->hasher(e.key) % new_bucket_size;
new_buckets[hc]->appendNode (this->buckets[i]->yield(np)); new_buckets[hc]->appendNode (this->buckets[i]->yield(np));

View File

@ -34,14 +34,14 @@
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
template <typename T, typename MPOOL> class LinkedList; template <typename T, typename MPOOL, typename COMPARATOR> class LinkedList;
template <typename T,typename MPOOL> template <typename T, typename MPOOL, typename COMPARATOR>
class LinkedListNode class LinkedListNode
{ {
public: public:
friend class LinkedList<T,MPOOL>; friend class LinkedList<T,MPOOL,COMPARATOR>;
typedef LinkedListNode<T,MPOOL> SelfType; typedef LinkedListNode<T,MPOOL,COMPARATOR> SelfType;
T value; // you can use this variable or accessor functions below T value; // you can use this variable or accessor functions below
@ -79,14 +79,120 @@ protected:
} }
}; };
template <typename T, typename MPOOL, typename COMPARATOR>
class LinkedListIterator {
public:
friend class LinkedList<T,MPOOL,COMPARATOR>;
typedef LinkedListNode<T,MPOOL,COMPARATOR> Node;
typedef LinkedListIterator<T,MPOOL,COMPARATOR> SelfType;
LinkedListIterator (): current(QSE_NULL) {}
LinkedListIterator (Node* node): current(node) {}
LinkedListIterator (const SelfType& it): current (it.current) {}
SelfType& operator= (const SelfType& it)
{
this->current = it.current;
return *this;
}
SelfType& operator++ () // prefix increment
{
QSE_ASSERT (this->current != QSE_NULL);
this->current = this->current->getNext();
return *this;
}
SelfType operator++ (int) // postfix increment
{
QSE_ASSERT (this->current != QSE_NULL);
SelfType saved (*this);
this->current = this->current->getNext(); //++(*this);
return saved;
}
SelfType& operator-- () // prefix decrement
{
QSE_ASSERT (this->current != QSE_NULL);
this->current = this->current->getPrev();
return *this;
}
SelfType operator-- (int) // postfix decrement
{
QSE_ASSERT (this->current != QSE_NULL);
SelfType saved (*this);
this->current = this->current->getPrev(); //--(*this);
return saved;
}
int operator== (const SelfType& it) const
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current == it.current;
}
int operator!= (const SelfType& it) const
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current != it.current;
}
bool isValid () const
{
return this->current != QSE_NULL;
}
T& getValue ()
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current->getValue();
}
const T& getValue () const
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current->getValue();
}
SelfType& setValue (const T& v)
{
QSE_ASSERT (this->current != QSE_NULL);
this->current->setValue (v);
return *this;
}
Node* getNode ()
{
return this->current;
}
protected:
Node* current;
};
template<typename T>
struct LinkedListComparator
{
// it must return true if two values are equal
bool operator() (const T& v1, const T& v2) const
{
return v1 == v2;
}
};
/// ///
/// The LinkedList<T,MPOOL> class provides a template for a doubly-linked list. /// The LinkedList<T,MPOOL> class provides a template for a doubly-linked list.
/// ///
template <typename T, typename MPOOL = Mpool> class LinkedList: public Mmged template <typename T, typename MPOOL = Mpool, typename COMPARATOR = LinkedListComparator<T> > class LinkedList: public Mmged
{ {
public: public:
typedef LinkedList<T,MPOOL> SelfType; typedef LinkedList<T,MPOOL,COMPARATOR> SelfType;
typedef LinkedListNode<T,MPOOL> Node; typedef LinkedListNode<T,MPOOL,COMPARATOR> Node;
typedef LinkedListIterator<T,MPOOL,COMPARATOR> Iterator;
typedef Mpool DefaultMpool;
typedef LinkedListComparator<T> DefaultComparator;
enum enum
{ {
@ -168,7 +274,35 @@ public:
// insert an externally created node. // insert an externally created node.
// may need to take extra care when using this method. // may need to take extra care when using this method.
Node* insertNode (Node* pos, Node* node); Node* insertNode (Node* pos, Node* node)
{
if (pos == QSE_NULL)
{
if (this->node_count == 0)
{
QSE_ASSERT (head_node == QSE_NULL);
QSE_ASSERT (tail_node == QSE_NULL);
this->head_node = this->tail_node = node;
}
else
{
node->prev = this->tail_node;
this->tail_node->next = node;
this->tail_node = node;
}
}
else
{
node->next = pos;
node->prev = pos->prev;
if (pos->prev) pos->prev->next = node;
else this->head_node = node;
pos->prev = node;
}
this->node_count++;
return node;
}
// create a new node to hold the value and insert it. // create a new node to hold the value and insert it.
Node* insertValue (Node* pos, const T& value) Node* insertValue (Node* pos, const T& value)
@ -432,7 +566,7 @@ public:
{ {
for (Node* p = this->head_node; p; p = p->next) for (Node* p = this->head_node; p; p = p->next)
{ {
if (value == p->value) return p; if (this->comparator (value, p->value)) return p;
} }
return QSE_NULL; return QSE_NULL;
} }
@ -441,7 +575,7 @@ public:
{ {
for (Node* p = tail_node; p; p = p->prev) for (Node* p = tail_node; p; p = p->prev)
{ {
if (value == p->value) return p; if (this->comparator (value, p->value)) return p;
} }
return QSE_NULL; return QSE_NULL;
} }
@ -450,7 +584,7 @@ public:
{ {
for (Node* p = head; p; p = p->next) for (Node* p = head; p; p = p->next)
{ {
if (value == p->value) return p; if (this->comparator (value, p->value)) return p;
} }
return QSE_NULL; return QSE_NULL;
} }
@ -459,17 +593,17 @@ public:
{ {
for (Node* p = tail; p; p = p->prev) for (Node* p = tail; p; p = p->prev)
{ {
if (value == p->value) return p; if (this->comparator (value, p->value)) return p;
} }
return QSE_NULL; return QSE_NULL;
} }
qse_size_t findFirstIndex (const T& value) const qse_size_t findFirstIndex (const T& value) const
{ {
qse_size_t index = 0; qse_size_t index = 0;
for (Node* p = this->head_node; p; p = p->next) for (Node* p = this->head_node; p; p = p->next)
{ {
if (value == p->value) return index; if (this->comparator (value, p->value)) return index;
index++; index++;
} }
return INVALID_INDEX; return INVALID_INDEX;
@ -481,7 +615,7 @@ public:
for (Node* p = tail_node; p; p = p->prev) for (Node* p = tail_node; p; p = p->prev)
{ {
index--; index--;
if (value == p->value) return index; if (this->comparator (value, p->value)) return index;
} }
return INVALID_INDEX; return INVALID_INDEX;
} }
@ -513,6 +647,11 @@ public:
this->mp.dispose (); this->mp.dispose ();
} }
//void reverse ()
//{
//
//}
typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur);
void traverse (TraverseCallback callback, Node* start) void traverse (TraverseCallback callback, Node* start)
@ -533,44 +672,19 @@ public:
} }
} }
Iterator getIterator (qse_size_t index = 0) const
{
return Iterator (this->getNodeAt(index));
}
protected: protected:
MPOOL mp; MPOOL mp;
COMPARATOR comparator;
Node* head_node; Node* head_node;
Node* tail_node; Node* tail_node;
qse_size_t node_count; qse_size_t node_count;
}; };
template <typename T,typename MPOOL>
inline typename LinkedList<T,MPOOL>::Node* LinkedList<T,MPOOL>::insertNode (Node* pos, Node* node)
{
if (pos == QSE_NULL)
{
if (this->node_count == 0)
{
QSE_ASSERT (head_node == QSE_NULL);
QSE_ASSERT (tail_node == QSE_NULL);
this->head_node = this->tail_node = node;
}
else
{
node->prev = this->tail_node;
this->tail_node->next = node;
this->tail_node = node;
}
}
else
{
node->next = pos;
node->prev = pos->prev;
if (pos->prev) pos->prev->next = node;
else this->head_node = node;
pos->prev = node;
}
this->node_count++;
return node;
}
///////////////////////////////// /////////////////////////////////
QSE_END_NAMESPACE(QSE) QSE_END_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////