diff options
| -rw-r--r-- | src/ContractionState.cxx | 1 | ||||
| -rw-r--r-- | src/RunStyles.cxx | 1 | ||||
| -rw-r--r-- | src/SparseVector.h | 5 | ||||
| -rw-r--r-- | src/SplitVector.h | 147 | ||||
| -rw-r--r-- | test/unit/testContractionState.cxx | 1 | ||||
| -rw-r--r-- | test/unit/testPartitioning.cxx | 1 | ||||
| -rw-r--r-- | test/unit/testRunStyles.cxx | 1 | ||||
| -rw-r--r-- | test/unit/testSparseVector.cxx | 9 | ||||
| -rw-r--r-- | test/unit/testSplitVector.cxx | 13 | 
9 files changed, 116 insertions, 63 deletions
diff --git a/src/ContractionState.cxx b/src/ContractionState.cxx index 60042bf88..6fca2ec4e 100644 --- a/src/ContractionState.cxx +++ b/src/ContractionState.cxx @@ -10,6 +10,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> diff --git a/src/RunStyles.cxx b/src/RunStyles.cxx index 38a6ba799..b0a9c1fac 100644 --- a/src/RunStyles.cxx +++ b/src/RunStyles.cxx @@ -11,6 +11,7 @@  #include <cstdarg>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> diff --git a/src/SparseVector.h b/src/SparseVector.h index 39324bdc1..ce38d0da1 100644 --- a/src/SparseVector.h +++ b/src/SparseVector.h @@ -163,7 +163,8 @@ template<>  inline void SparseVector<const char *>::ClearValue(int partition) {  	const char *value = values->ValueAt(partition);  	delete []value; -	values->SetValueAt(partition, NULL); +	value = nullptr; +	values->SetValueAt(partition, value);  }  template<> @@ -175,7 +176,7 @@ inline void SparseVector<const char *>::SetValueAt(int position, const char *val  		std::copy(value, value + len, valueCopy);  		CommonSetValueAt(position, valueCopy);  	} else { -		CommonSetValueAt(position, NULL); +		CommonSetValueAt(position, nullptr);  	}  } diff --git a/src/SplitVector.h b/src/SplitVector.h index e6a7701bb..6b839b24b 100644 --- a/src/SplitVector.h +++ b/src/SplitVector.h @@ -16,11 +16,11 @@ namespace Scintilla {  template <typename T>  class SplitVector {  protected: -	T *body; -	int size; +	std::vector<T> body; +	T empty;	/// Returned as the result of out-of-bounds access.  	int lengthBody;  	int part1Length; -	int gapLength;	/// invariant: gapLength == size - lengthBody +	int gapLength;	/// invariant: gapLength == body.size() - lengthBody  	int growSize;  	/// Move the gap to a particular position so that insertion and @@ -30,16 +30,16 @@ protected:  		if (position != part1Length) {  			if (position < part1Length) {  				// Moving the gap towards start so moving elements towards end -				std::copy_backward( -					body + position, -					body + part1Length, -					body + gapLength + part1Length); +				std::move_backward( +					body.data() + position, +					body.data() + part1Length, +					body.data() + gapLength + part1Length);  			} else {	// position > part1Length  				// Moving the gap towards end so moving elements towards start -				std::copy( -					body + part1Length + gapLength, -					body + gapLength + position, -					body + part1Length); +				std::move( +					body.data() + part1Length + gapLength, +					body.data() + gapLength + position, +					body.data() + part1Length);  			}  			part1Length = position;  		} @@ -49,16 +49,16 @@ protected:  	/// reallocating if more space needed.  	void RoomFor(int insertionLength) {  		if (gapLength <= insertionLength) { -			while (growSize < size / 6) +			while (growSize < static_cast<int>(body.size() / 6))  				growSize *= 2; -			ReAllocate(size + insertionLength + growSize); +			ReAllocate(static_cast<int>(body.size()) + insertionLength + growSize);  		}  	}  	void Init() { -		body = NULL; +		body.clear(); +		body.shrink_to_fit();  		growSize = 8; -		size = 0;  		lengthBody = 0;  		part1Length = 0;  		gapLength = 0; @@ -66,7 +66,7 @@ protected:  public:  	/// Construct a split buffer. -	SplitVector() { +	SplitVector() : empty() {  		Init();  	} @@ -75,8 +75,6 @@ public:  	void operator=(const SplitVector &) = delete;  	~SplitVector() { -		delete []body; -		body = 0;  	}  	int GetGrowSize() const { @@ -94,61 +92,73 @@ public:  		if (newSize < 0)  			throw std::runtime_error("SplitVector::ReAllocate: negative size."); -		if (newSize > size) { +		if (newSize > static_cast<int>(body.size())) {  			// Move the gap to the end  			GapTo(lengthBody); -			T *newBody = new T[newSize]; -			if ((size != 0) && (body != 0)) { -				std::copy(body, body + lengthBody, newBody); -				delete []body; -			} -			body = newBody; -			gapLength += newSize - size; -			size = newSize; +			gapLength += newSize - static_cast<int>(body.size()); +			// RoomFor implements a growth strategy but so does vector::resize so +			// ensure vector::resize allocates exactly the amount wanted by +			// calling reserve first. +			body.reserve(newSize); +			body.resize(newSize);  		}  	} -	/// Retrieve the character at a particular position. -	/// Retrieving positions outside the range of the buffer returns 0. -	/// The assertions here are disabled since calling code can be -	/// simpler if out of range access works and returns 0. -	T ValueAt(int position) const { +	/// Retrieve the element at a particular position. +	/// Retrieving positions outside the range of the buffer returns empty or 0. +	const T& ValueAt(int position) const {  		if (position < part1Length) { -			//PLATFORM_ASSERT(position >= 0);  			if (position < 0) { -				return 0; +				return empty;  			} else {  				return body[position];  			}  		} else { -			//PLATFORM_ASSERT(position < lengthBody);  			if (position >= lengthBody) { -				return 0; +				return empty;  			} else {  				return body[gapLength + position];  			}  		}  	} -	void SetValueAt(int position, T v) { +	/// Set the element at a particular position. +	/// Setting positions outside the range of the buffer performs no assignment +	/// but asserts in debug builds. +	template <typename ParamType> +	void SetValueAt(int position, ParamType&& v) {  		if (position < part1Length) {  			PLATFORM_ASSERT(position >= 0);  			if (position < 0) {  				;  			} else { -				body[position] = v; +				body[position] = std::move(v);  			}  		} else {  			PLATFORM_ASSERT(position < lengthBody);  			if (position >= lengthBody) {  				;  			} else { -				body[gapLength + position] = v; +				body[gapLength + position] = std::move(v);  			}  		}  	} -	T &operator[](int position) const { +	/// Retrieve the element at a particular position. +	/// The position must be within bounds or an assertion is triggered. +	const T &operator[](int position) const { +		PLATFORM_ASSERT(position >= 0 && position < lengthBody); +		if (position < part1Length) { +			return body[position]; +		} else { +			return body[gapLength + position]; +		} +	} + +	/// Retrieve reference to the element at a particular position. +	/// This, instead of the const variant, can be used to mutate in-place. +	/// The position must be within bounds or an assertion is triggered. +	T &operator[](int position) {  		PLATFORM_ASSERT(position >= 0 && position < lengthBody);  		if (position < part1Length) {  			return body[position]; @@ -171,7 +181,7 @@ public:  		}  		RoomFor(1);  		GapTo(position); -		body[part1Length] = v; +		body[part1Length] = std::move(v);  		lengthBody++;  		part1Length++;  		gapLength--; @@ -187,7 +197,28 @@ public:  			}  			RoomFor(insertLength);  			GapTo(position); -			std::fill(&body[part1Length], &body[part1Length + insertLength], v); +			std::fill(body.data() + part1Length, body.data() + part1Length + insertLength, v); +			lengthBody += insertLength; +			part1Length += insertLength; +			gapLength -= insertLength; +		} +	} + +	/// Add some new empty elements. +	/// InsertValue is good for value objects but not for unique_ptr objects +	/// since they can only be moved from once. +	void InsertEmpty(int position, int insertLength) { +		PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); +		if (insertLength > 0) { +			if ((position < 0) || (position > lengthBody)) { +				return; +			} +			RoomFor(insertLength); +			GapTo(position); +			for (int elem = part1Length; elem < part1Length + insertLength; elem++) { +				T emptyOne = {}; +				body[elem] = std::move(emptyOne); +			}  			lengthBody += insertLength;  			part1Length += insertLength;  			gapLength -= insertLength; @@ -198,7 +229,7 @@ public:  	/// appending zero valued elements if needed.  	void EnsureLength(int wantedLength) {  		if (Length() < wantedLength) { -			InsertValue(Length(), wantedLength - Length(), 0); +			InsertEmpty(Length(), wantedLength - Length());  		}  	} @@ -211,7 +242,7 @@ public:  			}  			RoomFor(insertLength);  			GapTo(positionToInsert); -			std::copy(s + positionFrom, s + positionFrom + insertLength, body + part1Length); +			std::copy(s + positionFrom, s + positionFrom + insertLength, body.data() + part1Length);  			lengthBody += insertLength;  			part1Length += insertLength;  			gapLength -= insertLength; @@ -236,7 +267,8 @@ public:  		}  		if ((position == 0) && (deleteLength == lengthBody)) {  			// Full deallocation returns storage and is faster -			delete []body; +			body.clear(); +			body.shrink_to_fit();  			Init();  		} else if (deleteLength > 0) {  			GapTo(position); @@ -247,10 +279,10 @@ public:  	/// Delete all the buffer contents.  	void DeleteAll() { -		DeleteRange(0, lengthBody); +		DeleteRange(0, static_cast<int>(lengthBody));  	} -	// Retrieve a range of elements into an array +	/// Retrieve a range of elements into an array  	void GetRange(T *buffer, int position, int retrieveLength) const {  		// Split into up to 2 ranges, before and after the split then use memcpy on each.  		int range1Length = 0; @@ -260,34 +292,39 @@ public:  			if (range1Length > part1AfterPosition)  				range1Length = part1AfterPosition;  		} -		std::copy(body + position, body + position + range1Length, buffer); +		std::copy(body.data() + position, body.data() + position + range1Length, buffer);  		buffer += range1Length; -		position = position + range1Length + gapLength; +		position = static_cast<int>(position + range1Length + gapLength);  		int range2Length = retrieveLength - range1Length; -		std::copy(body + position, body + position + range2Length, buffer); +		std::copy(body.data() + position, body.data() + position + range2Length, buffer);  	} +	/// Compact the buffer and return a pointer to the first element.  	T *BufferPointer() {  		RoomFor(1);  		GapTo(lengthBody); -		body[lengthBody] = 0; -		return body; +		T emptyOne = {}; +		body[lengthBody] = std::move(emptyOne); +		return body.data();  	} +	/// Return a pointer to a range of elements, first rearranging the buffer if +	/// needed to make that range contiguous.  	T *RangePointer(int position, int rangeLength) {  		if (position < part1Length) {  			if ((position + rangeLength) > part1Length) {  				// Range overlaps gap, so move gap to start of range.  				GapTo(position); -				return body + position + gapLength; +				return body.data() + position + gapLength;  			} else { -				return body + position; +				return body.data() + position;  			}  		} else { -			return body + position + gapLength; +			return body.data() + position + gapLength;  		}  	} +	/// Return the position of the gap within the buffer.  	int GapPosition() const {  		return part1Length;  	} diff --git a/test/unit/testContractionState.cxx b/test/unit/testContractionState.cxx index 989aa409d..8b401dcb6 100644 --- a/test/unit/testContractionState.cxx +++ b/test/unit/testContractionState.cxx @@ -3,6 +3,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> diff --git a/test/unit/testPartitioning.cxx b/test/unit/testPartitioning.cxx index 008c140d8..925cc9a32 100644 --- a/test/unit/testPartitioning.cxx +++ b/test/unit/testPartitioning.cxx @@ -3,6 +3,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> diff --git a/test/unit/testRunStyles.cxx b/test/unit/testRunStyles.cxx index 72840322c..e33cedb2e 100644 --- a/test/unit/testRunStyles.cxx +++ b/test/unit/testRunStyles.cxx @@ -3,6 +3,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> diff --git a/test/unit/testSparseVector.cxx b/test/unit/testSparseVector.cxx index ad0110ae0..16498397a 100644 --- a/test/unit/testSparseVector.cxx +++ b/test/unit/testSparseVector.cxx @@ -4,6 +4,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> @@ -45,9 +46,9 @@ TEST_CASE("SparseVector") {  	SECTION("InsertSpace") {  		st.InsertSpace(0, 5);  		REQUIRE(1 == st.Elements()); -		REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(0)); -		REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(1)); -		REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(4)); +		REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(0)); +		REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(1)); +		REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(4));  		st.Check();  	} @@ -119,7 +120,7 @@ TEST_CASE("SparseVector") {  		st.SetValueAt(4, "5");  		REQUIRE(2 == st.Elements());  		REQUIRE("----5" == Representation(st)); -		st.SetValueAt(4, NULL); +		st.SetValueAt(4, nullptr);  		REQUIRE(1 == st.Elements());  		REQUIRE("-----" == Representation(st));  		st.Check(); diff --git a/test/unit/testSplitVector.cxx b/test/unit/testSplitVector.cxx index 3af51c45e..e01810d33 100644 --- a/test/unit/testSplitVector.cxx +++ b/test/unit/testSplitVector.cxx @@ -3,6 +3,7 @@  #include <cstring>  #include <stdexcept> +#include <vector>  #include <algorithm>  #include <memory> @@ -280,11 +281,19 @@ TEST_CASE("SplitVector") {  	}  	SECTION("BufferPointer") { +		// Low-level access to the data  		sv.InsertFromArray(0, testArray, 0, lengthTestArray); +		sv.Insert(0, 99);	// This moves the gap so that BufferPointer() must also move +		REQUIRE(1 == sv.GapPosition()); +		const int lengthAfterInsertion = 1 + lengthTestArray; +		REQUIRE(lengthAfterInsertion == (sv.Length()));  		int *retrievePointer = sv.BufferPointer(); -		for (int i=0; i<sv.Length(); i++) { -			REQUIRE((i+3) == retrievePointer[i]); +		for (int i=1; i<sv.Length(); i++) { +			REQUIRE((i+3-1) == retrievePointer[i]);  		} +		REQUIRE(lengthAfterInsertion == sv.Length()); +		// Gap was moved to end. +		REQUIRE(lengthAfterInsertion == sv.GapPosition());  	}  	SECTION("DeleteBackAndForth") {  | 
