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 | 	qse_size_t operator() (qse_size_t current) const | ||||||
| 	{ | 	{ | ||||||
|  | 		if (current <= 0) current = 1; | ||||||
|  |  | ||||||
| 		return (current < 5000)?   (current + current): | 		return (current < 5000)?   (current + current): | ||||||
| 		       (current < 50000)?  (current + (current / 2)): | 		       (current < 50000)?  (current + (current / 2)): | ||||||
| 		       (current < 100000)? (current + (current / 4)): | 		       (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 | class Array: public Mmged | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	typedef Array<T,RESIZER> SelfType; | 	typedef Array<T,ASSIGNER,RESIZER> SelfType; | ||||||
|  |  | ||||||
| 	enum  | 	enum  | ||||||
| 	{ | 	{ | ||||||
| @ -59,8 +74,8 @@ public: | |||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	Array (Mmgr* mmgr = QSE_NULL, | 	Array (Mmgr* mmgr = QSE_NULL, | ||||||
| 	            qse_size_t capacity = DEFAULT_CAPACITY,  | 	       qse_size_t capacity = DEFAULT_CAPACITY,  | ||||||
| 	            qse_size_t mpb_size = 0): | 	       qse_size_t mpb_size = 0): | ||||||
| 		Mmged (mmgr), | 		Mmged (mmgr), | ||||||
| 		mp (mmgr, QSE_SIZEOF(T), mpb_size) | 		mp (mmgr, QSE_SIZEOF(T), mpb_size) | ||||||
| 	{ | 	{ | ||||||
| @ -79,82 +94,89 @@ public: | |||||||
| 		this->count  = 0; | 		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->buffer = this->clone_buffer (array, array.capacity, array.count); | ||||||
| 			this->capacity = 0; | 			this->count = array.count; | ||||||
| 			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->capacity = array.capacity; | 			this->capacity = array.capacity; | ||||||
| 			this->grow_factor = array.grow_factor; |  | ||||||
| 			this->count  = array.this->count; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	~Array () | 	~Array () | ||||||
| 	{ | 	{ | ||||||
| 		if (this->buffer) | 		this->clear (true); | ||||||
| 		{ |  | ||||||
| 			for (qse_size_t i = this->count; i > 0; ) |  | ||||||
| 			{ |  | ||||||
| 				--i; |  | ||||||
| 				this->buffer[i].~T (); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			::operator delete (this->buffer, &this->mp); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if 0 |  | ||||||
| 	SelfType& operator= (const SelfType& array) | 	SelfType& operator= (const SelfType& array) | ||||||
| 	{ | 	{ | ||||||
| 		setSize (array.this->count); | 		this->clear (true); | ||||||
| 		for (qse_size_t i = 0; i < array.this->count; i++) { | 		if (array.buffer) | ||||||
| 			this->buffer[i] = array.buffer[i]; | 		{ | ||||||
|  | 			this->buffer = this->clone_buffer (array, array.capacity, array.count); | ||||||
|  | 			this->count = array.count; | ||||||
|  | 			this->capacity = array.capacity; | ||||||
| 		} | 		} | ||||||
| 		return *this; | 		return *this; | ||||||
| 	} | 	} | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	/* | protected: | ||||||
| 	Array<T>& operator+= (const T& value) | 	T* clone_buffer (const T* srcbuf, qse_size_t capa, qse_size_t count) | ||||||
| 	{ | 	{ | ||||||
| 		addDatum (value); | 		QSE_ASSERT (capa > 0); | ||||||
| 		return *this; | 		QSE_ASSERT (count <= capa); | ||||||
| 	} |  | ||||||
| 	Array<T>& operator+ (const T& value) const |  | ||||||
| 	{ |  | ||||||
| 		Array<T> array (*this); |  | ||||||
| 		array.addDatum (value); |  | ||||||
| 		return array; |  | ||||||
| 	} |  | ||||||
| 	*/ |  | ||||||
|  |  | ||||||
|  | 		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 | 	bool isEmpty () const | ||||||
| 	{ | 	{ | ||||||
| 		return this->count == 0; | 		return this->count == 0; | ||||||
| @ -190,6 +212,19 @@ public: | |||||||
| 		return this->buffer; | 		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) | 	T& operator[] (qse_size_t index) | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (index < this->count); | 		QSE_ASSERT (index < this->count); | ||||||
| @ -217,23 +252,15 @@ public: | |||||||
| 	void set (qse_size_t index, const T& value) | 	void set (qse_size_t index, const T& value) | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (index < this->count); | 		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) | 	qse_size_t insert (qse_size_t index, const T& value) | ||||||
| 	{ | 	{ | ||||||
| 		if (index >= this->capacity)  | 		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); | 			qse_size_t new_capa = this->resizer (this->capacity); | ||||||
|  |  | ||||||
| 			if (index < new_capa) | 			if (index < new_capa) | ||||||
| @ -243,18 +270,33 @@ public: | |||||||
| 		} | 		} | ||||||
| 		else if (this->count >= this->capacity)  | 		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); | 			qse_size_t new_capa = this->resizer (this->capacity); | ||||||
| 			this->setCapacity (new_capa); | 			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]; | 			// shift the existing elements to the back by one slot. | ||||||
| 			this->set_item (i, this->buffer[i - 1]); | 			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->buffer[index] = value; | ||||||
| 		this->set_item (index, value); | 		this->put_item (index, value); | ||||||
| 		if (index > this->count) this->count = index + 1; | 		if (index > this->count) this->count = index + 1; | ||||||
| 		else this->count++; | 		else this->count++; | ||||||
|  |  | ||||||
| @ -273,150 +315,171 @@ public: | |||||||
|  |  | ||||||
| 		qse_size_t j = from_index; | 		qse_size_t j = from_index; | ||||||
| 		qse_size_t i = to_index + 1; | 		qse_size_t i = to_index + 1; | ||||||
|  |  | ||||||
|  | 		// replace deleted elements by surviving elements at the back | ||||||
| 		while (i < this->count)  | 		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; | 		this->count -= to_index - from_index + 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if 0 | protected: | ||||||
| 	qse_size_t addDatum (const T& value) | 	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(); | 		this->clear_all_items (); | ||||||
| 		while (i < this->count)  |  | ||||||
|  | 		if (clear_mpool)  | ||||||
| 		{ | 		{ | ||||||
| 			if (value == this->buffer[i])  | 			if (this->buffer) | ||||||
| 			{ | 			{ | ||||||
| 				remove (i); | 				// the buffer has been allocated using the memory pool. | ||||||
| 				break; | 				// 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) | 	void setSize (qse_size_t size) | ||||||
| 	{ | 	{ | ||||||
| 		if (size > this->capacity) this->setCapacity (size); | 		if (size < this->count) | ||||||
| 		QSE_ASSERT (size <= this->capacity); | 		{ | ||||||
| 		this->count = size; | 			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) | 	void setCapacity (qse_size_t capacity) | ||||||
| 	{ | 	{ | ||||||
| 		if (capacity <= 0)  | 		if (capacity <= 0)  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->buffer != QSE_NULL)  | 			this->clear (true); | ||||||
| 				delete[] this->buffer; |  | ||||||
| 			this->buffer = QSE_NULL; |  | ||||||
| 			this->capacity = 0; |  | ||||||
| 			this->count  = 0; |  | ||||||
| 		} | 		} | ||||||
| 		else  | 		else  | ||||||
| 		{ | 		{ | ||||||
| 			T* tmp = QSE_NULL; | 			 | ||||||
| 			qse_size_t cnt = this->count; | 			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]; | 				// don't call this->clear (true) here. clear items only. | ||||||
| 				if (cnt > capacity) cnt = capacity; | 				// the memory pool may destory the cloned buffer as well. | ||||||
| 				for (qse_size_t i = 0; i < cnt; i++)  | 				this->clear_all_items (); | ||||||
| 				{ |  | ||||||
| 					tmp[i] = this->buffer[i]; | 				// deallocate the current buffer; | ||||||
| 				} | 				::operator delete (this->buffer, &this->mp); | ||||||
| 			} | 				this->capacity = 0; | ||||||
| 			catch (...)  | 				this->buffer = QSE_NULL; | ||||||
| 			{ |  | ||||||
| 				if (tmp != QSE_NULL) delete[] tmp; |  | ||||||
| 				throw; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (this->buffer != QSE_NULL)  |  | ||||||
| 				delete[] this->buffer; |  | ||||||
| 			this->buffer = tmp; | 			this->buffer = tmp; | ||||||
| 			this->capacity = capacity; | 			this->capacity = capacity; | ||||||
| 			this->count = cnt; | 			this->count = cnt; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void trimToSize () | ||||||
|  | 	{ | ||||||
|  | 		this->setCapacity (this->size); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| #if 0 | #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++)  | 		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; | 		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++)  | 		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; | 		return INVALID_INDEX; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	qse_size_t lastIndexOf (const T& value) const | 	qse_size_t findLastIndex (const T& value) const | ||||||
| 	{ | 	{ | ||||||
| 		for (qse_size_t i = this->count; i > 0; )  | 		for (qse_size_t i = this->count; i > 0; )  | ||||||
| 		{ | 		{ | ||||||
| 			if (this->buffer[--i] == value) return i; | 			if (this->is_equal (this->buffer[--i], value)) return i; | ||||||
| 		} | 		} | ||||||
| 		return INVALID_INDEX; | 		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; )  | 		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; | 		return INVALID_INDEX; | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	 | ||||||
| 	void rotate (int dir, qse_size_t n) | 	void rotate (int dir, qse_size_t n) | ||||||
| 	{ | 	{ | ||||||
| 		qse_size_t first, last, cnt, index, nk; | 		qse_size_t first, last, cnt, index, nk; | ||||||
| 		T c; | 		T c; | ||||||
|  |  | ||||||
| 		if (dir == 0) return this->count; | 		if (dir == 0) return; | ||||||
| 		if ((n %= this->count) == 0) return this->count; | 		if ((n %= this->count) == 0) return; | ||||||
|  |  | ||||||
| 		if (dir > 0) n = this->count - n; | 		if (dir > 0) n = this->count - n; | ||||||
| 		first = 0; nk = this->count - n; cnt = 0;  | 		first = 0; nk = this->count - n; cnt = 0;  | ||||||
| @ -425,30 +488,36 @@ public: | |||||||
| 		{ | 		{ | ||||||
| 			last = first + nk; | 			last = first + nk; | ||||||
| 			index = first; | 			index = first; | ||||||
| 			c = this->buffer[first]; | 			//c = this->buffer[first]; | ||||||
|  | 			this->assigner (c, this->buffer[first], INVALID_INDEX); | ||||||
| 			while (1)  | 			while (1)  | ||||||
| 			{ | 			{ | ||||||
| 				cnt++; | 				cnt++; | ||||||
| 				while (index < nk)  | 				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; | 					index += n; | ||||||
| 				} | 				} | ||||||
| 				if (index == last) break; | 				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; | 				index -= nk; | ||||||
| 			} | 			} | ||||||
| 			this->buffer[last] = c; first++; | 			//this->buffer[last] = c;  | ||||||
|  | 			this->assigner (this->buffer[last], c, last); | ||||||
|  | 			first++; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	Mpool      mp; | 	Mpool      mp; | ||||||
|  | 	ASSIGNER   assigner; | ||||||
| 	RESIZER    resizer; | 	RESIZER    resizer; | ||||||
|  |  | ||||||
| 	qse_size_t count; | 	qse_size_t count; | ||||||
| 	qse_size_t capacity; | 	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 | 	// The assignment proxy is used to get the value informed of its position | ||||||
| 	// within the heap. This default implmentation, however, doesn't utilize | 	// within the heap. This default implmentation, however, doesn't utilize | ||||||
| 	// the position (index). | 	// 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; | 		v1 = v2; | ||||||
| 		return v1; | 		return v1; | ||||||
|  | |||||||
| @ -220,7 +220,7 @@ public: | |||||||
|  |  | ||||||
| 	SelfType& operator= (const SelfType& list) | 	SelfType& operator= (const SelfType& list) | ||||||
| 	{ | 	{ | ||||||
| 		this->clear (); | 		this->clear (false); | ||||||
|  |  | ||||||
| 		// note that the memory pool itself is not copied. | 		// note that the memory pool itself is not copied. | ||||||
|  |  | ||||||
| @ -620,6 +620,7 @@ protected: | |||||||
| 	mutable DatumList* datum_list; | 	mutable DatumList* datum_list; | ||||||
| 	mutable qse_size_t threshold; | 	mutable qse_size_t threshold; | ||||||
| 	qse_size_t         load_factor; | 	qse_size_t         load_factor; | ||||||
|  |  | ||||||
| 	HASHER             hasher; | 	HASHER             hasher; | ||||||
| 	EQUALER            equaler; | 	EQUALER            equaler; | ||||||
| 	RESIZER            resizer; | 	RESIZER            resizer; | ||||||
|  | |||||||
| @ -211,14 +211,16 @@ public: | |||||||
| 		this->clear (true); | 		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->node_count = 0; | ||||||
| 		this->head_node = QSE_NULL; | 		this->head_node = QSE_NULL; | ||||||
| 		this->tail_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->node_count = 0; | ||||||
| 		this->head_node = QSE_NULL; | 		this->head_node = QSE_NULL; | ||||||
|  | |||||||
| @ -324,8 +324,15 @@ public: | |||||||
| 		mp (mmgr, QSE_SIZEOF(Node), mpb_size), | 		mp (mmgr, QSE_SIZEOF(Node), mpb_size), | ||||||
| 		node_count (0) | 		node_count (0) | ||||||
| 	{ | 	{ | ||||||
| 		// create a nil object | 	#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||||
| 		this->nil = new(&this->mp) Node(); | 		// 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 | 		// set root to nil | ||||||
| 		this->root = this->nil; | 		this->root = this->nil; | ||||||
| @ -336,14 +343,20 @@ public: | |||||||
| 		mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), | 		mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), | ||||||
| 		node_count (0) | 		node_count (0) | ||||||
| 	{ | 	{ | ||||||
|  | 	#if defined(QSE_REDBLACKTREE_ALLOCATE_NIL) | ||||||
| 		// create a nil object | 		// create a nil object. note it doesn't go into the memory pool. | ||||||
| 		this->nil = new(&this->mp) Node(); | 		// 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 | 		// set root to nil | ||||||
| 		this->root = this->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(); | 		Iterator it = rbt.getIterator(); | ||||||
| 		while (it.isLegit()) | 		while (it.isLegit()) | ||||||
| 		{ | 		{ | ||||||
| @ -354,15 +367,22 @@ public: | |||||||
|  |  | ||||||
| 	~RedBlackTree () | 	~RedBlackTree () | ||||||
| 	{ | 	{ | ||||||
| 		this->clear (); | 		this->clear (true); | ||||||
| 		this->dispose_node (this->nil); |  | ||||||
|  | 	#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) | 	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(); | 		Iterator it = rbt.getIterator(); | ||||||
| 		while (it.isLegit()) | 		while (it.isLegit()) | ||||||
| 		{ | 		{ | ||||||
| @ -946,6 +966,8 @@ public: | |||||||
| 		while (this->root->notNil()) this->remove_node (this->root); | 		while (this->root->notNil()) this->remove_node (this->root); | ||||||
| 		QSE_ASSERT (this->root = this->nil); | 		QSE_ASSERT (this->root = this->nil); | ||||||
| 		QSE_ASSERT (this->node_count == 0); | 		QSE_ASSERT (this->node_count == 0); | ||||||
|  |  | ||||||
|  | 		if (clear_mpool) this->mp.dispose (); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const | 	Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const | ||||||
| @ -963,6 +985,13 @@ protected: | |||||||
| 	COMPARATOR comparator; | 	COMPARATOR comparator; | ||||||
|  |  | ||||||
| 	qse_size_t node_count; | 	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*      nil; // internal node to present nil | ||||||
| 	Node*      root; // root node. | 	Node*      root; // root node. | ||||||
| }; | }; | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user