added Pair and HashTable

This commit is contained in:
hyung-hwan 2015-02-04 13:43:01 +00:00
parent 67a5f4f5f5
commit 6e92bb2985
9 changed files with 700 additions and 45 deletions

View File

@ -52,7 +52,19 @@ struct HashListComparator
} }
}; };
template <typename T, typename MPOOL = Mpool, typename HASHER = HashListHasher<T>, typename COMPARATOR = HashListComparator<T> > struct HashListResizer
{
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));
}
};
template <typename T, typename MPOOL = Mpool, typename HASHER = HashListHasher<T>, typename COMPARATOR = HashListComparator<T>, typename RESIZER = HashListResizer >
class HashList: public Mmged class HashList: public Mmged
{ {
public: public:
@ -114,6 +126,10 @@ public:
this->load_factor = load_factor; this->load_factor = load_factor;
this->threshold = node_capacity * load_factor / 100; this->threshold = node_capacity * load_factor / 100;
// the memory manager for the linked list must raise an exception
// upon memory allocation error.
QSE_ASSERT (this->getMmgr()->isExceptionRaising());
} }
HashList (const SelfType& list): Mmged (list) HashList (const SelfType& list): Mmged (list)
@ -428,13 +444,14 @@ protected:
qse_size_t load_factor; qse_size_t load_factor;
HASHER hasher; HASHER hasher;
COMPARATOR comparator; COMPARATOR comparator;
RESIZER resizer;
void rehash () void rehash ()
{ {
// Move nodes around instead of values to prevent // Move nodes around instead of values to prevent
// existing values from being copied over and destroyed. // existing values from being copied over and destroyed.
// this incurs less number of memory allocations also. // this incurs less number of memory allocations also.
SelfType temp (this->getMmgr(), this->node_capacity << 1, this->load_factor, this->datum_list->getMPBlockSize()); SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, this->datum_list->getMPBlockSize());
Node* p = this->datum_list->getHeadNode(); Node* p = this->datum_list->getHeadNode();
while (p) while (p)
{ {

View File

@ -0,0 +1,630 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QSE_CMN_HASHTABLE_HPP_
#define _QSE_CMN_HASHTABLE_HPP_
#include <qse/Hashable.hpp>
#include <qse/cmn/LinkedList.hpp>
#include <qse/cmn/Pair.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
template<typename T>
struct HashTableHasher
{
qse_size_t operator() (const T& v) const
{
return v.hashCode();
}
};
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));
}
};
template <typename K, typename V, typename HASHER = HashTableHasher<K>, typename RESIZER = HashTableResizer>
class HashTable: public Mmged
{
public:
typedef Pair<K,V> Entry;
typedef LinkedList<Entry> Bucket;
typedef HashTable<K,V,HASHER,RESIZER> SelfType;
HashTable (Mmgr* mmgr, qse_size_t bucket_size = 10, qse_size_t load_factor = 75): Mmged(mmgr)
{
this->entry_count = 0;
this->bucket_size = bucket_size;
this->buckets = new Bucket[bucket_size];
this->load_factor = load_factor;
this->threshold = bucket_size * load_factor / 100;
}
HashTable (const SelfType& table)
{
this->entry_count = 0;
this->bucket_size = table.bucket_size;
this->buckets = new Bucket[table.bucket_size];
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];
typename Bucket::Node* np;
for (np = b.head(); np; np = np->forward())
{
Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc].append (e);
this->entry_count++;
}
}
// doesn't need to rehash in the copy constructor.
//if (entry_count >= threshold) rehash ();
}
~HashTable ()
{
this->clear ();
if (this->buckets) delete[] this->buckets;
}
SelfType& operator= (const SelfType& table)
{
this->clear ();
for (qse_size_t i = 0; i < table.bucket_size; i++)
{
Bucket& b = table.buckets[i];
typename Bucket::Node* np;
for (np = b.head(); np; np = np->forward())
{
Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % this->bucket_size;
this->buckets[hc].append (e);
entry_count++;
}
}
if (this->entry_count >= this->threshold) this->rehash ();
return *this;
}
qse_size_t getSize () const
{
return this->entry_count;
}
bool isEmpty () const
{
return this->entry_count == 0;
}
qse_size_t getBucketSize () const
{
return this->bucket_size;
}
Bucket& getBucket (qse_size_t index) const
{
qse_assert (index < this->bucket_size);
return this->buckets[index];
}
#if 0
V& operator[] (const K& key)
{
qse_size_t hc = this->hasher(key) % this->bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key) return e.value;
}
if (entry_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e2 = buckets[hc].append (Entry(key));
entry_count++;
return e2.value;
}
const V& operator[] (const K& key) const
{
qse_size_t hc = this->hasher(key) % this->bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key) return e.value;
}
if (entry_count >= threshold)
{
this->rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e2 = buckets[hc].append (Entry(key));
entry_count++;
return e2.value;
}
#endif
//
// NOTE: getConstWithCustomKey() and getWithCustomKey() would
// not need to have different names if compilers were smarter.
//
template <typename MK, typename MHASHER>
const V* getConstWithCustomKey (const MK& key) const
{
MHASHER h;
qse_size_t hc = h(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 QSE_NULL;
}
template <typename MK, typename MHASHER>
V* getWithCustomKey (const MK& key) const
{
MHASHER h;
qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward()) {
Entry& e = np->value;
if (key == e.key) return &e.value;
}
return QSE_NULL;
}
V* get (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()) {
Entry& e = np->value;
if (key == e.key) return &e.value;
}
return QSE_NULL;
}
const V* get (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()) {
const Entry& e = np->value;
if (key == e.key) return &e.value;
}
return QSE_NULL;
}
V* get (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()) {
Entry& e = np->value;
if (key == e.key) {
*hash_code = hc;
*node = np;
return &e.value;
}
}
return QSE_NULL;
}
const V* get (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())
{
Entry& e = np->value;
if (key == e.key)
{
*hash_code = hc;
*node = np;
return &e.value;
}
}
return QSE_NULL;
}
int put (const K& key, const V& value)
{
upsert (key, value);
return 0;
}
int putNew (const K& key, const V& value)
{
return (insertNew(key,value) == QSE_NULL)? -1: 0;
}
V* insert (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())
{
Entry& e = np->value;
if (key == e.key) return &e.value;
}
if (entry_count >= threshold)
{
rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e = buckets[hc].append (Entry(key));
entry_count++;
return &e.value;
}
V* insert (const K& key, const V& value)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key) return &e.value;
}
if (entry_count >= threshold)
{
rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e = buckets[hc].append (Entry(key,value));
entry_count++;
return &e.value;
}
V* insertNew (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())
{
Entry& e = np->value;
if (key == e.key) return QSE_NULL;
}
if (entry_count >= threshold)
{
rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e = buckets[hc].append (Entry(key));
entry_count++;
return &e.value;
}
V* insertNew (const K& key, const V& value)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key) return QSE_NULL;
}
if (entry_count >= threshold)
{
rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e = buckets[hc].append (Entry(key, value));
entry_count++;
return &e.value;
}
V* upsert (const K& key, const V& value)
{
qse_size_t hc = this->hasher(key) % bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key)
{
e.value = value;
return &e.value;
}
}
if (entry_count >= threshold)
{
rehash ();
hc = this->hasher(key) % bucket_size;
}
Entry& e = buckets[hc].append (Entry(key,value));
entry_count++;
return &e.value;
}
template <typename MK, typename MHASHER>
int removeWithCustomKey (const MK& key)
{
MHASHER h;
qse_size_t hc = h(key) % bucket_size;
typename Bucket::Node* np;
for (np = buckets[hc].head(); np; np = np->forward())
{
Entry& e = np->value;
if (key == e.key)
{
this->buckets[hc].remove (np);
this->entry_count--;
return 0;
}
}
return -1;
}
int remove (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())
{
Entry& e = np->value;
if (key == e.key)
{
this->buckets[hc].remove (np);
this->entry_count--;
return 0;
}
}
return -1;
}
int remove (qse_size_t hc, typename Bucket::Node* np)
{
//
// WARNING: this method should be used with extra care.
//
this->buckets[hc].remove (np);
this->entry_count--;
return 0;
}
qse_size_t removeValue (const V& value)
{
qse_size_t count = 0;
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
typename Bucket::Node* np, * np2;
np = buckets[i].head();
while (np != QSE_NULL) {
Entry& e = np->value;
np2 = np->forward ();
if (value == e.value) {
this->remove (i, np);
count++;
}
np = np2;
}
}
return count;
}
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())
{
Entry& e = np->value;
if (key == e.key) return true;
}
return false;
}
bool containsValue (const K& value) const
{
for (qse_size_t i = 0; i < bucket_size; i++)
{
typename Bucket::Node* np;
for (np = buckets[i].head(); np; np = np->forward())
{
Entry& e = np->value;
if (value == e.value) return true;
}
}
return false;
}
void clear (int new_bucket_size = 0)
{
for (qse_size_t i = 0; i < bucket_size; i++) buckets[i].clear ();
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;
}
}
typedef int (SelfType::*TraverseCallback)
(const Entry& entry, void* user_data) const;
int traverse (TraverseCallback callback, void* user_data) const
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
typename Bucket::Node* np;
for (np = buckets[i].head(); np; np = np->forward())
{
const Entry& e = np->value;
if ((this->*callback)(e,user_data) == -1) return -1;
}
}
return 0;
}
typedef int (*StaticTraverseCallback)
(SelfType* table, Entry& entry, void* user_data);
int traverse (StaticTraverseCallback callback, void* user_data)
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
typename Bucket::Node* np;
for (np = buckets[i].head(); np; np = np->forward())
{
Entry& e = np->value;
if (callback(this,e,user_data) == -1) return -1;
}
}
return 0;
}
protected:
mutable qse_size_t entry_count;
mutable qse_size_t bucket_size;
mutable Bucket* buckets;
mutable qse_size_t threshold;
qse_size_t load_factor;
HASHER hasher;
RESIZER resizer;
void rehash () const
{
qse_size_t new_bucket_size = this->resizer (this->bucket_size);
Bucket* new_buckets = new Bucket[new_bucket_size];
try
{
for (qse_size_t i = 0; i < this->bucket_size; i++)
{
/*
typename Bucket::Node* np;
for (np = buckets[i].head(); np; np = np->forward())
{
const Entry& e = np->value;
qse_size_t hc = e.key.hashCode() % new_bucket_size;
new_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.
typename Bucket::Node* np = buckets[i].head();
while (np)
{
typename Bucket::Node* next = np->forward();
const Entry& e = np->value;
qse_size_t hc = this->hasher(e.key) % new_bucket_size;
new_buckets[hc].appendNode (buckets[i].yield(np));
np = next;
}
}
}
catch (...)
{
delete[] new_buckets;
throw;
}
delete[] this->buckets;
this->buckets = new_buckets;
this->bucket_size = new_bucket_size;
this->threshold = this->load_factor * this->bucket_size / 100;
}
};
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////
#endif

View File

@ -35,13 +35,29 @@
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
/// The HeapMmgr class implements the heap-based memory manager interface. /// The HeapMmgr class implements a memory management interface that
/// It is a memory manager that's memory managed by another memory manager. /// handles a memory heap of a given size. Notably, it is a memory manager
/// managed by another memory manager.
///
/// \code
/// QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000);
/// QSE::LinkedList<int> int_list (&heap_mmgr);
/// int_list.append (10);
/// int_list.append (20);
/// \endcode
class QSE_EXPORT HeapMmgr: public Mmgr, public Mmged class QSE_EXPORT HeapMmgr: public Mmgr, public Mmged
{ {
public: public:
/// The constructor function accepts an memory manager \a mmgr that
/// is used to create a heap of the size \a heap_size. Optionally,
/// you can ask the memory manager to return #QSE_NULL upon allocation
/// failure by setting \a raise_exception to false.
HeapMmgr (Mmgr* mmgr, qse_size_t heap_size, bool raise_exception = true); HeapMmgr (Mmgr* mmgr, qse_size_t heap_size, bool raise_exception = true);
/// The destructor function frees the heap. Memory areas returned by
/// allocate(), reallocate(), allocMem(), reallocMem() are invalidated
/// all at once.
~HeapMmgr (); ~HeapMmgr ();
void* allocMem (qse_size_t n); void* allocMem (qse_size_t n);

View File

@ -103,6 +103,10 @@ public:
this->node_count = 0; this->node_count = 0;
this->head_node = QSE_NULL; this->head_node = QSE_NULL;
this->tail_node = QSE_NULL; this->tail_node = QSE_NULL;
// the memory manager for the linked list must raise an exception
// upon memory allocation error.
QSE_ASSERT (this->getMmgr()->isExceptionRaising());
} }
LinkedList (const SelfType& ll): Mmged(ll.getMmgr()), mp (ll.getMmgr(), ll.mp.getDatumSize(), ll.mp.getBlockSize()) LinkedList (const SelfType& ll): Mmged(ll.getMmgr()), mp (ll.getMmgr(), ll.mp.getDatumSize(), ll.mp.getBlockSize())

View File

@ -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 Mpoolable.hpp LinkedList.hpp HashList.hpp Mpool.hpp Pair.hpp LinkedList.hpp HashList.hpp HashTable.hpp
endif endif

View File

@ -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 Mpoolable.hpp LinkedList.hpp HashList.hpp @ENABLE_CXX_TRUE@ Mpool.hpp Pair.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,7 @@ 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 Mpoolable.hpp LinkedList.hpp HashList.hpp Mpool.hpp Pair.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/||"`;; \

View File

@ -81,6 +81,15 @@ public:
/// ///
virtual ~Mmgr () {} virtual ~Mmgr () {}
///
/// The isExceptionRaising() function tells if the memory manager
/// throws an exception upon a memory allocation error.
///
bool isExceptionRaising () const
{
return this->raise_exception;
}
/// ///
/// The allocate() function calls allocMem() for memory /// The allocate() function calls allocMem() for memory
/// allocation. if it fails, it raise an exception if it's /// allocation. if it fails, it raise an exception if it's

View File

@ -24,52 +24,34 @@
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_MPOOLABLE_HPP_ #ifndef _QSE_CMN_PAIR_HPP_
#define _QSE_CMN_MPOOLABLE_HPP_ #define _QSE_CMN_PAIR_HPP_
#include <qse/cmn/Mpool.hpp> #include <qse/types.h>
#include <qse/macros.h>
// use size_t as some compilers complain about qse_size_t used in new().
#include <stddef.h>
///////////////////////////////// /////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
class QSE_EXPORT Mpoolable template <typename KEY, typename VALUE> class Pair
{ {
public: public:
KEY key;
VALUE value;
/* Pair () {}
inline void* operator new (mp_size_t size) Pair (const KEY& key): key (key) {}
{ Pair (const KEY& key, const VALUE& value): key (key), value (value) {}
return ::operator new (size);
}
inline void operator delete (void* ptr) KEY& getKey () { return this->key; }
{ const KEY& getKey () const { return this->key; }
::operator delete (ptr);
}
*/
inline void* operator new (size_t size, Mpool* mp) VALUE& getValue () { return this->value; }
{ const VALUE& getValue () const { return this->value; }
return mp->isEnabled()? mp->allocate (): ::operator new (size);
}
#if defined(_MSC_VER) void setKey (const KEY& key) { this->key = key; }
void operator delete (void* ptr, Mpool* mp) void setValue (const VALUE& value) { this->value = value; }
{
if (mp->isEnabled()) mp->dispose (ptr);
else ::operator delete (mp);
}
#else
inline void dispose (void* ptr, Mpool* mp)
{
if (mp->isEnabled()) mp->dispose (ptr);
else ::operator delete (mp);
}
#endif
}; };
///////////////////////////////// /////////////////////////////////

View File

@ -80,10 +80,7 @@ void* HeapMmgr::reallocMem (void* ptr, qse_size_t n)
void HeapMmgr::freeMem (void* ptr) void HeapMmgr::freeMem (void* ptr)
{ {
if (this->xma) if (this->xma) qse_xma_free (this->xma, ptr);
{
qse_xma_free (this->xma, ptr);
}
} }
///////////////////////////////// /////////////////////////////////