added Mpool::swap().
fixed a bug in HashList::rehash() when the memory pool is enabled. added LinkedList::reverse()
This commit is contained in:
		| @ -199,6 +199,11 @@ public: | |||||||
| 		if (this->datum_list) this->free_datum_list (); | 		if (this->datum_list) this->free_datum_list (); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	Mpool& getMpool () | ||||||
|  | 	{ | ||||||
|  | 		return this->datum_list->getMpool (); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	SelfType& operator= (const SelfType& list) | 	SelfType& operator= (const SelfType& list) | ||||||
| 	{ | 	{ | ||||||
| 		this->clear (); | 		this->clear (); | ||||||
| @ -301,12 +306,12 @@ protected: | |||||||
|  |  | ||||||
| 		if (nodes[head] == QSE_NULL)  | 		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]; | 			this->nodes[tail] = this->nodes[head]; | ||||||
| 		} | 		} | ||||||
| 		else  | 		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]; | 		return this->nodes[head]; | ||||||
| @ -467,7 +472,13 @@ protected: | |||||||
| 		// 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->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(); | 		Node* p = this->datum_list->getHeadNode(); | ||||||
| 		while (p) | 		while (p) | ||||||
| 		{ | 		{ | ||||||
| @ -491,7 +502,7 @@ protected: | |||||||
| 			} | 			} | ||||||
| 			else  | 			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]; | 				temp.nodes[tail] = temp.nodes[head]; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -507,7 +518,13 @@ protected: | |||||||
| 			this->nodes[i] = QSE_NULL; | 			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; | 		qse_size_t temp_capa = temp.node_capacity; | ||||||
| 		Node** temp_nodes = temp.nodes; | 		Node** temp_nodes = temp.nodes; | ||||||
| 		DatumList* temp_datum_list = temp.datum_list; | 		DatumList* temp_datum_list = temp.datum_list; | ||||||
| @ -539,12 +556,12 @@ protected: | |||||||
|  |  | ||||||
| 		if (new_nodes[head] == QSE_NULL)  | 		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]; | 			new_nodes[tail] = new_nodes[head]; | ||||||
| 		} | 		} | ||||||
| 		else  | 		else  | ||||||
| 		{ | 		{ | ||||||
| 			new_nodes[head] = new_datum_list->insertValue (new_nodes[head], t); | 			new_nodes[head] = new_datum_list->insert (new_nodes[head], t); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -46,8 +46,8 @@ public: | |||||||
| 	T value; // you can use this variable or accessor functions below | 	T value; // you can use this variable or accessor functions below | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	SelfType* next; |  | ||||||
| 	SelfType* prev; | 	SelfType* prev; | ||||||
|  | 	SelfType* next; | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	T& getValue () { return this->value; } | 	T& getValue () { return this->value; } | ||||||
| @ -126,13 +126,13 @@ public: | |||||||
| 		return saved; | 		return saved; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	int operator== (const SelfType& it) const | 	bool operator== (const SelfType& it) const | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (this->current != QSE_NULL); | 		QSE_ASSERT (this->current != QSE_NULL); | ||||||
| 		return this->current == it.current; | 		return this->current == it.current; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	int operator!= (const SelfType& it) const | 	bool operator!= (const SelfType& it) const | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (this->current != QSE_NULL); | 		QSE_ASSERT (this->current != QSE_NULL); | ||||||
| 		return this->current != it.current; | 		return this->current != it.current; | ||||||
| @ -143,6 +143,23 @@ public: | |||||||
| 		return this->current != QSE_NULL; | 		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 () | 	T& getValue () | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (this->current != QSE_NULL); | 		QSE_ASSERT (this->current != QSE_NULL); | ||||||
| @ -247,14 +264,9 @@ public: | |||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	qse_size_t getMPBlockSize() const | 	Mpool& getMpool () | ||||||
| 	{ | 	{ | ||||||
| 		return this->mp.getBlockSize(); | 		return this->mp; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool isMPEnabled () const |  | ||||||
| 	{ |  | ||||||
| 		return this->mp.isEnabled(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	qse_size_t getSize () const  | 	qse_size_t getSize () const  | ||||||
| @ -267,17 +279,15 @@ public: | |||||||
| 		return this->node_count == 0; | 		return this->node_count == 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool contains (const T& value) const | 	/// The insertNode() function inserts an externally created \a node | ||||||
| 	{ | 	/// before the node at the given position \a pos. If \a pos is QSE_NULL, | ||||||
| 		return this->findFirstNode(value) != QSE_NULL;     | 	/// the \a node is inserted at the back of the list. You must take extra | ||||||
| 	} | 	/// care when using this function. | ||||||
|  |  | ||||||
| 	// insert an externally created node. |  | ||||||
| 	// may need to take extra care when using this method. |  | ||||||
| 	Node* insertNode (Node* pos, Node* node) | 	Node* insertNode (Node* pos, Node* node) | ||||||
| 	{ | 	{ | ||||||
| 		if (pos == QSE_NULL)  | 		if (pos == QSE_NULL)  | ||||||
| 		{ | 		{ | ||||||
|  | 			// add to the back | ||||||
| 			if (this->node_count == 0)  | 			if (this->node_count == 0)  | ||||||
| 			{ | 			{ | ||||||
| 				QSE_ASSERT (head_node == QSE_NULL); | 				QSE_ASSERT (head_node == QSE_NULL); | ||||||
| @ -293,6 +303,7 @@ public: | |||||||
| 		} | 		} | ||||||
| 		else  | 		else  | ||||||
| 		{ | 		{ | ||||||
|  | 			// insert 'node' before the node at the given position 'pos'. | ||||||
| 			node->next = pos; | 			node->next = pos; | ||||||
| 			node->prev = pos->prev; | 			node->prev = pos->prev; | ||||||
| 			if (pos->prev) pos->prev->next = node; | 			if (pos->prev) pos->prev->next = node; | ||||||
| @ -305,59 +316,22 @@ public: | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// create a new node to hold the value and insert it. | 	// 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); | 		Node* node = new(&this->mp) Node(value); | ||||||
| 		return this->insertNode (pos, node); | 		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); | 		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); | 		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) | 	void prependAll (const SelfType& list) | ||||||
| 	{ | 	{ | ||||||
| 		Node* n = list.tail_node; | 		Node* n = list.tail_node; | ||||||
| @ -435,6 +409,7 @@ public: | |||||||
|  |  | ||||||
| 		return node; | 		return node; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// remove a node from the list and free it. | 	// remove a node from the list and free it. | ||||||
| 	void remove (Node* node) | 	void remove (Node* node) | ||||||
| 	{ | 	{ | ||||||
| @ -446,20 +421,6 @@ public: | |||||||
| 		::operator delete (node, &this->mp); | 		::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* yieldByValue (const T& value, bool clear_links = true) | ||||||
| 	{ | 	{ | ||||||
| 		Node* p = this->findFirstNode (value); | 		Node* p = this->findFirstNode (value); | ||||||
| @ -611,7 +572,7 @@ public: | |||||||
|  |  | ||||||
| 	qse_size_t findLastIndex (const T& value) const | 	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)  | 		for (Node* p = tail_node; p; p = p->prev)  | ||||||
| 		{ | 		{ | ||||||
| 			index--; | 			index--; | ||||||
| @ -647,10 +608,20 @@ public: | |||||||
| 		this->mp.dispose (); | 		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); | 	typedef int (SelfType::*TraverseCallback) (Node* start, Node* cur); | ||||||
|  |  | ||||||
| @ -674,8 +645,16 @@ public: | |||||||
|  |  | ||||||
| 	Iterator getIterator (qse_size_t index = 0) const | 	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)); | 			return Iterator (this->getNodeAt(index)); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	MPOOL       mp; | 	MPOOL       mp; | ||||||
|  | |||||||
| @ -56,30 +56,33 @@ public: | |||||||
| 	void  dispose (void* ptr); | 	void  dispose (void* ptr); | ||||||
| 	void  dispose (); | 	void  dispose (); | ||||||
|  |  | ||||||
| 	inline bool isEnabled () const | 	bool isEnabled () const | ||||||
| 	{ | 	{ | ||||||
| 		return this->datum_size > 0 && this->block_size > 0; | 		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; | 		return this->datum_size <= 0 || this->block_size <= 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline qse_size_t getDatumSize () const | 	qse_size_t getDatumSize () const | ||||||
| 	{ | 	{ | ||||||
| 		return this->datum_size; | 		return this->datum_size; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline qse_size_t getBlockSize () const | 	qse_size_t getBlockSize () const | ||||||
| 	{ | 	{ | ||||||
| 		return this->block_size; | 		return this->block_size; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void setBlockSize (qse_size_t blockSize)  | 	void setBlockSize (qse_size_t blockSize)  | ||||||
| 	{ | 	{ | ||||||
| 		this->block_size = blockSize; | 		this->block_size = blockSize; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	int swap (Mpool& mpool); | ||||||
|  |  | ||||||
| #if defined(QSE_DEBUG_MPOOL) | #if defined(QSE_DEBUG_MPOOL) | ||||||
| 	qse_size_t  nalloc; | 	qse_size_t  nalloc; | ||||||
| 	qse_size_t  navail; | 	qse_size_t  navail; | ||||||
| @ -97,6 +100,8 @@ protected: | |||||||
| 		Chain* next; | 		Chain* next; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	// NOTE: whenever you add new member variables, make sure to | ||||||
|  | 	//       update the swap() function accordingly | ||||||
| 	Block* mp_blocks; | 	Block* mp_blocks; | ||||||
| 	Chain* free_list; | 	Chain* free_list; | ||||||
| 	qse_size_t datum_size; | 	qse_size_t datum_size; | ||||||
|  | |||||||
| @ -132,6 +132,50 @@ Mpool::Block* Mpool::add_block () | |||||||
| 	return 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) | QSE_END_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user