wrote mote code for Array
This commit is contained in:
		| @ -38,6 +38,8 @@ struct ArrayResizer | ||||
| { | ||||
| 	qse_size_t operator() (qse_size_t current) const | ||||
| 	{ | ||||
| 		if (current <= 0) current = 1; | ||||
|  | ||||
| 		return (current < 5000)?   (current + current): | ||||
| 		       (current < 50000)?  (current + (current / 2)): | ||||
| 		       (current < 100000)? (current + (current / 4)): | ||||
| @ -46,11 +48,24 @@ struct ArrayResizer | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template <typename T, typename RESIZER = ArrayResizer> | ||||
| template<typename T> | ||||
| struct ArrayAssigner | ||||
| { | ||||
| 	// The assignment proxy is used to get the value informed of its position | ||||
| 	// within the heap. This default implmentation, however, doesn't utilize | ||||
| 	// the position (index). | ||||
| 	T& operator() (T& v1, const T& v2, qse_size_t index) const | ||||
| 	{ | ||||
| 		v1 = v2; | ||||
| 		return v1; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template <typename T, typename ASSIGNER = ArrayAssigner<T>, typename RESIZER = ArrayResizer > | ||||
| class Array: public Mmged | ||||
| { | ||||
| public: | ||||
| 	typedef Array<T,RESIZER> SelfType; | ||||
| 	typedef Array<T,ASSIGNER,RESIZER> SelfType; | ||||
|  | ||||
| 	enum  | ||||
| 	{ | ||||
| @ -59,8 +74,8 @@ public: | ||||
| 	}; | ||||
|  | ||||
| 	Array (Mmgr* mmgr = QSE_NULL, | ||||
| 	            qse_size_t capacity = DEFAULT_CAPACITY,  | ||||
| 	            qse_size_t mpb_size = 0): | ||||
| 	       qse_size_t capacity = DEFAULT_CAPACITY,  | ||||
| 	       qse_size_t mpb_size = 0): | ||||
| 		Mmged (mmgr), | ||||
| 		mp (mmgr, QSE_SIZEOF(T), mpb_size) | ||||
| 	{ | ||||
| @ -79,82 +94,89 @@ public: | ||||
| 		this->count  = 0; | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	Array (const SelfType& array) | ||||
| 	Array (const SelfType& array):  | ||||
| 		Mmged (array.getMmgr()), | ||||
| 		mp (array.getMmgr(), array.mp.getDatumSize(), array.mp.getBlockSize()), | ||||
| 		count (0), capacity (0), buffer (QSE_NULL) | ||||
| 	{ | ||||
| 		if (array.buffer == QSE_NULL)  | ||||
| 		if (array.buffer) | ||||
| 		{ | ||||
| 			this->buffer = QSE_NULL; | ||||
| 			this->capacity = 0; | ||||
| 			this->grow_factor = array.grow_factor; | ||||
| 			this->count  = 0; | ||||
| 		} | ||||
| 		else  | ||||
| 		{ | ||||
| 			T* tmp = QSE_NULL; | ||||
| 			QSE_ASSERT (array.capacity > 0 && array.grow_factor > 0); | ||||
|  | ||||
| 			try {   | ||||
| 				tmp = new T[array.capacity]; | ||||
| 				for (qse_size_t i = 0; i < array.this->count; i++) { | ||||
| 					tmp[i] = array.buffer[i]; | ||||
| 				} | ||||
| 			} | ||||
| 			catch (...) { | ||||
| 				// just in case where the assignment throws an  | ||||
| 				// exception. when T is a class type, the operator =  | ||||
| 				// for the class may throw an exception. | ||||
| 				if (tmp != QSE_NULL) delete[] tmp; | ||||
| 				throw; | ||||
| 			} | ||||
|  | ||||
| 			this->buffer = tmp; | ||||
| 			this->buffer = this->clone_buffer (array, array.capacity, array.count); | ||||
| 			this->count = array.count; | ||||
| 			this->capacity = array.capacity; | ||||
| 			this->grow_factor = array.grow_factor; | ||||
| 			this->count  = array.this->count; | ||||
| 		} | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	~Array () | ||||
| 	{ | ||||
| 		if (this->buffer) | ||||
| 		{ | ||||
| 			for (qse_size_t i = this->count; i > 0; ) | ||||
| 			{ | ||||
| 				--i; | ||||
| 				this->buffer[i].~T (); | ||||
| 			} | ||||
|  | ||||
| 			::operator delete (this->buffer, &this->mp); | ||||
| 		} | ||||
| 		this->clear (true); | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	SelfType& operator= (const SelfType& array) | ||||
| 	{ | ||||
| 		setSize (array.this->count); | ||||
| 		for (qse_size_t i = 0; i < array.this->count; i++) { | ||||
| 			this->buffer[i] = array.buffer[i]; | ||||
| 		this->clear (true); | ||||
| 		if (array.buffer) | ||||
| 		{ | ||||
| 			this->buffer = this->clone_buffer (array, array.capacity, array.count); | ||||
| 			this->count = array.count; | ||||
| 			this->capacity = array.capacity; | ||||
| 		} | ||||
| 		return *this; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	Array<T>& operator+= (const T& value) | ||||
| protected: | ||||
| 	T* clone_buffer (const T* srcbuf, qse_size_t capa, qse_size_t count) | ||||
| 	{ | ||||
| 		addDatum (value); | ||||
| 		return *this; | ||||
| 	} | ||||
| 	Array<T>& operator+ (const T& value) const | ||||
| 	{ | ||||
| 		Array<T> array (*this); | ||||
| 		array.addDatum (value); | ||||
| 		return array; | ||||
| 	} | ||||
| 	*/ | ||||
| 		QSE_ASSERT (capa > 0); | ||||
| 		QSE_ASSERT (count <= capa); | ||||
|  | ||||
| 		qse_size_t index; | ||||
|  | ||||
| 		//T* tmp = new T[capa]; | ||||
| 		T* tmp = (T*)::operator new (capa * QSE_SIZEOF(*tmp), &this->mp); | ||||
|  | ||||
| 		try  | ||||
| 		{ | ||||
| 			for (index = 0; index < count; index++)  | ||||
| 			{ | ||||
| 				//tmp[index] = srcbuf[index]; | ||||
| 				// copy-construct each element. | ||||
| 				new((QSE::Mpool*)QSE_NULL, &tmp[index]) T(srcbuf[index]); | ||||
| 			} | ||||
| 		} | ||||
| 		catch (...)  | ||||
| 		{ | ||||
| 			// in case copy-constructor raises an exception. | ||||
| 			QSE_ASSERT (tmp != QSE_NULL); | ||||
| 			while (index > 0) | ||||
| 			{ | ||||
| 				--index; | ||||
| 				tmp[index].~T (); | ||||
| 			} | ||||
| 			::operator delete (tmp, &this->mp); | ||||
| 			throw; | ||||
| 		} | ||||
|  | ||||
| 		return tmp; | ||||
| 	} | ||||
|  | ||||
| 	void put_item (qse_size_t index, const T& value) | ||||
| 	{ | ||||
| 		if (index >= this->count) | ||||
| 		{ | ||||
| 			// no value exists in the given position. | ||||
| 			// i can copy-construct the value. | ||||
| 			new((QSE::Mpool*)QSE_NULL, &this->buffer[index]) T(value); | ||||
| 			//this->notify_position (this->buffer[index], index); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// there is an old value in the position. | ||||
| 			this->assigner (this->buffer[index], value, index); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| 	bool isEmpty () const | ||||
| 	{ | ||||
| 		return this->count == 0; | ||||
| @ -190,6 +212,19 @@ public: | ||||
| 		return this->buffer; | ||||
| 	} | ||||
|  | ||||
| 	/// The getBufferIndex() function returns the index of the | ||||
| 	/// given value \a v if it is one of the values of the array. | ||||
| 	/// It returns #INVALID_INDEX if not. | ||||
| 	qse_size_t getIndex (const T& v) | ||||
| 	{ | ||||
| 		if (&v >= &this->buffer[0] && &v < &this->buffer[this->count]) | ||||
| 		{ | ||||
| 			return &v - &this->buffer[0]; | ||||
| 		} | ||||
|  | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
|  | ||||
| 	T& operator[] (qse_size_t index) | ||||
| 	{ | ||||
| 		QSE_ASSERT (index < this->count); | ||||
| @ -217,23 +252,15 @@ public: | ||||
| 	void set (qse_size_t index, const T& value) | ||||
| 	{ | ||||
| 		QSE_ASSERT (index < this->count); | ||||
| 		this->buffer[index] = value; | ||||
| 		this->insert (index, value); | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	void set_item (qse_size_t index, const T& value) | ||||
| 	{ | ||||
| 		if (index >= this->count) | ||||
| 			new((QSE::Mpool*)QSE_NULL, &this->buffer[index]) T(value); | ||||
| 		else | ||||
| 			this->buffer[index] = value; | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| 	qse_size_t insert (qse_size_t index, const T& value) | ||||
| 	{ | ||||
| 		if (index >= this->capacity)  | ||||
| 		{ | ||||
| 			// the position to add the element is beyond the | ||||
| 			// capacity. resize the buffer. | ||||
| 			qse_size_t new_capa = this->resizer (this->capacity); | ||||
|  | ||||
| 			if (index < new_capa) | ||||
| @ -243,18 +270,33 @@ public: | ||||
| 		} | ||||
| 		else if (this->count >= this->capacity)  | ||||
| 		{ | ||||
| 			// the array is already full. | ||||
| 			// insertion requires at least one more slot | ||||
| 			qse_size_t new_capa = this->resizer (this->capacity); | ||||
| 			this->setCapacity (new_capa); | ||||
| 		} | ||||
|  | ||||
| 		for (qse_size_t i = this->count; i > index; i--)  | ||||
| 		if (index < this->count) | ||||
| 		{ | ||||
| 			//this->buffer[i] = this->buffer[i - 1]; | ||||
| 			this->set_item (i, this->buffer[i - 1]); | ||||
| 			// shift the existing elements to the back by one slot. | ||||
| 			for (qse_size_t i = this->count; i > index; i--)  | ||||
| 			{ | ||||
| 				//this->buffer[i] = this->buffer[i - 1]; | ||||
| 				this->put_item (i, this->buffer[i - 1]); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (index > this->count) | ||||
| 		{ | ||||
| 			// the insertion position leaves some gaps in between. | ||||
| 			// fill the gap with a default value. | ||||
| 			for (qse_size_t i = this->count; i < index; i++) | ||||
| 			{ | ||||
| 				new((QSE::Mpool*)QSE_NULL, &this->buffer[i]) T(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		//this->buffer[index] = value; | ||||
| 		this->set_item (index, value); | ||||
| 		this->put_item (index, value); | ||||
| 		if (index > this->count) this->count = index + 1; | ||||
| 		else this->count++; | ||||
|  | ||||
| @ -273,150 +315,171 @@ public: | ||||
|  | ||||
| 		qse_size_t j = from_index; | ||||
| 		qse_size_t i = to_index + 1; | ||||
|  | ||||
| 		// replace deleted elements by surviving elements at the back | ||||
| 		while (i < this->count)  | ||||
| 		{ | ||||
| 			this->buffer[j++] = this->buffer[i++]; | ||||
| 			//this->buffer[j++] = this->buffer[i++]; | ||||
| 			this->assigner (this->buffer[j], this->buffer[i], j); | ||||
| 			j++; i++; | ||||
| 		} | ||||
|  | ||||
| 		// call the destructor of deleted elements. | ||||
| 		while (j < this->count) | ||||
| 		{ | ||||
| 			this->buffer[j].~T (); | ||||
| 			j++; | ||||
| 		} | ||||
|  | ||||
| 		// recalculate the number of elements  | ||||
| 		this->count -= to_index - from_index + 1; | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	qse_size_t addDatum (const T& value) | ||||
| protected: | ||||
| 	void clear_all_items  () | ||||
| 	{ | ||||
| 		return insert (this->count, value); | ||||
| 		QSE_ASSERT (this->count <= 0 || (this->count >= 1 && this->buffer)); | ||||
|  | ||||
| 		for (qse_size_t i = this->count; i > 0; ) | ||||
| 		{ | ||||
| 			--i; | ||||
| 			this->buffer[i].~T (); | ||||
| 		} | ||||
| 	 | ||||
| 		this->count = 0; | ||||
| 	} | ||||
|  | ||||
| 	qse_size_t removeDatum (const T& value) | ||||
| public: | ||||
| 	void clear (bool clear_mpool = false) | ||||
| 	{ | ||||
| 		qse_size_t i = 0, sz = this->size(); | ||||
| 		while (i < this->count)  | ||||
| 		this->clear_all_items (); | ||||
|  | ||||
| 		if (clear_mpool)  | ||||
| 		{ | ||||
| 			if (value == this->buffer[i])  | ||||
| 			if (this->buffer) | ||||
| 			{ | ||||
| 				remove (i); | ||||
| 				break; | ||||
| 				// the buffer has been allocated using the memory pool. | ||||
| 				// if the memory pool should be cleared, the buffer must | ||||
| 				// not be left over either. | ||||
| 				QSE_ASSERT (this->capacity > 0); | ||||
| 				::operator delete (this->buffer, &this->mp); | ||||
| 				this->capacity = 0; | ||||
| 				this->buffer = QSE_NULL; | ||||
| 			} | ||||
| 			i++; | ||||
|  | ||||
| 			QSE_ASSERT (this->capacity == 0); | ||||
| 			this->mp.dispose (); | ||||
| 		} | ||||
|  | ||||
| 		return sz - this->size(); | ||||
| 	} | ||||
|  | ||||
| 	qse_size_t removeDatums (const T& value) | ||||
| 	{ | ||||
| 		qse_size_t i = 0, sz = this->size(); | ||||
|  | ||||
| 		while (i < this->count)  | ||||
| 		{ | ||||
| 			if (value == this->buffer[i]) remove (i); | ||||
| 			else i++; | ||||
| 		} | ||||
|  | ||||
| 		return sz - this->size(); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
|  | ||||
| 	void clear () | ||||
| 	{ | ||||
| 		setSize (0); | ||||
| 	} | ||||
|  | ||||
| 	void trimToSize () | ||||
| 	{ | ||||
| 		setCapacity (this->size); | ||||
| 	} | ||||
|  | ||||
| 	void setSize (qse_size_t size) | ||||
| 	{ | ||||
| 		if (size > this->capacity) this->setCapacity (size); | ||||
| 		QSE_ASSERT (size <= this->capacity); | ||||
| 		this->count = size; | ||||
| 		if (size < this->count) | ||||
| 		{ | ||||
| 			for (qse_size_t i = size; i < this->count; ++i) | ||||
| 			{ | ||||
| 				// call the destructor of the items  | ||||
| 				this->buffer[i].~T (); | ||||
| 			} | ||||
|  | ||||
| 			this->count = size; | ||||
| 		} | ||||
| 		else if (size > this->count) | ||||
| 		{ | ||||
| 			if (size > this->capacity) this->setCapacity (size); | ||||
| 			for (qse_size_t i = this->count; i < size; ++i) | ||||
| 			{ | ||||
| 				// use the default contructor to set the value. | ||||
| 				new((QSE::Mpool*)QSE_NULL, &this->buffer[i]) T(); | ||||
| 			} | ||||
|  | ||||
| 			this->count = size; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void setCapacity (qse_size_t capacity) | ||||
| 	{ | ||||
| 		if (capacity <= 0)  | ||||
| 		{ | ||||
| 			if (this->buffer != QSE_NULL)  | ||||
| 				delete[] this->buffer; | ||||
| 			this->buffer = QSE_NULL; | ||||
| 			this->capacity = 0; | ||||
| 			this->count  = 0; | ||||
| 			this->clear (true); | ||||
| 		} | ||||
| 		else  | ||||
| 		{ | ||||
| 			T* tmp = QSE_NULL; | ||||
| 			 | ||||
| 			qse_size_t cnt = this->count; | ||||
| 			if (cnt > capacity) cnt = capacity; | ||||
|  | ||||
| 			try  | ||||
| 			T* tmp = clone_buffer (*this, capacity, cnt); | ||||
|  | ||||
| 			if (this->buffer)  | ||||
| 			{ | ||||
| 				tmp = new T[capacity]; | ||||
| 				if (cnt > capacity) cnt = capacity; | ||||
| 				for (qse_size_t i = 0; i < cnt; i++)  | ||||
| 				{ | ||||
| 					tmp[i] = this->buffer[i]; | ||||
| 				} | ||||
| 			} | ||||
| 			catch (...)  | ||||
| 			{ | ||||
| 				if (tmp != QSE_NULL) delete[] tmp; | ||||
| 				throw; | ||||
| 				// don't call this->clear (true) here. clear items only. | ||||
| 				// the memory pool may destory the cloned buffer as well. | ||||
| 				this->clear_all_items (); | ||||
|  | ||||
| 				// deallocate the current buffer; | ||||
| 				::operator delete (this->buffer, &this->mp); | ||||
| 				this->capacity = 0; | ||||
| 				this->buffer = QSE_NULL; | ||||
| 			} | ||||
|  | ||||
| 			if (this->buffer != QSE_NULL)  | ||||
| 				delete[] this->buffer; | ||||
| 			this->buffer = tmp; | ||||
| 			this->capacity = capacity; | ||||
| 			this->count = cnt; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void trimToSize () | ||||
| 	{ | ||||
| 		this->setCapacity (this->size); | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	qse_size_t indexOf (const T& value) const | ||||
| 	qse_size_t findFirstIndex (const T& value) const | ||||
| 	{ | ||||
| 		for (qse_size_t i = 0; i < this->count; i++)  | ||||
| 		{ | ||||
| 			if (this->buffer[i] == value) return i; | ||||
| 			if (this->is_equal (this->buffer[i], value)) return i; | ||||
| 		} | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
| 	 | ||||
| 	qse_size_t indexOf (const T& value, qse_size_t index) const | ||||
| 	qse_size_t findFirstIndex (const T& value, qse_size_t index) const | ||||
| 	{ | ||||
| 		for (qse_size_t i = index; i < this->count; i++)  | ||||
| 		{ | ||||
| 			if (this->buffer[i] == value) return i; | ||||
| 			if (this->is_equal (this->buffer[i], value)) return i; | ||||
| 		} | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
|  | ||||
| 	qse_size_t findLastIndex (const T& value) const | ||||
| 	{ | ||||
| 		for (qse_size_t i = this->count; i > 0; )  | ||||
| 		{ | ||||
| 			if (this->is_equal (this->buffer[--i], value)) return i; | ||||
| 		} | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
| 	 | ||||
| 	qse_size_t lastIndexOf (const T& value) const | ||||
| 	{ | ||||
| 		for (qse_size_t i = this->count; i > 0; )  | ||||
| 		{ | ||||
| 			if (this->buffer[--i] == value) return i; | ||||
| 		}	 | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
| 	 | ||||
| 	qse_size_t lastIndexOf (const T& value, qse_size_t index) const | ||||
| 	qse_size_t findLastIndex (const T& value, qse_size_t index) const | ||||
| 	{ | ||||
| 		for (qse_size_t i = index + 1; i > 0; )  | ||||
| 		{ | ||||
| 			if (this->buffer[--i] == value) return i; | ||||
| 			if (this->is_equal (this->buffer[--i], value)) return i; | ||||
| 		} | ||||
| 		return INVALID_INDEX; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	 | ||||
| 	void rotate (int dir, qse_size_t n) | ||||
| 	{ | ||||
| 		qse_size_t first, last, cnt, index, nk; | ||||
| 		T c; | ||||
|  | ||||
| 		if (dir == 0) return this->count; | ||||
| 		if ((n %= this->count) == 0) return this->count; | ||||
| 		if (dir == 0) return; | ||||
| 		if ((n %= this->count) == 0) return; | ||||
|  | ||||
| 		if (dir > 0) n = this->count - n; | ||||
| 		first = 0; nk = this->count - n; cnt = 0;  | ||||
| @ -425,30 +488,36 @@ public: | ||||
| 		{ | ||||
| 			last = first + nk; | ||||
| 			index = first; | ||||
| 			c = this->buffer[first]; | ||||
| 			//c = this->buffer[first]; | ||||
| 			this->assigner (c, this->buffer[first], INVALID_INDEX); | ||||
| 			while (1)  | ||||
| 			{ | ||||
| 				cnt++; | ||||
| 				while (index < nk)  | ||||
| 				{ | ||||
| 					this->buffer[index] = this->buffer[index + n]; | ||||
| 					//this->buffer[index] = this->buffer[index + n]; | ||||
| 					this->assigner (this->buffer[index], this->buffer[index + n], index); | ||||
| 					index += n; | ||||
| 				} | ||||
| 				if (index == last) break; | ||||
| 				this->buffer[index] = this->buffer[index - nk]; | ||||
| 				//this->buffer[index] = this->buffer[index - nk]; | ||||
| 				this->assigner (this->buffer[index], this->buffer[index - nk], index); | ||||
| 				index -= nk; | ||||
| 			} | ||||
| 			this->buffer[last] = c; first++; | ||||
| 			//this->buffer[last] = c;  | ||||
| 			this->assigner (this->buffer[last], c, last); | ||||
| 			first++; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	Mpool      mp; | ||||
| 	ASSIGNER   assigner; | ||||
| 	RESIZER    resizer; | ||||
|  | ||||
| 	qse_size_t count; | ||||
| 	qse_size_t capacity; | ||||
| 	T* buffer; | ||||
| 	T*         buffer; | ||||
| }; | ||||
|  | ||||
| ///////////////////////////////// | ||||
|  | ||||
| @ -92,7 +92,7 @@ struct BinaryHeapAssigner | ||||
| 	// The assignment proxy is used to get the value informed of its position | ||||
| 	// within the heap. This default implmentation, however, doesn't utilize | ||||
| 	// the position (index). | ||||
| 	T& operator() (T& v1, const T& v2, xp_size_t index) const | ||||
| 	T& operator() (T& v1, const T& v2, qse_size_t index) const | ||||
| 	{ | ||||
| 		v1 = v2; | ||||
| 		return v1; | ||||
|  | ||||
| @ -220,7 +220,7 @@ public: | ||||
|  | ||||
| 	SelfType& operator= (const SelfType& list) | ||||
| 	{ | ||||
| 		this->clear (); | ||||
| 		this->clear (false); | ||||
|  | ||||
| 		// note that the memory pool itself is not copied. | ||||
|  | ||||
| @ -620,6 +620,7 @@ protected: | ||||
| 	mutable DatumList* datum_list; | ||||
| 	mutable qse_size_t threshold; | ||||
| 	qse_size_t         load_factor; | ||||
|  | ||||
| 	HASHER             hasher; | ||||
| 	EQUALER            equaler; | ||||
| 	RESIZER            resizer; | ||||
|  | ||||
| @ -211,14 +211,16 @@ public: | ||||
| 		this->clear (true); | ||||
| 	} | ||||
|  | ||||
| 	LinkedList (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size) | ||||
| 	LinkedList (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0):  | ||||
| 		Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size) | ||||
| 	{ | ||||
| 		this->node_count = 0; | ||||
| 		this->head_node = QSE_NULL; | ||||
| 		this->tail_node = QSE_NULL; | ||||
| 	} | ||||
|  | ||||
| 	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()) | ||||
| 	{ | ||||
| 		this->node_count = 0; | ||||
| 		this->head_node = QSE_NULL; | ||||
|  | ||||
| @ -324,8 +324,15 @@ public: | ||||
| 		mp (mmgr, QSE_SIZEOF(Node), mpb_size), | ||||
| 		node_count (0) | ||||
| 	{ | ||||
| 		// create a nil object | ||||
| 		this->nil = new(&this->mp) Node(); | ||||
| 	#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||
| 		// create a nil object. note it doesn't go into the memory pool. | ||||
| 		// the nil node allocated inside the memory pool makes implementation | ||||
| 		// of this->clear (true) difficult as disposal of memory pool | ||||
| 		// also deallocates the nil node. | ||||
| 		this->nil = new(this->getMmgr()) Node(); | ||||
| 	#else | ||||
| 		this->nil = &this->xnil; | ||||
| 	#endif | ||||
|  | ||||
| 		// set root to nil | ||||
| 		this->root = this->nil; | ||||
| @ -336,14 +343,20 @@ public: | ||||
| 		mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), | ||||
| 		node_count (0) | ||||
| 	{ | ||||
|  | ||||
| 		// create a nil object | ||||
| 		this->nil = new(&this->mp) Node(); | ||||
| 	#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||
| 		// create a nil object. note it doesn't go into the memory pool. | ||||
| 		// the nil node allocated inside the memory pool makes implementation | ||||
| 		// of this->clear (true) difficult as disposal of memory pool | ||||
| 		// also deallocates the nil node. | ||||
| 		this->nil = new(this->getMmgr()) Node(); | ||||
| 	#else | ||||
| 		this->nil = &this->xnil; | ||||
| 	#endif | ||||
|  | ||||
| 		// set root to nil | ||||
| 		this->root = this->nil; | ||||
|  | ||||
| 		// TODO: do the level-order traversal to minize rebalancing. | ||||
| 		// TODO: do the level-order traversal to minimize rebalancing. | ||||
| 		Iterator it = rbt.getIterator(); | ||||
| 		while (it.isLegit()) | ||||
| 		{ | ||||
| @ -354,15 +367,22 @@ public: | ||||
|  | ||||
| 	~RedBlackTree () | ||||
| 	{ | ||||
| 		this->clear (); | ||||
| 		this->dispose_node (this->nil); | ||||
| 		this->clear (true); | ||||
|  | ||||
| 	#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||
| 		// destroy the nil node. | ||||
| 		this->nil->~Node ();  | ||||
| 		::operator delete (this->nil, this->getMmgr()); | ||||
| 	#else | ||||
| 		// do nothing | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	SelfType& operator= (const SelfType& rbt) | ||||
| 	{ | ||||
| 		this->clear (); | ||||
| 		this->clear (false); | ||||
|  | ||||
| 		// TODO: do the level-order traversal to minize rebalancing. | ||||
| 		// TODO: do the level-order traversal to minimize rebalancing. | ||||
| 		Iterator it = rbt.getIterator(); | ||||
| 		while (it.isLegit()) | ||||
| 		{ | ||||
| @ -946,6 +966,8 @@ public: | ||||
| 		while (this->root->notNil()) this->remove_node (this->root); | ||||
| 		QSE_ASSERT (this->root = this->nil); | ||||
| 		QSE_ASSERT (this->node_count == 0); | ||||
|  | ||||
| 		if (clear_mpool) this->mp.dispose (); | ||||
| 	} | ||||
|  | ||||
| 	Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const | ||||
| @ -963,6 +985,13 @@ protected: | ||||
| 	COMPARATOR comparator; | ||||
|  | ||||
| 	qse_size_t node_count; | ||||
| #if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||
| 	// nothing. let the constructor allocate it to this->nil. | ||||
| #else | ||||
| 	// use a statically declared nil object. | ||||
| 	Node       xnil; | ||||
| #endif | ||||
|  | ||||
| 	Node*      nil; // internal node to present nil | ||||
| 	Node*      root; // root node. | ||||
| }; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user