From 6da46ff4e1d5688fe968bf06ffa948255afeaede Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 5 Feb 2015 15:51:50 +0000 Subject: [PATCH] added Mmgr::callocate() fixed various problems in HashTable --- qse/include/qse/cmn/HashTable.hpp | 238 +++++++++++++++++++---------- qse/include/qse/cmn/LinkedList.hpp | 4 +- qse/include/qse/cmn/Mmgr.hpp | 6 + qse/lib/cmn/Mmgr.cpp | 8 + 4 files changed, 173 insertions(+), 83 deletions(-) diff --git a/qse/include/qse/cmn/HashTable.hpp b/qse/include/qse/cmn/HashTable.hpp index 7f70c492..2fe4b72c 100644 --- a/qse/include/qse/cmn/HashTable.hpp +++ b/qse/include/qse/cmn/HashTable.hpp @@ -60,48 +60,98 @@ template , typename class HashTable: public Mmged { public: - typedef Pair Entry; + typedef Pair Entry; typedef LinkedList Bucket; typedef HashTable SelfType; +protected: + Bucket** allocate_bucket (Mmgr* mm, qse_size_t bs) 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); + } + } + 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 = 10, qse_size_t load_factor = 75): Mmged(mmgr) { - this->entry_count = 0; + this->buckets = this->allocate_bucket (this->getMmgr(), bucket_size); this->bucket_size = bucket_size; - this->buckets = new Bucket[bucket_size]; + this->entry_count = 0; this->load_factor = load_factor; this->threshold = bucket_size * load_factor / 100; } - HashTable (const SelfType& table) + HashTable (const SelfType& table): Mmged (table) { - this->entry_count = 0; + this->buckets = this->allocate_bucket (this->getMmgr(), table.bucket_size); this->bucket_size = table.bucket_size; - this->buckets = new Bucket[table.bucket_size]; + this->entry_count = 0; this->load_factor = table.load_factor; this->threshold = table.bucket_size * table.load_factor / 100; for (qse_size_t i = 0; i < table.bucket_size; i++) { - Bucket& b = table.buckets[i]; + Bucket* b = table.buckets[i]; typename Bucket::Node* np; - for (np = b.head(); np; np = np->forward()) + for (np = b->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; qse_size_t hc = this->hasher(e.key) % this->bucket_size; - this->buckets[hc].append (e); + this->buckets[hc]->append (e); this->entry_count++; } } // doesn't need to rehash in the copy constructor. - //if (entry_count >= threshold) rehash (); + //if (entry_count >= threshold) this->rehash (); } ~HashTable () { this->clear (); - if (this->buckets) delete[] this->buckets; + this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size); } SelfType& operator= (const SelfType& table) @@ -110,13 +160,13 @@ public: for (qse_size_t i = 0; i < table.bucket_size; i++) { - Bucket& b = table.buckets[i]; + Bucket* b = table.buckets[i]; typename Bucket::Node* np; - for (np = b.head(); np; np = np->forward()) + for (np = b->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; qse_size_t hc = this->hasher(e.key) % this->bucket_size; - this->buckets[hc].append (e); + this->buckets[hc]->append (e); entry_count++; } } @@ -142,7 +192,7 @@ public: Bucket& getBucket (qse_size_t index) const { - qse_assert (index < this->bucket_size); + QSE_ASSERT (index < this->bucket_size); return this->buckets[index]; } @@ -152,7 +202,7 @@ public: qse_size_t hc = this->hasher(key) % this->bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return e.value; @@ -164,7 +214,7 @@ public: hc = this->hasher(key) % bucket_size; } - Entry& e2 = buckets[hc].append (Entry(key)); + Entry& e2 = this->buckets[hc]->append (Entry(key)); entry_count++; return e2.value; } @@ -174,7 +224,7 @@ public: qse_size_t hc = this->hasher(key) % this->bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return e.value; @@ -186,7 +236,7 @@ public: hc = this->hasher(key) % bucket_size; } - Entry& e2 = buckets[hc].append (Entry(key)); + Entry& e2 = this->buckets[hc]->append (Entry(key)); entry_count++; return e2.value; } @@ -204,7 +254,8 @@ public: qse_size_t hc = h(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) { + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) + { const Entry& e = np->value; if (key == e.key) return &e.value; } @@ -219,7 +270,8 @@ public: qse_size_t hc = h(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) { + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) + { Entry& e = np->value; if (key == e.key) return &e.value; } @@ -227,40 +279,56 @@ public: return QSE_NULL; } - V* get (const K& key) +protected: + Entry* find_pair (const K& key) { qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) { + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) + { Entry& e = np->value; - if (key == e.key) return &e.value; + if (key == e.key) return &e; } return QSE_NULL; } - const V* get (const K& key) const +public: + Entry* findPair (const K& key) { - qse_size_t hc = this->hasher(key) % bucket_size; - - typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) { - const Entry& e = np->value; - if (key == e.key) return &e.value; - } + return this->find_pair (key); + } + const Entry* findPair (const K& key) const + { + return this->find_pair (key); + } + + V* findValue (const K& key) + { + Entry* pair = this->findPair (key); + if (pair) return &pair->value; return QSE_NULL; } - V* get (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) + const V* findValue (const K& key) const + { + const Entry* pair = this->findPair (key); + if (pair) return &pair->value; + return QSE_NULL; + } + + V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) { qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) { + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) + { Entry& e = np->value; - if (key == e.key) { + if (key == e.key) + { *hash_code = hc; *node = np; return &e.value; @@ -270,12 +338,12 @@ public: return QSE_NULL; } - const V* get (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) const + const V* findValue (const K& key, qse_size_t* hash_code, typename Bucket::Node** node) const { qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) @@ -305,7 +373,7 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return &e.value; @@ -313,11 +381,11 @@ public: if (entry_count >= threshold) { - rehash (); + this->rehash (); hc = this->hasher(key) % bucket_size; } - Entry& e = buckets[hc].append (Entry(key)); + Entry& e = this->buckets[hc]->append (Entry(key)); entry_count++; return &e.value; } @@ -327,7 +395,7 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return &e.value; @@ -335,11 +403,11 @@ public: if (entry_count >= threshold) { - rehash (); + this->rehash (); hc = this->hasher(key) % bucket_size; } - Entry& e = buckets[hc].append (Entry(key,value)); + Entry& e = this->buckets[hc]->append (Entry(key,value)); entry_count++; return &e.value; } @@ -349,7 +417,7 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return QSE_NULL; @@ -357,11 +425,11 @@ public: if (entry_count >= threshold) { - rehash (); + this->rehash (); hc = this->hasher(key) % bucket_size; } - Entry& e = buckets[hc].append (Entry(key)); + Entry& e = this->buckets[hc]->append (Entry(key)); entry_count++; return &e.value; } @@ -371,7 +439,7 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return QSE_NULL; @@ -379,11 +447,11 @@ public: if (entry_count >= threshold) { - rehash (); + this->rehash (); hc = this->hasher(key) % bucket_size; } - Entry& e = buckets[hc].append (Entry(key, value)); + Entry& e = this->buckets[hc]->append (Entry(key, value)); entry_count++; return &e.value; } @@ -393,7 +461,7 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) @@ -405,11 +473,11 @@ public: if (entry_count >= threshold) { - rehash (); + this->rehash (); hc = this->hasher(key) % bucket_size; } - Entry& e = buckets[hc].append (Entry(key,value)); + Entry& e = this->buckets[hc]->append (Entry(key,value)); entry_count++; return &e.value; } @@ -421,12 +489,12 @@ public: qse_size_t hc = h(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) { - this->buckets[hc].remove (np); + this->buckets[hc]->remove (np); this->entry_count--; return 0; } @@ -440,12 +508,12 @@ public: qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) { - this->buckets[hc].remove (np); + this->buckets[hc]->remove (np); this->entry_count--; return 0; } @@ -459,11 +527,12 @@ public: // // WARNING: this method should be used with extra care. // - this->buckets[hc].remove (np); + this->buckets[hc]->remove (np); this->entry_count--; return 0; } +#if 0 qse_size_t removeValue (const V& value) { qse_size_t count = 0; @@ -471,11 +540,13 @@ public: for (qse_size_t i = 0; i < this->bucket_size; i++) { typename Bucket::Node* np, * np2; - np = buckets[i].head(); - while (np != QSE_NULL) { + np = this->buckets[i]->getHeadNode(); + while (np != QSE_NULL) + { Entry& e = np->value; - np2 = np->forward (); - if (value == e.value) { + np2 = np->getNext (); + if (value == e.value) + { this->remove (i, np); count++; } @@ -485,13 +556,14 @@ public: return count; } +#endif bool containsKey (const K& key) const { qse_size_t hc = this->hasher(key) % bucket_size; typename Bucket::Node* np; - for (np = buckets[hc].head(); np; np = np->forward()) + for (np = this->buckets[hc]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (key == e.key) return true; @@ -505,7 +577,7 @@ public: for (qse_size_t i = 0; i < bucket_size; i++) { typename Bucket::Node* np; - for (np = buckets[i].head(); np; np = np->forward()) + for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (value == e.value) return true; @@ -515,18 +587,19 @@ public: return false; } - void clear (int new_bucket_size = 0) + void clear (qse_size_t new_bucket_size = 0) { - for (qse_size_t i = 0; i < bucket_size; i++) buckets[i].clear (); - entry_count = 0; + for (qse_size_t i = 0; i < bucket_size; i++) this->buckets[i]->clear (); + this->entry_count = 0; if (new_bucket_size > 0) { - Bucket* tmp = new Bucket[new_bucket_size]; - bucket_size = new_bucket_size; - threshold = bucket_size * load_factor / 100; - delete[] buckets; - buckets = tmp; + Bucket** tmp = this->allocate_bucket (this->getMmgr(), new_bucket_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; } } @@ -538,7 +611,7 @@ public: for (qse_size_t i = 0; i < this->bucket_size; i++) { typename Bucket::Node* np; - for (np = buckets[i].head(); np; np = np->forward()) + for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { const Entry& e = np->value; if ((this->*callback)(e,user_data) == -1) return -1; @@ -556,7 +629,7 @@ public: for (qse_size_t i = 0; i < this->bucket_size; i++) { typename Bucket::Node* np; - for (np = buckets[i].head(); np; np = np->forward()) + for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { Entry& e = np->value; if (callback(this,e,user_data) == -1) return -1; @@ -569,7 +642,7 @@ public: protected: mutable qse_size_t entry_count; mutable qse_size_t bucket_size; - mutable Bucket* buckets; + mutable Bucket** buckets; mutable qse_size_t threshold; qse_size_t load_factor; HASHER hasher; @@ -578,7 +651,7 @@ protected: void rehash () const { qse_size_t new_bucket_size = this->resizer (this->bucket_size); - Bucket* new_buckets = new Bucket[new_bucket_size]; + Bucket** new_buckets = this->allocate_bucket (this->getMmgr(), new_bucket_size); try { @@ -586,11 +659,11 @@ protected: { /* typename Bucket::Node* np; - for (np = buckets[i].head(); np; np = np->forward()) + for (np = this->buckets[i]->getHeadNode(); np; np = np->getNext()) { const Entry& e = np->value; qse_size_t hc = e.key.hashCode() % new_bucket_size; - new_buckets[hc].append (e); + new_this->buckets[hc]->append (e); } */ @@ -599,24 +672,25 @@ protected: // if the bucket uses a memory pool, this would not // work. fortunately, the hash table doesn't use it // for a bucket. - typename Bucket::Node* np = buckets[i].head(); + typename Bucket::Node* np = this->buckets[i]->getHeadNode(); while (np) { - typename Bucket::Node* next = np->forward(); + typename Bucket::Node* next = np->getNext(); const Entry& e = np->value; qse_size_t hc = this->hasher(e.key) % new_bucket_size; - new_buckets[hc].appendNode (buckets[i].yield(np)); + new_buckets[hc]->appendNode (this->buckets[i]->yield(np)); np = next; } } } catch (...) { - delete[] new_buckets; + this->dispose_bucket (this->getMmgr(), new_buckets, new_bucket_size); throw; } - delete[] this->buckets; + 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; diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp index 1ceaaa2e..e6f6ec21 100644 --- a/qse/include/qse/cmn/LinkedList.hpp +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -126,7 +126,8 @@ public: this->append (p->value); return *this; } - + +#if 0 T& operator[] (qse_size_t index) { // same as getValueAt() @@ -142,6 +143,7 @@ public: Node* np = this->getNodeAt (index); return np->value; } +#endif qse_size_t getMPBlockSize() const { diff --git a/qse/include/qse/cmn/Mmgr.hpp b/qse/include/qse/cmn/Mmgr.hpp index fa58ace2..36c542c5 100644 --- a/qse/include/qse/cmn/Mmgr.hpp +++ b/qse/include/qse/cmn/Mmgr.hpp @@ -102,6 +102,12 @@ public: return xptr; } + /// + /// The callocate() function allocates memory like allocate() and + /// clears the memory before returning. + /// + void* callocate (qse_size_t n); + /// /// The reallocate() function calls reallocMem() for memory /// reallocation. if it fails, it raise an exception if it's diff --git a/qse/lib/cmn/Mmgr.cpp b/qse/lib/cmn/Mmgr.cpp index 65572965..2fbe036c 100644 --- a/qse/lib/cmn/Mmgr.cpp +++ b/qse/lib/cmn/Mmgr.cpp @@ -26,6 +26,7 @@ #include #include +#include "mem.h" ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) @@ -46,6 +47,13 @@ void Mmgr::free_mem (mmgr_t* mmgr, void* ptr) ((Mmgr*)mmgr->ctx)->freeMem (ptr); } +void* Mmgr::callocate (qse_size_t n) +{ + void* ptr = this->allocate (n); + QSE_MEMSET (ptr, 0, n); + return ptr; +} + Mmgr* Mmgr::dfl_mmgr = StdMmgr::getInstance(); Mmgr* Mmgr::getDFL ()