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() { |