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 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)

View File

@ -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;
}
return QSE_NULL;
}
if (this->pair_count >= threshold)
Pair* find_pair (const K& key, qse_size_t hc) const
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
BucketNode* np = this->find_pair_node (key, hc);
if (np) return &np->value;
return QSE_NULL;
}
// 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
template <typename MK, typename MCOMPARATOR>
BucketNode* find_pair_node_with_custom_key (const MK& 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;
}
#endif
protected:
template <typename MK, typename MHASHER, typename MCOMPARATOR>
Pair* find_pair_with_custom_key (const MK& key) 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;
@ -728,6 +601,7 @@ protected:
mutable Bucket** buckets;
mutable qse_size_t threshold;
qse_size_t load_factor;
qse_size_t bucket_mpb_size;
HASHER hasher;
COMPARATOR comparator;
RESIZER resizer;
@ -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));

View File

@ -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,7 +593,7 @@ 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;
}
@ -469,7 +603,7 @@ public:
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)
/////////////////////////////////