diff options
| -rw-r--r-- | lexers/LexCPP.cxx | 8 | ||||
| -rw-r--r-- | lexlib/SparseState.h | 32 | ||||
| -rw-r--r-- | test/unit/testSparseState.cxx | 101 | 
3 files changed, 136 insertions, 5 deletions
| diff --git a/lexers/LexCPP.cxx b/lexers/LexCPP.cxx index 92248f7f0..2e5fdd0d1 100644 --- a/lexers/LexCPP.cxx +++ b/lexers/LexCPP.cxx @@ -506,7 +506,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,  	const int maskActivity = 0x3F;  	std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1); -	bool changedRawStringState = rawStringTerminators.Delete(lineCurrent); +	SparseState<std::string> rawSTNew(lineCurrent);  	int activitySet = preproc.IsInactive() ? 0x40 : 0; @@ -540,8 +540,7 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,  			lineCurrent++;  			vlls.Add(lineCurrent, preproc);  			if (rawStringTerminator != "") { -				rawStringTerminators.Set(lineCurrent-1, rawStringTerminator); -				changedRawStringState = true; +				rawSTNew.Set(lineCurrent-1, rawStringTerminator);  			}  		} @@ -893,7 +892,8 @@ void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle,  		}  		continuationLine = false;  	} -	if (definitionsChanged || changedRawStringState) +	const bool rawStringsChanged = rawStringTerminators.Merge(rawSTNew, lineCurrent); +	if (definitionsChanged || rawStringsChanged)  		styler.ChangeLexerState(startPos, startPos + length);  	sc.Complete();  } diff --git a/lexlib/SparseState.h b/lexlib/SparseState.h index c84fdc861..bd74ecef2 100644 --- a/lexlib/SparseState.h +++ b/lexlib/SparseState.h @@ -28,6 +28,7 @@ class SparseState {  			return (position == other.position) && (value == other.value);  		}  	}; +	int positionFirst;  	typedef std::vector<State> stateVector;  	stateVector states; @@ -37,6 +38,9 @@ class SparseState {  	}  public: +	SparseState(int positionFirst_=-1) { +		positionFirst = positionFirst_; +	}  	void Set(int position, T value) {  		Delete(position);  		if ((states.size() == 0) || (value != states[states.size()-1].value)) { @@ -69,6 +73,34 @@ public:  	size_t size() const {  		return states.size();  	} + +	// Returns true if Merge caused a significant change +	bool Merge(const SparseState<T> &other, int ignoreAfter) { +		// Changes caused beyond ignoreAfter are not significant +		Delete(ignoreAfter+1); + +		bool different = true; +		bool changed = false; +		typename stateVector::iterator low = Find(other.positionFirst); +		if (static_cast<size_t>(states.end() - low) == other.states.size()) { +			// Same number in other as after positionFirst in this +			different = !std::equal(low, states.end(), other.states.begin()); +		} +		if (different) { +			if (low != states.end()) { +				states.erase(low, states.end()); +				changed = true; +			} +			typename stateVector::const_iterator startOther = other.states.begin(); +			if (!states.empty() && states.back().value == startOther->value) +				startOther++; +			if (startOther != other.states.end()) { +				states.insert(states.end(), startOther, other.states.end()); +				changed = true; +			} +		} +		return changed; +	}  };  #ifdef SCI_NAMESPACE diff --git a/test/unit/testSparseState.cxx b/test/unit/testSparseState.cxx index 74f1032b2..a30240d62 100644 --- a/test/unit/testSparseState.cxx +++ b/test/unit/testSparseState.cxx @@ -95,13 +95,112 @@ TEST_F(SparseStateTest, ReplaceLast) {  	EXPECT_EQ(32, pss->ValueAt(3));  } -TEST_F(SparseStateTest, CheckOnlyChangeAppended) { +TEST_F(SparseStateTest, OnlyChangeAppended) {  	pss->Set(0, 30);  	pss->Set(2, 31);  	pss->Set(3, 31);  	EXPECT_EQ(2u, pss->size());  } +TEST_F(SparseStateTest, MergeBetween) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); +	EXPECT_EQ(3u, pss->size()); + +	SparseState<int> ssAdditions(3); +	ssAdditions.Set(4, 34); +	EXPECT_EQ(1u, ssAdditions.size()); +	bool mergeChanged = pss->Merge(ssAdditions,5); +	EXPECT_EQ(0, mergeChanged); + +	ssAdditions.Set(4, 44); +	EXPECT_EQ(1u, ssAdditions.size()); +	mergeChanged = pss->Merge(ssAdditions,5); +	EXPECT_EQ(true, mergeChanged); +	EXPECT_EQ(3u, pss->size()); +	EXPECT_EQ(44, pss->ValueAt(4)); +} + +TEST_F(SparseStateTest, MergeAtExisting) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); +	EXPECT_EQ(3u, pss->size()); + +	SparseState<int> ssAdditions(4); +	ssAdditions.Set(4, 34); +	EXPECT_EQ(1u, ssAdditions.size()); +	bool mergeChanged = pss->Merge(ssAdditions,5); +	EXPECT_EQ(0, mergeChanged); + +	ssAdditions.Set(4, 44); +	EXPECT_EQ(1u, ssAdditions.size()); +	mergeChanged = pss->Merge(ssAdditions,5); +	EXPECT_EQ(true, mergeChanged); +	EXPECT_EQ(3u, pss->size()); +	EXPECT_EQ(44, pss->ValueAt(4)); +} + +TEST_F(SparseStateTest, MergeWhichRemoves) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); +	EXPECT_EQ(3u, pss->size()); + +	SparseState<int> ssAdditions(2); +	ssAdditions.Set(2, 22); +	EXPECT_EQ(1u, ssAdditions.size()); +	EXPECT_EQ(22, ssAdditions.ValueAt(2)); +	bool mergeChanged = pss->Merge(ssAdditions,5); +	EXPECT_EQ(true, mergeChanged); +	EXPECT_EQ(2u, pss->size()); +	EXPECT_EQ(22, pss->ValueAt(2)); +} + +TEST_F(SparseStateTest, MergeIgnoreSome) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); + +	SparseState<int> ssAdditions(2); +	ssAdditions.Set(2, 32); +	bool mergeChanged = pss->Merge(ssAdditions,3); + +	EXPECT_EQ(0, mergeChanged); +	EXPECT_EQ(2u, pss->size()); +	EXPECT_EQ(32, pss->ValueAt(2)); +} + +TEST_F(SparseStateTest, MergeIgnoreSomeStart) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); + +	SparseState<int> ssAdditions(2); +	ssAdditions.Set(2, 32); +	bool mergeChanged = pss->Merge(ssAdditions,2); + +	EXPECT_EQ(0, mergeChanged); +	EXPECT_EQ(2u, pss->size()); +	EXPECT_EQ(32, pss->ValueAt(2)); +} + +TEST_F(SparseStateTest, MergeIgnoreRepeat) { +	pss->Set(0, 30); +	pss->Set(2, 32); +	pss->Set(4, 34); + +	SparseState<int> ssAdditions(5); +	// Appending same value as at end of pss. +	ssAdditions.Set(5, 34); +	bool mergeChanged = pss->Merge(ssAdditions,6); + +	EXPECT_EQ(0, mergeChanged); +	EXPECT_EQ(3u, pss->size()); +	EXPECT_EQ(34, pss->ValueAt(4)); +} +  class SparseStateStringTest : public ::testing::Test {  protected:  	virtual void SetUp() { | 
