diff --git a/qse/include/qse/cmn/HashList.hpp b/qse/include/qse/cmn/HashList.hpp index 994ecdcb..b4f01f41 100644 --- a/qse/include/qse/cmn/HashList.hpp +++ b/qse/include/qse/cmn/HashList.hpp @@ -199,6 +199,11 @@ public: if (this->datum_list) this->free_datum_list (); } + Mpool& getMpool () + { + return this->datum_list->getMpool (); + } + SelfType& operator= (const SelfType& list) { this->clear (); @@ -301,12 +306,12 @@ protected: if (nodes[head] == QSE_NULL) { - this->nodes[head] = this->datum_list->insertValue (QSE_NULL, datum); + this->nodes[head] = this->datum_list->insert ((Node*)QSE_NULL, datum); this->nodes[tail] = this->nodes[head]; } else { - this->nodes[head] = datum_list->insertValue (this->nodes[head], datum); + this->nodes[head] = datum_list->insert (this->nodes[head], datum); } return this->nodes[head]; @@ -467,7 +472,13 @@ protected: // Move nodes around instead of values to prevent // existing values from being copied over and destroyed. // this incurs less number of memory allocations also. - SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, this->datum_list->getMPBlockSize()); + Mpool& mpool = this->getMpool(); + + // Using the memory pool block size of 0 is OK because the nodes + // to be inserted are yielded off the original list and inserted + // without new allocation. + //SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, mpool.getBlockSize()); + SelfType temp (this->getMmgr(), this->resizer(this->node_capacity), this->load_factor, 0); Node* p = this->datum_list->getHeadNode(); while (p) { @@ -491,7 +502,7 @@ protected: } else { - temp.nodes[head] = temp.datum_list->insertNode (QSE_NULL, pp); + temp.nodes[head] = temp.datum_list->insertNode ((Node*)QSE_NULL, pp); temp.nodes[tail] = temp.nodes[head]; } @@ -507,7 +518,13 @@ protected: this->nodes[i] = QSE_NULL; } - // swap the contents + // swapping the memory pool is a critical thing to do + // especially when the memory pooling is enabled. the datum node in + // 'temp' is actual allocated inside 'mpool' not inside temp.getMpool(). + // it is because yield() has been used for insertion into 'temp'. + mpool.swap (temp.getMpool()); + + // swap the actual contents qse_size_t temp_capa = temp.node_capacity; Node** temp_nodes = temp.nodes; DatumList* temp_datum_list = temp.datum_list; @@ -539,12 +556,12 @@ protected: if (new_nodes[head] == QSE_NULL) { - new_nodes[head] = new_datum_list->insertValue (QSE_NULL, t); + new_nodes[head] = new_datum_list->insert ((Node*)QSE_NULL, t); new_nodes[tail] = new_nodes[head]; } else { - new_nodes[head] = new_datum_list->insertValue (new_nodes[head], t); + new_nodes[head] = new_datum_list->insert (new_nodes[head], t); } } diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp index 5f9381b6..9463dc9e 100644 --- a/qse/include/qse/cmn/LinkedList.hpp +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -46,8 +46,8 @@ public: T value; // you can use this variable or accessor functions below protected: - SelfType* next; SelfType* prev; + SelfType* next; public: T& getValue () { return this->value; } @@ -126,13 +126,13 @@ public: return saved; } - int operator== (const SelfType& it) const + bool operator== (const SelfType& it) const { QSE_ASSERT (this->current != QSE_NULL); return this->current == it.current; } - int operator!= (const SelfType& it) const + bool operator!= (const SelfType& it) const { QSE_ASSERT (this->current != QSE_NULL); return this->current != it.current; @@ -143,6 +143,23 @@ public: return this->current != QSE_NULL; } + T& operator* () // dereference + { + return this->current->getValue(); + } + + const T& operator* () const // dereference + { + return this->current->getValue(); + } + +#if 0 + T* operator-> () + { + return &this->current->getValue(); + } +#endif + T& getValue () { QSE_ASSERT (this->current != QSE_NULL); @@ -247,14 +264,9 @@ public: } #endif - qse_size_t getMPBlockSize() const + Mpool& getMpool () { - return this->mp.getBlockSize(); - } - - bool isMPEnabled () const - { - return this->mp.isEnabled(); + return this->mp; } qse_size_t getSize () const @@ -267,17 +279,15 @@ public: return this->node_count == 0; } - bool contains (const T& value) const - { - return this->findFirstNode(value) != QSE_NULL; - } - - // insert an externally created node. - // may need to take extra care when using this method. + /// The insertNode() function inserts an externally created \a node + /// before the node at the given position \a pos. If \a pos is QSE_NULL, + /// the \a node is inserted at the back of the list. You must take extra + /// care when using this function. Node* insertNode (Node* pos, Node* node) { if (pos == QSE_NULL) { + // add to the back if (this->node_count == 0) { QSE_ASSERT (head_node == QSE_NULL); @@ -293,6 +303,7 @@ public: } else { + // insert 'node' before the node at the given position 'pos'. node->next = pos; node->prev = pos->prev; if (pos->prev) pos->prev->next = node; @@ -305,59 +316,22 @@ public: } // create a new node to hold the value and insert it. - Node* insertValue (Node* pos, const T& value) + Node* insert (Node* pos, const T& value) { Node* node = new(&this->mp) Node(value); return this->insertNode (pos, node); } - T& insert (Node* node, const T& value) + Node* prepend (const T& value) { - return this->insertValue(node, value)->value; - } - - T& insert (qse_size_t index, const T& value) - { - QSE_ASSERT (index <= node_count); - - if (index >= node_count) - { - // insert it at the back - return this->insert ((Node*)QSE_NULL, value); - } - - return this->insert (this->getNodeAt(index), value); - } - - T& prepend (const T& value) - { - // same as prependValue() return this->insert (this->head_node, value); } - T& append (const T& value) + + Node* append (const T& value) { - // same as appendValue() return this->insert ((Node*)QSE_NULL, value); } - Node* prependNode (Node* node) - { - return this->insertNode (head_node, node); - } - Node* appendNode (Node* node) - { - return this->insertNode ((Node*)QSE_NULL, node); - } - - Node* prependValue (const T& value) - { - return this->insertValue (this->head_node, value); - } - Node* appendValue (const T& value) - { - return this->insertValue ((Node*)QSE_NULL, value); - } - void prependAll (const SelfType& list) { Node* n = list.tail_node; @@ -435,6 +409,7 @@ public: return node; } + // remove a node from the list and free it. void remove (Node* node) { @@ -446,20 +421,6 @@ public: ::operator delete (node, &this->mp); } - void remove (qse_size_t index) - { - QSE_ASSERT (index < node_count); - - Node* np = this->head_node; - while (index > 0) - { - np = np->next; - index--; - } - - this->remove (np); - } - Node* yieldByValue (const T& value, bool clear_links = true) { Node* p = this->findFirstNode (value); @@ -611,7 +572,7 @@ public: qse_size_t findLastIndex (const T& value) const { - qse_size_t index = node_count; + qse_size_t index = this->node_count; for (Node* p = tail_node; p; p = p->prev) { index--; @@ -647,10 +608,20 @@ public: this->mp.dispose (); } - //void reverse () - //{ - // - //} + /// The reverse() function reverses the order of nodes. + void reverse () + { + if (this->node_count > 0) + { + Node* head = this->head_node; + QSE_ASSERT (head != QSE_NULL); + while (head->next) + { + Node* next_node = this->yield (head->next, false); + this->insertNode (this->head_node, next_node); + } + } + } typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); @@ -674,7 +645,15 @@ public: Iterator getIterator (qse_size_t index = 0) const { - return Iterator (this->getNodeAt(index)); + 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: diff --git a/qse/include/qse/cmn/Mpool.hpp b/qse/include/qse/cmn/Mpool.hpp index 7e187321..3a375f85 100644 --- a/qse/include/qse/cmn/Mpool.hpp +++ b/qse/include/qse/cmn/Mpool.hpp @@ -56,30 +56,33 @@ public: void dispose (void* ptr); void dispose (); - inline bool isEnabled () const + bool isEnabled () const { return this->datum_size > 0 && this->block_size > 0; } - inline bool isDisabled () const + + bool isDisabled () const { return this->datum_size <= 0 || this->block_size <= 0; } - inline qse_size_t getDatumSize () const + qse_size_t getDatumSize () const { return this->datum_size; } - inline qse_size_t getBlockSize () const + qse_size_t getBlockSize () const { return this->block_size; } - inline void setBlockSize (qse_size_t blockSize) + void setBlockSize (qse_size_t blockSize) { this->block_size = blockSize; } + int swap (Mpool& mpool); + #if defined(QSE_DEBUG_MPOOL) qse_size_t nalloc; qse_size_t navail; @@ -97,6 +100,8 @@ protected: Chain* next; }; + // NOTE: whenever you add new member variables, make sure to + // update the swap() function accordingly Block* mp_blocks; Chain* free_list; qse_size_t datum_size; diff --git a/qse/lib/cmn/Mpool.cpp b/qse/lib/cmn/Mpool.cpp index a00acbde..2e925fd9 100644 --- a/qse/lib/cmn/Mpool.cpp +++ b/qse/lib/cmn/Mpool.cpp @@ -132,6 +132,50 @@ Mpool::Block* Mpool::add_block () return block; } +int Mpool::swap (Mpool& mpool) +{ + // this function is sensitive to member variables changes. + // whenever you add new member variables, this function require + // relevant changes. + + if (this->getMmgr() != mpool.getMmgr()) + { + // disallow to swap contents if memory managers are different. + return -1; + } + + if (this != &mpool) + { + #if defined(QSE_DEBUG_MPOOL) + qse_size_t org_nalloc = this->nalloc; + qse_size_t org_navail = this->navail; + + this->nalloc = mpool.nalloc; + this->navail = mpool.navail; + + mpool.nalloc = org_nalloc; + mpool.navail = org_navail; + #endif + + Block* org_mp_blocks = this->mp_blocks; + Chain* org_free_list = this->free_list; + qse_size_t org_datum_size = this->datum_size; + qse_size_t org_block_size = this->block_size; + + this->mp_blocks = mpool.mp_blocks; + this->free_list = mpool.free_list; + this->datum_size = mpool.datum_size; + this->block_size = mpool.block_size; + + mpool.mp_blocks = org_mp_blocks; + mpool.free_list = org_free_list; + mpool.datum_size = org_datum_size; + mpool.block_size = org_block_size; + } + + return 0; +} + ///////////////////////////////// QSE_END_NAMESPACE(QSE) /////////////////////////////////