added Mmgr::callocate()

fixed various problems in HashTable
This commit is contained in:
hyung-hwan 2015-02-05 15:51:50 +00:00
parent 6e92bb2985
commit 6da46ff4e1
4 changed files with 173 additions and 83 deletions

View File

@ -64,44 +64,94 @@ public:
typedef LinkedList<Entry> Bucket; typedef LinkedList<Entry> Bucket;
typedef HashTable<K,V,HASHER,RESIZER> SelfType; typedef HashTable<K,V,HASHER,RESIZER> 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) 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->bucket_size = bucket_size;
this->buckets = new Bucket[bucket_size]; this->entry_count = 0;
this->load_factor = load_factor; this->load_factor = load_factor;
this->threshold = bucket_size * load_factor / 100; 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->bucket_size = table.bucket_size;
this->buckets = new Bucket[table.bucket_size]; this->entry_count = 0;
this->load_factor = table.load_factor; this->load_factor = table.load_factor;
this->threshold = table.bucket_size * table.load_factor / 100; this->threshold = table.bucket_size * table.load_factor / 100;
for (qse_size_t i = 0; i < table.bucket_size; i++) 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; typename Bucket::Node* np;
for (np = b.head(); np; np = np->forward()) for (np = b->getHeadNode(); np; np = np->getNext())
{ {
Entry& e = np->value; Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size; qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc].append (e); this->buckets[hc]->append (e);
this->entry_count++; this->entry_count++;
} }
} }
// doesn't need to rehash in the copy constructor. // doesn't need to rehash in the copy constructor.
//if (entry_count >= threshold) rehash (); //if (entry_count >= threshold) this->rehash ();
} }
~HashTable () ~HashTable ()
{ {
this->clear (); this->clear ();
if (this->buckets) delete[] this->buckets; this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
} }
SelfType& operator= (const SelfType& table) SelfType& operator= (const SelfType& table)
@ -110,13 +160,13 @@ public:
for (qse_size_t i = 0; i < table.bucket_size; i++) 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; typename Bucket::Node* np;
for (np = b.head(); np; np = np->forward()) for (np = b->getHeadNode(); np; np = np->getNext())
{ {
Entry& e = np->value; Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size; qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc].append (e); this->buckets[hc]->append (e);
entry_count++; entry_count++;
} }
} }
@ -142,7 +192,7 @@ public:
Bucket& getBucket (qse_size_t index) const Bucket& getBucket (qse_size_t index) const
{ {
qse_assert (index < this->bucket_size); QSE_ASSERT (index < this->bucket_size);
return this->buckets[index]; return this->buckets[index];
} }
@ -152,7 +202,7 @@ public:
qse_size_t hc = this->hasher(key) % this->bucket_size; qse_size_t hc = this->hasher(key) % this->bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return e.value; if (key == e.key) return e.value;
@ -164,7 +214,7 @@ public:
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Entry& e2 = buckets[hc].append (Entry(key)); Entry& e2 = this->buckets[hc]->append (Entry(key));
entry_count++; entry_count++;
return e2.value; return e2.value;
} }
@ -174,7 +224,7 @@ public:
qse_size_t hc = this->hasher(key) % this->bucket_size; qse_size_t hc = this->hasher(key) % this->bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return e.value; if (key == e.key) return e.value;
@ -186,7 +236,7 @@ public:
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Entry& e2 = buckets[hc].append (Entry(key)); Entry& e2 = this->buckets[hc]->append (Entry(key));
entry_count++; entry_count++;
return e2.value; return e2.value;
} }
@ -204,7 +254,8 @@ public:
qse_size_t hc = h(key) % bucket_size; qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np; 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; const Entry& e = np->value;
if (key == e.key) return &e.value; if (key == e.key) return &e.value;
} }
@ -219,7 +270,8 @@ public:
qse_size_t hc = h(key) % bucket_size; qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return &e.value; if (key == e.key) return &e.value;
} }
@ -227,40 +279,56 @@ public:
return QSE_NULL; return QSE_NULL;
} }
V* get (const K& key) protected:
Entry* find_pair (const K& key)
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return &e.value; if (key == e.key) return &e;
} }
return QSE_NULL; 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; return this->find_pair (key);
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;
} }
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; 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; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) { if (key == e.key)
{
*hash_code = hc; *hash_code = hc;
*node = np; *node = np;
return &e.value; return &e.value;
@ -270,12 +338,12 @@ public:
return QSE_NULL; 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; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) if (key == e.key)
@ -305,7 +373,7 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return &e.value; if (key == e.key) return &e.value;
@ -313,11 +381,11 @@ public:
if (entry_count >= threshold) if (entry_count >= threshold)
{ {
rehash (); this->rehash ();
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Entry& e = buckets[hc].append (Entry(key)); Entry& e = this->buckets[hc]->append (Entry(key));
entry_count++; entry_count++;
return &e.value; return &e.value;
} }
@ -327,7 +395,7 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return &e.value; if (key == e.key) return &e.value;
@ -335,11 +403,11 @@ public:
if (entry_count >= threshold) if (entry_count >= threshold)
{ {
rehash (); this->rehash ();
hc = this->hasher(key) % bucket_size; 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++; entry_count++;
return &e.value; return &e.value;
} }
@ -349,7 +417,7 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return QSE_NULL; if (key == e.key) return QSE_NULL;
@ -357,11 +425,11 @@ public:
if (entry_count >= threshold) if (entry_count >= threshold)
{ {
rehash (); this->rehash ();
hc = this->hasher(key) % bucket_size; hc = this->hasher(key) % bucket_size;
} }
Entry& e = buckets[hc].append (Entry(key)); Entry& e = this->buckets[hc]->append (Entry(key));
entry_count++; entry_count++;
return &e.value; return &e.value;
} }
@ -371,7 +439,7 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return QSE_NULL; if (key == e.key) return QSE_NULL;
@ -379,11 +447,11 @@ public:
if (entry_count >= threshold) if (entry_count >= threshold)
{ {
rehash (); this->rehash ();
hc = this->hasher(key) % bucket_size; 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++; entry_count++;
return &e.value; return &e.value;
} }
@ -393,7 +461,7 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) if (key == e.key)
@ -405,11 +473,11 @@ public:
if (entry_count >= threshold) if (entry_count >= threshold)
{ {
rehash (); this->rehash ();
hc = this->hasher(key) % bucket_size; 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++; entry_count++;
return &e.value; return &e.value;
} }
@ -421,12 +489,12 @@ public:
qse_size_t hc = h(key) % bucket_size; qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) if (key == e.key)
{ {
this->buckets[hc].remove (np); this->buckets[hc]->remove (np);
this->entry_count--; this->entry_count--;
return 0; return 0;
} }
@ -440,12 +508,12 @@ public:
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) if (key == e.key)
{ {
this->buckets[hc].remove (np); this->buckets[hc]->remove (np);
this->entry_count--; this->entry_count--;
return 0; return 0;
} }
@ -459,11 +527,12 @@ public:
// //
// WARNING: this method should be used with extra care. // WARNING: this method should be used with extra care.
// //
this->buckets[hc].remove (np); this->buckets[hc]->remove (np);
this->entry_count--; this->entry_count--;
return 0; return 0;
} }
#if 0
qse_size_t removeValue (const V& value) qse_size_t removeValue (const V& value)
{ {
qse_size_t count = 0; qse_size_t count = 0;
@ -471,11 +540,13 @@ public:
for (qse_size_t i = 0; i < this->bucket_size; i++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
typename Bucket::Node* np, * np2; typename Bucket::Node* np, * np2;
np = buckets[i].head(); np = this->buckets[i]->getHeadNode();
while (np != QSE_NULL) { while (np != QSE_NULL)
{
Entry& e = np->value; Entry& e = np->value;
np2 = np->forward (); np2 = np->getNext ();
if (value == e.value) { if (value == e.value)
{
this->remove (i, np); this->remove (i, np);
count++; count++;
} }
@ -485,13 +556,14 @@ public:
return count; return count;
} }
#endif
bool containsKey (const K& key) const bool containsKey (const K& key) const
{ {
qse_size_t hc = this->hasher(key) % bucket_size; qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np; 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; Entry& e = np->value;
if (key == e.key) return true; if (key == e.key) return true;
@ -505,7 +577,7 @@ public:
for (qse_size_t i = 0; i < bucket_size; i++) for (qse_size_t i = 0; i < bucket_size; i++)
{ {
typename Bucket::Node* np; 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; Entry& e = np->value;
if (value == e.value) return true; if (value == e.value) return true;
@ -515,18 +587,19 @@ public:
return false; 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 (); for (qse_size_t i = 0; i < bucket_size; i++) this->buckets[i]->clear ();
entry_count = 0; this->entry_count = 0;
if (new_bucket_size > 0) if (new_bucket_size > 0)
{ {
Bucket* tmp = new Bucket[new_bucket_size]; Bucket** tmp = this->allocate_bucket (this->getMmgr(), new_bucket_size);
bucket_size = new_bucket_size; this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
threshold = bucket_size * load_factor / 100;
delete[] buckets; this->buckets = tmp;
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++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
typename Bucket::Node* np; 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; const Entry& e = np->value;
if ((this->*callback)(e,user_data) == -1) return -1; 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++) for (qse_size_t i = 0; i < this->bucket_size; i++)
{ {
typename Bucket::Node* np; 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; Entry& e = np->value;
if (callback(this,e,user_data) == -1) return -1; if (callback(this,e,user_data) == -1) return -1;
@ -569,7 +642,7 @@ public:
protected: protected:
mutable qse_size_t entry_count; mutable qse_size_t entry_count;
mutable qse_size_t bucket_size; mutable qse_size_t bucket_size;
mutable Bucket* buckets; mutable Bucket** buckets;
mutable qse_size_t threshold; mutable qse_size_t threshold;
qse_size_t load_factor; qse_size_t load_factor;
HASHER hasher; HASHER hasher;
@ -578,7 +651,7 @@ protected:
void rehash () const void rehash () const
{ {
qse_size_t new_bucket_size = this->resizer (this->bucket_size); 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 try
{ {
@ -586,11 +659,11 @@ protected:
{ {
/* /*
typename Bucket::Node* np; 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; const Entry& e = np->value;
qse_size_t hc = e.key.hashCode() % new_bucket_size; 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 // if the bucket uses a memory pool, this would not
// work. fortunately, the hash table doesn't use it // work. fortunately, the hash table doesn't use it
// for a bucket. // for a bucket.
typename Bucket::Node* np = buckets[i].head(); typename Bucket::Node* np = this->buckets[i]->getHeadNode();
while (np) while (np)
{ {
typename Bucket::Node* next = np->forward(); typename Bucket::Node* next = np->getNext();
const Entry& e = np->value; const Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % new_bucket_size; 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; np = next;
} }
} }
} }
catch (...) catch (...)
{ {
delete[] new_buckets; this->dispose_bucket (this->getMmgr(), new_buckets, new_bucket_size);
throw; throw;
} }
delete[] this->buckets; this->dispose_bucket (this->getMmgr(), this->buckets, this->bucket_size);
this->buckets = new_buckets; this->buckets = new_buckets;
this->bucket_size = new_bucket_size; this->bucket_size = new_bucket_size;
this->threshold = this->load_factor * this->bucket_size / 100; this->threshold = this->load_factor * this->bucket_size / 100;

View File

@ -127,6 +127,7 @@ public:
return *this; return *this;
} }
#if 0
T& operator[] (qse_size_t index) T& operator[] (qse_size_t index)
{ {
// same as getValueAt() // same as getValueAt()
@ -142,6 +143,7 @@ public:
Node* np = this->getNodeAt (index); Node* np = this->getNodeAt (index);
return np->value; return np->value;
} }
#endif
qse_size_t getMPBlockSize() const qse_size_t getMPBlockSize() const
{ {

View File

@ -102,6 +102,12 @@ public:
return xptr; 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 /// The reallocate() function calls reallocMem() for memory
/// reallocation. if it fails, it raise an exception if it's /// reallocation. if it fails, it raise an exception if it's

View File

@ -26,6 +26,7 @@
#include <qse/cmn/Mmgr.hpp> #include <qse/cmn/Mmgr.hpp>
#include <qse/cmn/StdMmgr.hpp> #include <qse/cmn/StdMmgr.hpp>
#include "mem.h"
///////////////////////////////// /////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
@ -46,6 +47,13 @@ void Mmgr::free_mem (mmgr_t* mmgr, void* ptr)
((Mmgr*)mmgr->ctx)->freeMem (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::dfl_mmgr = StdMmgr::getInstance();
Mmgr* Mmgr::getDFL () Mmgr* Mmgr::getDFL ()