refactored HashTable, HashList, LinkedList
This commit is contained in:
parent
8c15d39d9a
commit
890097af66
@ -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)
|
||||||
|
@ -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)
|
Pair* find_pair (const K& key, qse_size_t hc) const
|
||||||
{
|
{
|
||||||
this->rehash ();
|
BucketNode* np = this->find_pair_node (key, hc);
|
||||||
hc = this->hasher(key) % bucket_size;
|
if (np) return &np->value;
|
||||||
|
return QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert a new key if the key is not found
|
template <typename MK, typename MCOMPARATOR>
|
||||||
Pair& e2 = this->buckets[hc]->append (Pair(key));
|
BucketNode* find_pair_node_with_custom_key (const MK& key, qse_size_t hc) const
|
||||||
this->pair_count++;
|
|
||||||
return e2.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const V& operator[] (const K& key) 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;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
template <typename MK, typename MHASHER, typename MCOMPARATOR>
|
|
||||||
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)
|
protected:
|
||||||
{
|
int remove (qse_size_t hc, BucketNode* np)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// 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;
|
||||||
@ -728,6 +601,7 @@ protected:
|
|||||||
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;
|
||||||
|
qse_size_t bucket_mpb_size;
|
||||||
HASHER hasher;
|
HASHER hasher;
|
||||||
COMPARATOR comparator;
|
COMPARATOR comparator;
|
||||||
RESIZER resizer;
|
RESIZER resizer;
|
||||||
@ -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));
|
||||||
|
@ -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,7 +593,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -469,7 +603,7 @@ public:
|
|||||||
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)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user