simplified HashTable, HashList, LinkedList

This commit is contained in:
hyung-hwan 2015-02-27 14:19:04 +00:00
parent ca8956366c
commit 06dbccbc06
6 changed files with 188 additions and 790 deletions

View File

@ -24,8 +24,8 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QSE_CMN_COUPLE_HPP_
#define _QSE_CMN_COUPLE_HPP_
#ifndef _QSE_CMN_ASSOCIATION_HPP_
#define _QSE_CMN_ASSOCIATION_HPP_
#include <qse/types.h>
#include <qse/macros.h>
@ -34,24 +34,25 @@
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
template <typename KEY, typename VALUE> class Couple
template <typename K, typename V>
class Association
{
public:
KEY key;
VALUE value;
K key;
V value;
Couple () {}
Couple (const KEY& key): key (key) {}
Couple (const KEY& key, const VALUE& value): key (key), value (value) {}
Association () {}
Association (const K& key): key (key) {}
Association (const K& key, const V& value): key (key), value (value) {}
KEY& getKey () { return this->key; }
const KEY& getKey () const { return this->key; }
K& getKey () { return this->key; }
const K& getKey () const { return this->key; }
VALUE& getValue () { return this->value; }
const VALUE& getValue () const { return this->value; }
V& getValue () { return this->value; }
const V& getValue () const { return this->value; }
void setKey (const KEY& key) { this->key = key; }
void setValue (const VALUE& value) { this->value = value; }
void setKey (const K& key) { this->key = key; }
void setValue (const V& value) { this->value = value; }
};
/////////////////////////////////

View File

@ -83,7 +83,7 @@ public:
typedef LinkedList<T,COMPARATOR> DatumList;
typedef typename DatumList::Node Node;
typedef typename DatumList::Iterator Iterator;
typedef typename DatumList::Visiter Visiter;
typedef typename DatumList::ConstIterator ConstIterator;
typedef HashList<T,HASHER,COMPARATOR,RESIZER> SelfType;
typedef HashListHasher<T> DefaultHasher;
@ -213,21 +213,11 @@ public:
~HashList ()
{
this->clear ();
this->clear (true);
if (this->nodes) this->getMmgr()->dispose (this->nodes); //delete[] this->nodes;
if (this->datum_list) this->free_datum_list ();
}
Mpool& getMpool ()
{
return this->datum_list->getMpool ();
}
const Mpool& getMpool() const
{
return this->datum_list->getMpool ();
}
SelfType& operator= (const SelfType& list)
{
this->clear ();
@ -254,19 +244,49 @@ public:
return *this;
}
Mpool& getMpool ()
{
return this->datum_list->getMpool ();
}
const Mpool& getMpool() const
{
return this->datum_list->getMpool ();
}
qse_size_t getCapacity() const
{
return this->node_capacity;
}
qse_size_t getSize () const
{
return this->datum_list->getSize ();
}
bool isEmpty () const
{
return this->datum_list->isEmpty();
return this->datum_list->isEmpty ();
}
Node* getHeadNode () const
Node* getHeadNode ()
{
return this->datum_list->getHeadNode();
return this->datum_list->getHeadNode ();
}
Node* getTaileNode () const
const Node* getHeadNode () const
{
return this->datum_list->getTailNode();
return this->datum_list->getHeadNode ();
}
Node* getTailNode ()
{
return this->datum_list->getTailNode ();
}
const Node* getTailNode () const
{
return this->datum_list->getTailNode ();
}
protected:
@ -548,48 +568,13 @@ public:
return -1;
}
void clear ()
void clear (bool clear_mpool = false)
{
for (qse_size_t i = 0; i < (this->node_capacity << 1); i++)
{
this->nodes[i] = QSE_NULL;
}
if (this->datum_list) this->datum_list->clear ();
}
typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur);
void traverse (TraverseCallback callback, Node* start)
{
Node* cur, *prev, * next;
cur = start;
while (cur)
{
prev = cur->getPrevNode ();
next = cur->getNextNode ();
int n = (this->*callback) (start, cur);
if (n > 0) cur = next;
else if (n < 0) cur = prev;
else break;
}
}
void traverse (Visiter& visiter)
{
return this->datum_list->traverse (visiter);
}
qse_size_t getCapacity() const
{
return this->node_capacity;
}
qse_size_t getSize () const
{
return this->datum_list->getSize();
this->datum_list->clear (clear_mpool);
}
/// The getIterator() function returns an interator.
@ -617,6 +602,11 @@ public:
return this->datum_list->getIterator (index);
}
ConstIterator getConstIterator (qse_size_t index = 0) const
{
return this->datum_list->getConstIterator (index);
}
protected:
mutable qse_size_t node_capacity;
mutable Node** nodes;

