refactored HashTable, HashList, LinkedList
This commit is contained in:
parent
8c15d39d9a
commit
890097af66
@ -72,6 +72,10 @@ public:
|
||||
typedef typename DatumList::Node Node;
|
||||
typedef HashList<T,MPOOL,HASHER,COMPARATOR> SelfType;
|
||||
|
||||
typedef HashListHasher<T> DefaultHasher;
|
||||
typedef HashListComparator<T> DefaultComparator;
|
||||
typedef HashListResizer DefaultResizer;
|
||||
|
||||
HashList (
|
||||
Mmgr* mmgr = QSE_NULL,
|
||||
qse_size_t node_capacity = 10,
|
||||
@ -221,7 +225,46 @@ public:
|
||||
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:
|
||||
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)
|
||||
{
|
||||
qse_size_t hc, head, tail;
|
||||
@ -269,46 +312,10 @@ protected:
|
||||
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:
|
||||
Node* findNode (const T& datum)
|
||||
{
|
||||
return (Node*)this->find_node (datum);
|
||||
return this->find_node (datum);
|
||||
}
|
||||
|
||||
const Node* findNode (const T& datum) const
|
||||
@ -330,14 +337,37 @@ public:
|
||||
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)
|
||||
@ -392,16 +422,6 @@ public:
|
||||
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);
|
||||
|
||||
void traverse (TraverseCallback callback, Node* start)
|
||||
@ -434,13 +454,13 @@ public:
|
||||
|
||||
protected:
|
||||
mutable qse_size_t node_capacity;
|
||||
mutable Node** nodes;
|
||||
mutable Node** nodes;
|
||||
mutable DatumList* datum_list;
|
||||
mutable qse_size_t threshold;
|
||||
qse_size_t load_factor;
|
||||
HASHER hasher;
|
||||
COMPARATOR comparator;
|
||||
RESIZER resizer;
|
||||
qse_size_t load_factor;
|
||||
HASHER hasher;
|
||||
COMPARATOR comparator;
|
||||
RESIZER resizer;
|
||||
|
||||
void rehash ()
|
||||
{
|
||||
|
@ -72,8 +72,13 @@ class HashTable: public Mmged
|
||||
public:
|
||||
typedef Couple<K,V> Pair;
|
||||
typedef LinkedList<Pair> Bucket;
|
||||
typedef typename LinkedList<Pair>::Node BucketNode;
|
||||
typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType;
|
||||
|
||||
typedef HashTableHasher<K> DefaultHasher;
|
||||
typedef HashTableComparator<K> DefaultComparator;
|
||||
typedef HashTableResizer DefaultResizer;
|
||||
|
||||
protected:
|
||||
Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs) const
|
||||
{
|
||||
@ -84,7 +89,7 @@ protected:
|
||||
b = (Bucket**) mm->callocate (QSE_SIZEOF(*b) * bs);
|
||||
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 (...)
|
||||
@ -124,13 +129,14 @@ protected:
|
||||
}
|
||||
|
||||
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->bucket_size = bucket_size;
|
||||
this->pair_count = 0;
|
||||
this->load_factor = load_factor;
|
||||
this->threshold = bucket_size * load_factor / 100;
|
||||
this->bucket_mpb_size = bucket_mpb_size;
|
||||
}
|
||||
|
||||
HashTable (const SelfType& table): Mmged (table)
|
||||
@ -140,11 +146,12 @@ public:
|
||||
this->pair_count = 0;
|
||||
this->load_factor = table.load_factor;
|
||||
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++)
|
||||
{
|
||||
Bucket* b = table.buckets[i];
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = b->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
@ -171,7 +178,7 @@ public:
|
||||
for (qse_size_t i = 0; i < table.bucket_size; i++)
|
||||
{
|
||||
Bucket* b = table.buckets[i];
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = b->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
@ -185,6 +192,20 @@ public:
|
||||
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
|
||||
{
|
||||
return this->pair_count;
|
||||
@ -218,111 +239,45 @@ public:
|
||||
return this->buckets[index];
|
||||
}
|
||||
|
||||
#if 0
|
||||
V& operator[] (const K& key)
|
||||
protected:
|
||||
BucketNode* find_pair_node (const K& key, qse_size_t hc) const
|
||||
{
|
||||
qse_size_t hc = this->hasher(key) % this->bucket_size;
|
||||
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (this->comparator (key, e.key)) return e.value;
|
||||
if (this->comparator(key, e.key)) return np;
|
||||
}
|
||||
|
||||
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;
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Pair* pair = this->find_pair (key, hc);
|
||||
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;
|
||||
BucketNode* np = this->find_pair_node (key, hc);
|
||||
if (np) return &np->value;
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
template <typename MK, typename MHASHER, typename MCOMPARATOR>
|
||||
Pair* find_pair_with_custom_key (const MK& key) const
|
||||
template <typename MK, typename MCOMPARATOR>
|
||||
BucketNode* find_pair_node_with_custom_key (const MK& key, qse_size_t hc) const
|
||||
{
|
||||
MHASHER hash;
|
||||
MCOMPARATOR is_equal;
|
||||
|
||||
qse_size_t hc = hash(key) % this->bucket_size;
|
||||
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (is_equal(key, e.key)) return &e;
|
||||
if (is_equal(key, e.key)) return np;
|
||||
}
|
||||
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
/// \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>
|
||||
const Pair* findPairWithCustomKey (const MK& key) const
|
||||
template <typename MK, typename MCOMPARATOR>
|
||||
Pair* find_pair_with_custom_key (const MK& key, qse_size_t hc) const
|
||||
{
|
||||
return this->find_pair_with_custom_key<MK,MHASHER,MCOMPARATOR> (key);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BucketNode* np = this->find_pair_node_with_custom_key<MK,MCOMPARATOR> (key, hc);
|
||||
if (np) return &np->value;
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
@ -351,15 +306,15 @@ public:
|
||||
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;
|
||||
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (this->comparator (key, e.key))
|
||||
if (this->comparator(key, e.key))
|
||||
{
|
||||
*hash_code = hc;
|
||||
*node = np;
|
||||
@ -370,15 +325,15 @@ public:
|
||||
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;
|
||||
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (this->comparator (key, e.key))
|
||||
if (this->comparator(key, e.key))
|
||||
{
|
||||
*hash_code = hc;
|
||||
*node = np;
|
||||
@ -389,27 +344,68 @@ public:
|
||||
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);
|
||||
return 0;
|
||||
MHASHER hash;
|
||||
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)
|
||||
{
|
||||
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 (this->comparator (key, e.key)) return &e;
|
||||
}
|
||||
Pair* pair = this->find_pair (key, hc);
|
||||
if (pair) return QSE_NULL; // existing pair found.
|
||||
|
||||
if (this->pair_count >= threshold)
|
||||
{
|
||||
@ -417,21 +413,21 @@ public:
|
||||
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++;
|
||||
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)
|
||||
{
|
||||
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 (this->comparator (key, e.key)) return &e;
|
||||
}
|
||||
Pair* pair = this->find_pair (key, hc);
|
||||
if (pair) return QSE_NULL; // existing pair found.
|
||||
|
||||
if (this->pair_count >= threshold)
|
||||
{
|
||||
@ -439,22 +435,32 @@ public:
|
||||
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++;
|
||||
return &e;
|
||||
return &new_pair;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Pair* upsert (const K& Key)
|
||||
/// The update() function updates an existing pair of the \a 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;
|
||||
|
||||
Pair* pair = this->find_pair (key, hc);
|
||||
if (pair)
|
||||
{
|
||||
// don't change the existing value.
|
||||
return pair
|
||||
}
|
||||
if (pair) return pair; // return the existing pair
|
||||
|
||||
if (this->pair_count >= threshold)
|
||||
{
|
||||
@ -462,13 +468,15 @@ public:
|
||||
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));
|
||||
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)
|
||||
{
|
||||
qse_size_t hc = this->hasher(key) % this->bucket_size;
|
||||
@ -476,6 +484,7 @@ public:
|
||||
Pair* pair = this->find_pair (key, hc);
|
||||
if (pair)
|
||||
{
|
||||
// update the value of the existing pair
|
||||
pair->value = value;
|
||||
return pair;
|
||||
}
|
||||
@ -486,126 +495,14 @@ public:
|
||||
hc = this->hasher(key) % this->bucket_size;
|
||||
}
|
||||
|
||||
// insert a new key if the key is not found
|
||||
Pair& new_pair = this->buckets[hc]->append (Pair(key,value));
|
||||
// insert a new pair if the key is not found
|
||||
Pair& new_pair = this->buckets[hc]->append (Pair(key, value));
|
||||
this->pair_count++;
|
||||
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;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
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)
|
||||
protected:
|
||||
int remove (qse_size_t hc, BucketNode* np)
|
||||
{
|
||||
//
|
||||
// WARNING: this method should be used with extra care.
|
||||
@ -615,59 +512,35 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
qse_size_t removeValue (const V& value)
|
||||
{
|
||||
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
|
||||
public:
|
||||
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())
|
||||
|
||||
BucketNode* np = this->find_pair_node (key, hc);
|
||||
if (np)
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (key == e.key) return true;
|
||||
this->remove (hc, np);
|
||||
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;
|
||||
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
if (value == e.value) return true;
|
||||
}
|
||||
this->remove (hc, np);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
typename Bucket::Node* np;
|
||||
BucketNode* np;
|
||||
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
|
||||
{
|
||||
const Pair& e = np->value;
|
||||
@ -711,7 +584,7 @@ public:
|
||||
{
|
||||
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())
|
||||
{
|
||||
Pair& e = np->value;
|
||||
@ -721,16 +594,17 @@ public:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
mutable qse_size_t pair_count;
|
||||
mutable qse_size_t bucket_size;
|
||||
mutable Bucket** buckets;
|
||||
mutable qse_size_t threshold;
|
||||
qse_size_t load_factor;
|
||||
HASHER hasher;
|
||||
COMPARATOR comparator;
|
||||
RESIZER resizer;
|
||||
qse_size_t load_factor;
|
||||
qse_size_t bucket_mpb_size;
|
||||
HASHER hasher;
|
||||
COMPARATOR comparator;
|
||||
RESIZER resizer;
|
||||
|
||||
void rehash () const
|
||||
{
|
||||
@ -742,7 +616,7 @@ protected:
|
||||
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())
|
||||
{
|
||||
const Pair& e = np->value;
|
||||
@ -756,10 +630,10 @@ protected:
|
||||
// if the bucket uses a memory pool, this would not
|
||||
// work. fortunately, the hash table doesn't use it
|
||||
// for a bucket.
|
||||
typename Bucket::Node* np = this->buckets[i]->getHeadNode();
|
||||
BucketNode* np = this->buckets[i]->getHeadNode();
|
||||
while (np)
|
||||
{
|
||||
typename Bucket::Node* next = np->getNext();
|
||||
BucketNode* next = np->getNext();
|
||||
const Pair& e = np->value;
|
||||
qse_size_t hc = this->hasher(e.key) % new_bucket_size;
|
||||
new_buckets[hc]->appendNode (this->buckets[i]->yield(np));
|
||||
|
@ -34,14 +34,14 @@
|
||||
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
|
||||
{
|
||||
public:
|
||||
friend class LinkedList<T,MPOOL>;
|
||||
typedef LinkedListNode<T,MPOOL> SelfType;
|
||||
friend class LinkedList<T,MPOOL,COMPARATOR>;
|
||||
typedef LinkedListNode<T,MPOOL,COMPARATOR> SelfType;
|
||||
|
||||
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.
|
||||
///
|
||||
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:
|
||||
typedef LinkedList<T,MPOOL> SelfType;
|
||||
typedef LinkedListNode<T,MPOOL> Node;
|
||||
typedef LinkedList<T,MPOOL,COMPARATOR> SelfType;
|
||||
typedef LinkedListNode<T,MPOOL,COMPARATOR> Node;
|
||||
typedef LinkedListIterator<T,MPOOL,COMPARATOR> Iterator;
|
||||
|
||||
typedef Mpool DefaultMpool;
|
||||
typedef LinkedListComparator<T> DefaultComparator;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -168,7 +274,35 @@ public:
|
||||
|
||||
// insert an externally created node.
|
||||
// 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.
|
||||
Node* insertValue (Node* pos, const T& value)
|
||||
@ -432,7 +566,7 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -441,7 +575,7 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -450,7 +584,7 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -459,17 +593,17 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
qse_size_t findFirstIndex (const T& value) const
|
||||
{
|
||||
qse_size_t index = 0;
|
||||
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++;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
@ -481,7 +615,7 @@ public:
|
||||
for (Node* p = tail_node; p; p = p->prev)
|
||||
{
|
||||
index--;
|
||||
if (value == p->value) return index;
|
||||
if (this->comparator (value, p->value)) return index;
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
@ -513,6 +647,11 @@ public:
|
||||
this->mp.dispose ();
|
||||
}
|
||||
|
||||
//void reverse ()
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur);
|
||||
|
||||
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:
|
||||
MPOOL mp;
|
||||
COMPARATOR comparator;
|
||||
Node* head_node;
|
||||
Node* tail_node;
|
||||
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)
|
||||
/////////////////////////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user