simplified HashTable, HashList, LinkedList
This commit is contained in:
parent
ca8956366c
commit
06dbccbc06
@ -24,8 +24,8 @@
|
|||||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _QSE_CMN_COUPLE_HPP_
|
#ifndef _QSE_CMN_ASSOCIATION_HPP_
|
||||||
#define _QSE_CMN_COUPLE_HPP_
|
#define _QSE_CMN_ASSOCIATION_HPP_
|
||||||
|
|
||||||
#include <qse/types.h>
|
#include <qse/types.h>
|
||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
@ -34,24 +34,25 @@
|
|||||||
QSE_BEGIN_NAMESPACE(QSE)
|
QSE_BEGIN_NAMESPACE(QSE)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
|
||||||
template <typename KEY, typename VALUE> class Couple
|
template <typename K, typename V>
|
||||||
|
class Association
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KEY key;
|
K key;
|
||||||
VALUE value;
|
V value;
|
||||||
|
|
||||||
Couple () {}
|
Association () {}
|
||||||
Couple (const KEY& key): key (key) {}
|
Association (const K& key): key (key) {}
|
||||||
Couple (const KEY& key, const VALUE& value): key (key), value (value) {}
|
Association (const K& key, const V& value): key (key), value (value) {}
|
||||||
|
|
||||||
KEY& getKey () { return this->key; }
|
K& getKey () { return this->key; }
|
||||||
const KEY& getKey () const { return this->key; }
|
const K& getKey () const { return this->key; }
|
||||||
|
|
||||||
VALUE& getValue () { return this->value; }
|
V& getValue () { return this->value; }
|
||||||
const VALUE& getValue () const { return this->value; }
|
const V& getValue () const { return this->value; }
|
||||||
|
|
||||||
void setKey (const KEY& key) { this->key = key; }
|
void setKey (const K& key) { this->key = key; }
|
||||||
void setValue (const VALUE& value) { this->value = value; }
|
void setValue (const V& value) { this->value = value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
@ -83,7 +83,7 @@ public:
|
|||||||
typedef LinkedList<T,COMPARATOR> DatumList;
|
typedef LinkedList<T,COMPARATOR> DatumList;
|
||||||
typedef typename DatumList::Node Node;
|
typedef typename DatumList::Node Node;
|
||||||
typedef typename DatumList::Iterator Iterator;
|
typedef typename DatumList::Iterator Iterator;
|
||||||
typedef typename DatumList::Visiter Visiter;
|
typedef typename DatumList::ConstIterator ConstIterator;
|
||||||
typedef HashList<T,HASHER,COMPARATOR,RESIZER> SelfType;
|
typedef HashList<T,HASHER,COMPARATOR,RESIZER> SelfType;
|
||||||
|
|
||||||
typedef HashListHasher<T> DefaultHasher;
|
typedef HashListHasher<T> DefaultHasher;
|
||||||
@ -213,21 +213,11 @@ public:
|
|||||||
|
|
||||||
~HashList ()
|
~HashList ()
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear (true);
|
||||||
if (this->nodes) this->getMmgr()->dispose (this->nodes); //delete[] this->nodes;
|
if (this->nodes) this->getMmgr()->dispose (this->nodes); //delete[] this->nodes;
|
||||||
if (this->datum_list) this->free_datum_list ();
|
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)
|
SelfType& operator= (const SelfType& list)
|
||||||
{
|
{
|
||||||
this->clear ();
|
this->clear ();
|
||||||
@ -254,19 +244,49 @@ public:
|
|||||||
return *this;
|
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
|
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:
|
protected:
|
||||||
@ -548,48 +568,13 @@ public:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear ()
|
void clear (bool clear_mpool = false)
|
||||||
{
|
{
|
||||||
for (qse_size_t i = 0; i < (this->node_capacity << 1); i++)
|
for (qse_size_t i = 0; i < (this->node_capacity << 1); i++)
|
||||||
{
|
{
|
||||||
this->nodes[i] = QSE_NULL;
|
this->nodes[i] = QSE_NULL;
|
||||||
}
|
}
|
||||||
if (this->datum_list) this->datum_list->clear ();
|
this->datum_list->clear (clear_mpool);
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The getIterator() function returns an interator.
|
/// The getIterator() function returns an interator.
|
||||||
@ -617,6 +602,11 @@ public:
|
|||||||
return this->datum_list->getIterator (index);
|
return this->datum_list->getIterator (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstIterator getConstIterator (qse_size_t index = 0) const
|
||||||
|
{
|
||||||
|
return this->datum_list->getConstIterator (index);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable qse_size_t node_capacity;
|
mutable qse_size_t node_capacity;
|
||||||
mutable Node** nodes;
|
mutable Node** nodes;
|
||||||
|
@ -27,10 +27,7 @@
|
|||||||
#ifndef _QSE_CMN_HASHTABLE_HPP_
|
#ifndef _QSE_CMN_HASHTABLE_HPP_
|
||||||
#define _QSE_CMN_HASHTABLE_HPP_
|
#define _QSE_CMN_HASHTABLE_HPP_
|
||||||
|
|
||||||
/*#include <qse/Hashable.hpp>
|
#include <qse/cmn/Association.hpp>
|
||||||
#include <qse/cmn/LinkedList.hpp>*/
|
|
||||||
|
|
||||||
#include <qse/cmn/Couple.hpp>
|
|
||||||
#include <qse/cmn/HashList.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;
|
typedef HashListResizer HashTableResizer;
|
||||||
|
|
||||||
template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename COMPARATOR = HashTableComparator<K>, typename RESIZER = HashTableResizer>
|
template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename COMPARATOR = HashTableComparator<K>, typename RESIZER = HashTableResizer>
|
||||||
class HashTable: public Mmged
|
class HashTable: public Mmged
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef Couple<K,V> Pair;
|
typedef Association<K,V> Pair;
|
||||||
typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType;
|
typedef HashTable<K,V,HASHER,COMPARATOR,RESIZER> SelfType;
|
||||||
|
|
||||||
typedef HashTableHasher<K> DefaultHasher;
|
typedef HashTableHasher<K> DefaultHasher;
|
||||||
@ -123,6 +106,7 @@ public:
|
|||||||
typedef HashList<Pair,PairHasher,PairComparator,RESIZER> PairList;
|
typedef HashList<Pair,PairHasher,PairComparator,RESIZER> PairList;
|
||||||
typedef typename PairList::Node PairNode;
|
typedef typename PairList::Node PairNode;
|
||||||
typedef typename PairList::Iterator Iterator;
|
typedef typename PairList::Iterator Iterator;
|
||||||
|
typedef typename PairList::ConstIterator ConstIterator;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -153,12 +137,47 @@ public:
|
|||||||
|
|
||||||
Mpool& getMpool ()
|
Mpool& getMpool ()
|
||||||
{
|
{
|
||||||
return this->datum_list->getMpool();
|
return this->pair_list.getMpool ();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mpool& getMpool () const
|
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)
|
Pair* insert (const K& key, const V& value)
|
||||||
@ -177,7 +196,6 @@ public:
|
|||||||
|
|
||||||
Pair* update (const K& key, const V& value)
|
Pair* update (const K& key, const V& value)
|
||||||
{
|
{
|
||||||
|
|
||||||
//PairNode* node = this->pair_list.update (Pair(key, value));
|
//PairNode* node = this->pair_list.update (Pair(key, value));
|
||||||
//if (!node) return QSE_NULL;
|
//if (!node) return QSE_NULL;
|
||||||
//return &node->value;
|
//return &node->value;
|
||||||
@ -228,632 +246,25 @@ public:
|
|||||||
return this->pair_list.template heteroremove<MK,MHASHER,MComparator> (key);
|
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 (clear_mpool);
|
||||||
return this->pair_list.clear ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_size_t getSize() const
|
|
||||||
{
|
|
||||||
return this->pair_list.getSize ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Iterator getIterator (qse_size_t index = 0)
|
Iterator getIterator (qse_size_t index = 0)
|
||||||
{
|
{
|
||||||
return this->pair_list.getIterator (index);
|
return this->pair_list.getIterator (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstIterator getConstIterator (qse_size_t index = 0) const
|
||||||
|
{
|
||||||
|
return this->pair_list.getConstIterator (index);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PairList pair_list;
|
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)
|
QSE_END_NAMESPACE(QSE)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
@ -79,12 +79,12 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename COMPARATOR>
|
template <typename T, typename COMPARATOR, typename NODE, typename GET_T>
|
||||||
class LinkedListIterator {
|
class LinkedListIterator {
|
||||||
public:
|
public:
|
||||||
friend class LinkedList<T,COMPARATOR>;
|
friend class LinkedList<T,COMPARATOR>;
|
||||||
typedef LinkedListNode<T,COMPARATOR> Node;
|
typedef NODE Node;
|
||||||
typedef LinkedListIterator<T,COMPARATOR> SelfType;
|
typedef LinkedListIterator<T,COMPARATOR,NODE,GET_T> SelfType;
|
||||||
|
|
||||||
LinkedListIterator (): current(QSE_NULL) {}
|
LinkedListIterator (): current(QSE_NULL) {}
|
||||||
LinkedListIterator (Node* node): current(node) {}
|
LinkedListIterator (Node* node): current(node) {}
|
||||||
@ -143,12 +143,7 @@ public:
|
|||||||
return this->current != QSE_NULL;
|
return this->current != QSE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator* () // dereference
|
GET_T& operator* () // dereference
|
||||||
{
|
|
||||||
return this->current->getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& operator* () const // dereference
|
|
||||||
{
|
{
|
||||||
return this->current->getValue();
|
return this->current->getValue();
|
||||||
}
|
}
|
||||||
@ -160,13 +155,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
T& getValue ()
|
GET_T& getValue ()
|
||||||
{
|
|
||||||
QSE_ASSERT (this->current != QSE_NULL);
|
|
||||||
return this->current->getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& getValue () const
|
|
||||||
{
|
{
|
||||||
QSE_ASSERT (this->current != QSE_NULL);
|
QSE_ASSERT (this->current != QSE_NULL);
|
||||||
return this->current->getValue();
|
return this->current->getValue();
|
||||||
@ -206,17 +195,11 @@ template <typename T, typename COMPARATOR = LinkedListComparator<T> > class Link
|
|||||||
public:
|
public:
|
||||||
typedef LinkedList<T,COMPARATOR> SelfType;
|
typedef LinkedList<T,COMPARATOR> SelfType;
|
||||||
typedef LinkedListNode<T,COMPARATOR> Node;
|
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;
|
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
|
enum
|
||||||
{
|
{
|
||||||
INVALID_INDEX = ~(qse_size_t)0
|
INVALID_INDEX = ~(qse_size_t)0
|
||||||
@ -224,7 +207,7 @@ public:
|
|||||||
|
|
||||||
~LinkedList ()
|
~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)
|
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);
|
this->remove (this->head_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTail ()
|
void removeTail ()
|
||||||
{
|
{
|
||||||
this->remove (this->tail_node);
|
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;
|
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;
|
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);
|
QSE_ASSERT (index < this->node_count);
|
||||||
|
|
||||||
@ -525,6 +538,17 @@ public:
|
|||||||
return np;
|
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)
|
T& getValueAt (qse_size_t index)
|
||||||
{
|
{
|
||||||
// same as operator[]
|
// same as operator[]
|
||||||
@ -606,7 +630,7 @@ public:
|
|||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear ()
|
void clear (bool clear_mpool = false)
|
||||||
{
|
{
|
||||||
Node* p, * saved;
|
Node* p, * saved;
|
||||||
|
|
||||||
@ -625,12 +649,34 @@ public:
|
|||||||
|
|
||||||
this->head_node = this->tail_node = QSE_NULL;
|
this->head_node = this->tail_node = QSE_NULL;
|
||||||
QSE_ASSERT (this->node_count == 0);
|
QSE_ASSERT (this->node_count == 0);
|
||||||
|
|
||||||
|
if (clear_mpool) this->mp.dispose ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearout ()
|
Iterator getIterator (qse_size_t index = 0)
|
||||||
{
|
{
|
||||||
this->clear ();
|
if (this->node_count <= 0)
|
||||||
this->mp.dispose ();
|
{
|
||||||
|
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.
|
/// 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:
|
protected:
|
||||||
Mpool mp;
|
Mpool mp;
|
||||||
COMPARATOR comparator;
|
COMPARATOR comparator;
|
||||||
|
@ -52,6 +52,6 @@ pkginclude_HEADERS = \
|
|||||||
if ENABLE_CXX
|
if ENABLE_CXX
|
||||||
pkginclude_HEADERS += \
|
pkginclude_HEADERS += \
|
||||||
Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
|
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
|
endif
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ build_triplet = @build@
|
|||||||
host_triplet = @host@
|
host_triplet = @host@
|
||||||
@ENABLE_CXX_TRUE@am__append_1 = \
|
@ENABLE_CXX_TRUE@am__append_1 = \
|
||||||
@ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \
|
@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
|
subdir = include/qse/cmn
|
||||||
DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \
|
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 \
|
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 \
|
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 \
|
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_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||||
am__vpath_adj = case $$p in \
|
am__vpath_adj = case $$p in \
|
||||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user