View File

@ -27,10 +27,7 @@
#ifndef _QSE_CMN_HASHTABLE_HPP_
#define _QSE_CMN_HASHTABLE_HPP_
/*#include <qse/Hashable.hpp>
#include <qse/cmn/LinkedList.hpp>*/
#include <qse/cmn/Couple.hpp>
#include <qse/cmn/Association.hpp>
#include <qse/cmn/HashList.hpp>
/////////////////////////////////
@ -56,27 +53,13 @@ struct HashTableComparator
}
};
#if 0
struct HashTableResizer
{
qse_size_t operator() (qse_size_t current) const
{
return (current < 5000)? (current + current):
(current < 50000)? (current + (current / 2)):
(current < 100000)? (current + (current / 4)):
(current < 150000)? (current + (current / 8)):
(current + (current / 16));
}
};
#endif
typedef HashListResizer HashTableResizer;
template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename COMPARATOR = HashTableComparator<K>, typename RESIZER = HashTableResizer>
class HashTable: public Mmged
{
public:
typedef Couple<K,V> Pair;
typedef Association<K,V> Pair;
typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType;
typedef HashTableHasher<K> DefaultHasher;
@ -123,6 +106,7 @@ public:
typedef HashList<Pair,PairHasher,PairComparator,RESIZER> PairList;
typedef typename PairList::Node PairNode;
typedef typename PairList::Iterator Iterator;
typedef typename PairList::ConstIterator ConstIterator;
enum
{
@ -153,12 +137,47 @@ public:
Mpool& getMpool ()
{
return this->datum_list->getMpool();
return this->pair_list.getMpool ();
}
const Mpool& getMpool () const
{
return this->datum_list->getMpool();
return this->pair_list.getMpool ();
}
qse_size_t getCapacity() const
{
return this->pair_list.getCapacity ();
}
qse_size_t getSize() const
{
return this->pair_list.getSize ();
}
bool isEmpty () const
{
return this->pair_list.isEmpty ();
}
PairNode* getHeadNode ()
{
return this->pair_list.getHeadNode ();
}
const PairNode* getHeadNode () const
{
return this->pair_list.getHeadNode ();
}
PairNode* getTailNode ()
{
return this->pair_list.getTailNode ();
}
const PairNode* getTailNode () const
{
return this->pair_list.getTailNode ();
}
Pair* insert (const K& key, const V& value)
@ -177,7 +196,6 @@ public:
Pair* update (const K& key, const V& value)
{
//PairNode* node = this->pair_list.update (Pair(key, value));
//if (!node) return QSE_NULL;
//return &node->value;
@ -228,632 +246,25 @@ public:
return this->pair_list.template heteroremove<MK,MHASHER,MComparator> (key);
}
void clear ()
void clear (bool clear_mpool = false)
{
// TODO: accept new capacity.
return this->pair_list.clear ();
return this->pair_list.clear (clear_mpool);
}
qse_size_t getSize() const
{
return this->pair_list.getSize ();
}
Iterator getIterator (qse_size_t index = 0)
{
return this->pair_list.getIterator (index);
}
ConstIterator getConstIterator (qse_size_t index = 0) const
{
return this->pair_list.getConstIterator (index);
}
protected:
PairList pair_list;
};
#if 0
template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename COMPARATOR = HashTableComparator<K>, typename RESIZER = HashTableResizer>
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;
enum
{
DEFAULT_CAPACITY = 10,
DEFAULT_LOAD_FACTOR = 75, // Load factor in percentage
MIN_CAPACITY = 1,
MIN_LOAD_FACTOR = 20
};
protected:
Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs, qse_size_t mpb_size) const
{
Bucket** b = QSE_NULL;
try
{
b = (Bucket**) mm->callocate (QSE_SIZEOF(*b) * bs);
for (qse_size_t i = 0; i < bs; i++)
{
b[i] = new(mm) Bucket (mm, mpb_size);
}
}
catch (...)
{
if (b)
{
for (qse_size_t i = bs; i > 0;)
{
i--;
if (b[i])
{
b[i]->~Bucket ();
::operator delete (b, mm);
}
}
mm->dispose (b);
}
throw;
}
return b;
}
void dispose_bucket (Mmgr* mm, Bucket** b, qse_size_t bs) const
{
for (qse_size_t i = bs; i > 0;)
{
i--;
if (b[i])
{
b[i]->~Bucket ();
::operator delete (b[i], mm);
}
}
mm->dispose (b);
}
public:
HashTable (Mmgr* mmgr, qse_size_t bucket_size = DEFAULT_CAPACITY, qse_size_t load_factor = DEFAULT_LOAD_FACTOR, qse_size_t bucket_mpb_size = 0): Mmged(mmgr)
{
if (bucket_size < MIN_CAPACITY) bucket_size = MIN_CAPACITY;
if (load_factor < MIN_LOAD_FACTOR) load_factor = MIN_LOAD_FACTOR;
this->buckets = this->allocate_bucket (this->getMmgr(), bucket_size, bucket_mpb_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)
{
this->buckets = this->allocate_bucket (this->getMmgr(), table.bucket_size, table.bucket_mpb_size);
this->bucket_size = table.bucket_size;
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];
BucketNode* np;
for (np = b->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc]->append (e);
this->pair_count++;
}
}
// no rehashing is needed in the copy constructor.
//if (this->pair_count >= threshold) this->rehash ();
}
~HashTable ()
{
this->clear ();
this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
}
SelfType& operator= (const SelfType& table)
{
this->clear ();
for (qse_size_t i = 0; i < table.bucket_size; i++)
{
Bucket* b = table.buckets[i];
BucketNode* np;
for (np = b->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc]->append (e);
this->pair_count++;
}
}
if (this->pair_count >= this->threshold) this->rehash ();
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;
}
bool isEmpty () const
{
return this->pair_count == 0;
}
/// The getBucketSize() function returns the number of
/// pair list currently existing.
qse_size_t getBucketSize () const
{
return this->bucket_size;
}
/// The getBucket() function returns the pointer to the
/// list of pairs of the given hash value \a index.
Bucket* getBucket (qse_size_t index)
{
QSE_ASSERT (index < this->bucket_size);
return this->buckets[index];
}
/// The getBucket() function returns the pointer to the
/// list of pairs of the given hash value \a index.
const Bucket* getBucket (qse_size_t index) const
{
QSE_ASSERT (index < this->bucket_size);
return this->buckets[index];
}
protected:
BucketNode* find_pair_node (const K& key, qse_size_t hc) const
{
BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (this->comparator(key, e.key)) return np;
}
return QSE_NULL;
}
Pair* find_pair (const K& key, qse_size_t hc) const
{
BucketNode* np = this->find_pair_node (key, hc);
if (np) return &np->value;
return QSE_NULL;
}
template <typename MK, typename MCOMPARATOR>
BucketNode* find_pair_node_with_custom_key (const MK& key, qse_size_t hc) const
{
MCOMPARATOR is_equal;
BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (is_equal(key, e.key)) return np;
}
return QSE_NULL;
}
template <typename MK, typename MCOMPARATOR>
Pair* find_pair_with_custom_key (const MK& key, qse_size_t hc) const
{
BucketNode* np = this->find_pair_node_with_custom_key<MK,MCOMPARATOR> (key, hc);
if (np) return &np->value;
return QSE_NULL;
}
public:
Pair* findPair (const K& key)
{
return this->find_pair (key, this->hasher(key) % this->bucket_size);
}
const Pair* findPair (const K& key) const
{
return this->find_pair (key, this->hasher(key) % this->bucket_size);
}
V* findValue (const K& key)
{
Pair* pair = this->findPair (key);
if (pair) return &pair->value;
return QSE_NULL;
}
const V* findValue (const K& key) const
{
const Pair* pair = this->findPair (key);
if (pair) return &pair->value;
return QSE_NULL;
}
V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node)
{
qse_size_t hc = this->hasher(key) % bucket_size;
BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (this->comparator(key, e.key))
{
*hash_code = hc;
*node = np;
return &e.value;
}
}
return QSE_NULL;
}
const V* findValue (const K& key, qse_size_t* hash_code, BucketNode** node) const
{
qse_size_t hc = this->hasher(key) % bucket_size;
BucketNode* np;
for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (this->comparator(key, e.key))
{
*hash_code = hc;
*node = np;
return &e.value;
}
}
return QSE_NULL;
}
/// \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)
{
MHASHER hash;
return this->find_pair_with_custom_key<MK,MCOMPARATOR> (key, hash(key) % this->bucket_size);
}
template <typename MK, typename MHASHER, typename MCOMPARATOR>
const Pair* findPairWithCustomKey (const MK& key) const
{
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;
Pair* pair = this->find_pair (key, hc);
if (pair) return QSE_NULL; // existing pair found.
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
// insert a new pair
BucketNode* node = this->buckets[hc]->append (Pair(key));
this->pair_count++;
return &node->value;
}
/// 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;
Pair* pair = this->find_pair (key, hc);
if (pair) return QSE_NULL; // existing pair found.
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
// insert a new pair
BucketNode* node = this->buckets[hc]->append (Pair(key, value));
this->pair_count++;
return &node->value;
}
/// 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) return pair; // return the existing pair
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % this->bucket_size;
}
// insert a new pair if the key is not found
BucketNode* node = this->buckets[hc]->append (Pair(key));
this->pair_count++;
return &node->value;
}
/// 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;
Pair* pair = this->find_pair (key, hc);
if (pair)
{
// update the value of the existing pair
pair->value = value;
return pair;
}
if (this->pair_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % this->bucket_size;
}
// insert a new pair if the key is not found
BucketNode* node = this->buckets[hc]->append (Pair(key, value));
this->pair_count++;
return &node->value;
}
protected:
int remove (qse_size_t hc, BucketNode* np)
{
//
// WARNING: this method should be used with extra care.
//
this->buckets[hc]->remove (np);
this->pair_count--;
return 0;
}
public:
int remove (const K& key)
{
qse_size_t hc = this->hasher(key) % bucket_size;
BucketNode* np = this->find_pair_node (key, hc);
if (np)
{
this->remove (hc, np);
return 0;
}
return -1;
}
template <typename MK, typename MHASHER, typename MCOMPARATOR>
int removeWithCustomKey (const MK& key)
{
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)
{
this->remove (hc, np);
return 0;
}
return -1;
}
void clear (qse_size_t new_bucket_size = 0)
{
for (qse_size_t i = 0; i < bucket_size; i++) this->buckets[i]->clear ();
this->pair_count = 0;
if (new_bucket_size > 0)
{
Bucket** tmp = this->allocate_bucket (this->getMmgr(), new_bucket_size, this->bucket_mpb_size);
this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
this->buckets = tmp;
this->bucket_size = new_bucket_size;
this->threshold = this->bucket_size * this->load_factor / 100;
}
}
typedef int (SelfType::*TraverseCallback)
(const Pair& entry, void* user_data) const;
int traverse (TraverseCallback callback, void* user_data) const
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{
const Pair& e = np->value;
if ((this->*callback)(e,user_data) == -1) return -1;
}
}
return 0;
}
typedef int (*StaticTraverseCallback)
(SelfType* table, Pair& entry, void* user_data);
int traverse (StaticTraverseCallback callback, void* user_data)
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{
Pair& e = np->value;
if (callback(this,e,user_data) == -1) return -1;
}
}
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;
qse_size_t bucket_mpb_size;
HASHER hasher;
COMPARATOR comparator;
RESIZER resizer;
void rehash () const
{
qse_size_t new_bucket_size = this->resizer (this->bucket_size);
Bucket** new_buckets = this->allocate_bucket (this->getMmgr(), new_bucket_size, this->bucket_mpb_size);
try
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
/*
BucketNode* np;
for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext())
{
const Pair& e = np->value;
qse_size_t hc = e.key.hashCode() % new_bucket_size;
new_this->buckets[hc]->append (e);
}
*/
// this approach save redundant memory allocation
// and retains the previous pointers before rehashing.
// if the bucket uses a memory pool, this would not
// work. fortunately, the hash table doesn't use it
// for a bucket. ---> this is not true any more.
// ---> this has been broken as memory pool
// ---> can be activated for buckets.
BucketNode* np = this->buckets[i]->getHeadNode();
while (np)
{
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));
np = next;
}
}
}
catch (...)
{
this->dispose_bucket (this->getMmgr(), new_buckets, new_bucket_size);
throw;
}
this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
this->buckets = new_buckets;
this->bucket_size = new_bucket_size;
this->threshold = this->load_factor * this->bucket_size / 100;
}
};
#endif
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

