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.
|
||||
*/
|
||||
|
||||
#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; }
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
@ -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,17 +244,47 @@ 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 ();
|
||||
}
|
||||
|
||||
Node* getHeadNode () const
|
||||
Node* getHeadNode ()
|
||||
{
|
||||
return this->datum_list->getHeadNode ();
|
||||
}
|
||||
|
||||
Node* getTaileNode () const
|
||||
const Node* getHeadNode () const
|
||||
{
|
||||
return this->datum_list->getHeadNode ();
|
||||
}
|
||||
|
||||
Node* getTailNode ()
|
||||
{
|
||||
return this->datum_list->getTailNode ();
|
||||
}
|
||||
|
||||
const Node* getTailNode () const
|
||||
{
|
||||
return this->datum_list->getTailNode ();
|
||||
}
|
||||
@ -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;
|
||||
|
@ -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)
|
||||
/////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/||"`;; \
|
||||
|
Loading…
x
Reference in New Issue
Block a user