View File

@ -79,12 +79,12 @@ protected:
}
};
template <typename T, typename COMPARATOR>
template <typename T, typename COMPARATOR, typename NODE, typename GET_T>
class LinkedListIterator {
public:
friend class LinkedList<T,COMPARATOR>;
typedef LinkedListNode<T,COMPARATOR> Node;
typedef LinkedListIterator<T,COMPARATOR> SelfType;
typedef NODE Node;
typedef LinkedListIterator<T,COMPARATOR,NODE,GET_T> SelfType;
LinkedListIterator (): current(QSE_NULL) {}
LinkedListIterator (Node* node): current(node) {}
@ -143,12 +143,7 @@ public:
return this->current != QSE_NULL;
}
T& operator* () // dereference
{
return this->current->getValue();
}
const T& operator* () const // dereference
GET_T& operator* () // dereference
{
return this->current->getValue();
}
@ -160,13 +155,7 @@ public:
}
#endif
T& getValue ()
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current->getValue();
}
const T& getValue () const
GET_T& getValue ()
{
QSE_ASSERT (this->current != QSE_NULL);
return this->current->getValue();
@ -206,17 +195,11 @@ template <typename T, typename COMPARATOR = LinkedListComparator<T> > class Link
public:
typedef LinkedList<T,COMPARATOR> SelfType;
typedef LinkedListNode<T,COMPARATOR> Node;
typedef LinkedListIterator<T,COMPARATOR> Iterator;
typedef LinkedListIterator<T,COMPARATOR,Node,T> Iterator;
typedef LinkedListIterator<T,COMPARATOR,const Node,const T> ConstIterator;
typedef LinkedListComparator<T> DefaultComparator;
struct Visiter
{
// return 1 to move forward, -1 to move backward, 0 to stop
virtual ~Visiter() {}
virtual int operator() (Node* node) = 0;
};
enum
{
INVALID_INDEX = ~(qse_size_t)0
@ -224,7 +207,7 @@ public:
~LinkedList ()
{
this->clearout ();
this->clear (true);
}
LinkedList (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size)
@ -485,22 +468,52 @@ public:
{
this->remove (this->head_node);
}
void removeTail ()
{
this->remove (this->tail_node);
}
Node* getHeadNode () const
/// The getHeadNode() function returns the first node.
/// \code
/// QSE::LinkedList<int> l;
/// QSE::LinkedList<int>::Node* np;
/// for (np = l.getHeadNode(); np; np = np->getNextNode())
/// {
/// printf ("%d\n", np->value);
/// }
/// \endcode
Node* getHeadNode ()
{
return this->head_node;
}
Node* getTailNode () const
const Node* getHeadNode () const
{
return this->head_node;
}
/// The getTailNode() function returns the last node.
/// \code
/// QSE::LinkedList<int> l;
/// QSE::LinkedList<int>::Node* np;
/// for (np = l.getTailNode(); np; np = np->getPrevNode())
/// {
/// printf ("%d\n", np->value);
/// }
/// \endcode
Node* getTailNode ()
{
return this->tail_node;
}
Node* getNodeAt (qse_size_t index) const
const Node* getTailNode () const
{
return this->tail_node;
}
protected:
Node* get_node_at (qse_size_t index) const
{
QSE_ASSERT (index < this->node_count);
@ -525,6 +538,17 @@ public:
return np;
}
public:
Node* getNodeAt (qse_size_t index)
{
return this->get_node_at (index);
}
const Node* getNodeAt (qse_size_t index) const
{
return this->get_node_at (index);
}
T& getValueAt (qse_size_t index)
{
// same as operator[]
@ -606,7 +630,7 @@ public:
return INVALID_INDEX;
}
void clear ()
void clear (bool clear_mpool = false)
{
Node* p, * saved;
@ -625,12 +649,34 @@ public:
this->head_node = this->tail_node = QSE_NULL;
QSE_ASSERT (this->node_count == 0);
if (clear_mpool) this->mp.dispose ();
}
void clearout ()
Iterator getIterator (qse_size_t index = 0)
{
this->clear ();
this->mp.dispose ();
if (this->node_count <= 0)
{
return Iterator (QSE_NULL);
}
else
{
if (index >= this->node_count) index = this->node_count - 1;
return Iterator (this->getNodeAt(index));
}
}
ConstIterator getConstIterator (qse_size_t index = 0) const
{
if (this->node_count <= 0)
{
return ConstIterator (QSE_NULL);
}
else
{
if (index >= this->node_count) index = this->node_count - 1;
return ConstIterator (this->getNodeAt(index));
}
}
/// The reverse() function reverses the order of nodes.
@ -648,57 +694,6 @@ public:
}
}
typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur);
void traverse (TraverseCallback callback, Node* start)
{
Node* cur, * prev, * next;
cur = start;
while (cur)
{
prev = cur->prev;
next = cur->next;
int n = (this->*callback) (start, cur);
if (n > 0) cur = next;
else if (n < 0) cur = prev;
else break;
}
}
void traverse (Visiter& visiter)
{
Node* cur, * prev, * next;
cur = this->head_node;
while (cur)
{
prev = cur->prev;
next = cur->next;
int n = visiter (cur);
if (n > 0) cur = next;
else if (n < 0) cur = prev;
else break;
}
}
Iterator getIterator (qse_size_t index = 0) const
{
if (this->node_count <= 0)
{
return Iterator (QSE_NULL);
}
else
{
if (index >= this->node_count) index = this->node_count - 1;
return Iterator (this->getNodeAt(index));
}
}
protected:
Mpool mp;
COMPARATOR comparator;

View File

@ -52,6 +52,6 @@ pkginclude_HEADERS = \
if ENABLE_CXX
pkginclude_HEADERS += \
Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
Mpool.hpp Couple.hpp LinkedList.hpp HashList.hpp HashTable.hpp
Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp
endif

View File

@ -52,7 +52,7 @@ build_triplet = @build@
host_triplet = @host@
@ENABLE_CXX_TRUE@am__append_1 = \
@ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
@ENABLE_CXX_TRUE@ Mpool.hpp Couple.hpp LinkedList.hpp HashList.hpp HashTable.hpp
@ENABLE_CXX_TRUE@ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp
subdir = include/qse/cmn
DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \
@ -91,7 +91,8 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dir.h dll.h \
nwio.h oht.h opt.h path.h pio.h pma.h rbt.h rex.h sck.h sio.h \
sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \
utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
Mpool.hpp Couple.hpp LinkedList.hpp HashList.hpp HashTable.hpp
Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp \
HashTable.hpp
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \