aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2026-03-30 18:30:55 +1100
committerNeil <nyamatongwe@gmail.com>2026-03-30 18:30:55 +1100
commitf07caccbf33acd188cbe4961ece30251102351cc (patch)
tree9a7b573d41923b77229e28386164d05e9d710fff
parenta00464fbff54f486efa3ee103948e3526548fc46 (diff)
downloadscintilla-mirror-f07caccbf33acd188cbe4961ece30251102351cc.tar.gz
Feature [feature-requests:#1582]. Improve performance of Document::SetStyles.
Report changed range for Document::SetStyleFor.
-rw-r--r--src/CellBuffer.cxx103
-rw-r--r--src/CellBuffer.h24
-rw-r--r--src/Document.cxx25
3 files changed, 107 insertions, 45 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 3e9deb934..3d4050633 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -439,35 +439,90 @@ const char *CellBuffer::InsertString(Sci::Position position, const char *s, Sci:
return data;
}
-bool CellBuffer::SetStyleAt(Sci::Position position, char styleValue) noexcept {
- if (!hasStyles) {
- return false;
- }
- const char curVal = style.ValueAt(position);
- if (curVal != styleValue) {
- style.SetValueAt(position, styleValue);
- return true;
- } else {
- return false;
+namespace {
+
+ChangedRange CopyBytes(char *p, const char *styles, Sci::Position length, Sci::Position offset) noexcept {
+ for (Sci::Position start = 0; start < length; start++) {
+ if (p[start] != styles[start]) {
+ for (Sci::Position end = length - 1; end >= 0; end--) {
+ if (p[end] != styles[end]) {
+ memcpy(p+start, styles+start, end-start+1);
+ return { start + offset, end + offset };
+ }
+ }
+ }
}
+ return {};
}
-bool CellBuffer::SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept {
- if (!hasStyles) {
- return false;
- }
- bool changed = false;
- PLATFORM_ASSERT(lengthStyle == 0 ||
- (lengthStyle > 0 && lengthStyle + position <= style.Length()));
- while (lengthStyle--) {
- const char curVal = style.ValueAt(position);
- if (curVal != styleValue) {
- style.SetValueAt(position, styleValue);
- changed = true;
+ChangedRange SetBytes(char *p, char style, Sci::Position length, Sci::Position offset) noexcept {
+ for (Sci::Position start = 0; start < length; start++) {
+ if (p[start] != style) {
+ for (Sci::Position end = length - 1; end >= 0; end--) {
+ if (p[end] != style) {
+ memset(p+start, style, end-start+1);
+ return { start + offset, end + offset };
+ }
+ }
}
- position++;
}
- return changed;
+ return {};
+}
+
+struct Lengths {
+ Sci::Position length1;
+ Sci::Position length2;
+};
+
+Lengths SplitUpdate(const SplitVector<char> &style, Sci::Position position, Sci::Position length) noexcept {
+ length = std::min(length, style.Length() - position);
+
+ // Divide length into two parts if it overlaps the gap
+ const Sci::Position part1Length = style.GapPosition();
+
+ // If all after gap then place in length1 to avoid second call
+ if (position >= part1Length) {
+ return { length, 0 };
+ }
+ // If all before gap then place in length1
+ const Sci::Position beforeGap = part1Length - position;
+ if (length <= beforeGap) {
+ return { length, 0 };
+ }
+ // Some before gap and some after gap so put portion in length1 and rest in length2
+ return { beforeGap, length - beforeGap };
+}
+
+}
+
+ChangedRange CellBuffer::SetStyles(Sci::Position position, const char *styles, Sci::Position length) noexcept {
+ if (!hasStyles || (position < 0) || (length <= 0)) {
+ return {};
+ }
+
+ const Lengths lengths = SplitUpdate(style, position, length);
+ ChangedRange cr = CopyBytes(&style[position], styles, lengths.length1, position);
+ if (lengths.length2) {
+ const ChangedRange cr2 = CopyBytes(&style[position + lengths.length1], styles + lengths.length1,
+ lengths.length2, position + lengths.length1);
+ cr.Merge(cr2);
+ }
+ return cr;
+}
+
+ChangedRange CellBuffer::SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept {
+ if (!hasStyles || (position < 0) || (lengthStyle <= 0)) {
+ return {};
+ }
+
+ const Lengths lengths = SplitUpdate(style, position, lengthStyle);
+ ChangedRange cr = SetBytes(&style[position], styleValue, lengths.length1, position);
+ if (lengths.length2) {
+ const ChangedRange cr2 = SetBytes(&style[position + lengths.length1], styleValue,
+ lengths.length2, position + lengths.length1);
+ cr.Merge(cr2);
+ }
+ return cr;
}
// The char* returned is to an allocation owned by the undo history
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 1b035597a..e48eded4d 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -66,6 +66,24 @@ struct SplitView {
}
};
+struct ChangedRange {
+ Sci::Position start = Sci::invalidPosition;
+ Sci::Position end = Sci::invalidPosition;
+ ChangedRange() noexcept = default;
+ ChangedRange(Sci::Position start_, Sci::Position end_) noexcept : start(start_), end(end_) {}
+ [[nodiscard]] bool Empty() const noexcept {
+ return start < 0;
+ }
+ void Merge(const ChangedRange &cr2) noexcept {
+ if (cr2.start >= 0) {
+ if (start < 0) {
+ *this = cr2;
+ } else {
+ end = cr2.end;
+ }
+ }
+ }
+};
/**
* Holder for an expandable array of characters that supports undo and line markers.
@@ -141,9 +159,9 @@ public:
const char *InsertString(Sci::Position position, const char *s, Sci::Position insertLength, bool &startSequence);
/// Setting styles for positions outside the range of the buffer is safe and has no effect.
- /// @return true if the style of a character is changed.
- bool SetStyleAt(Sci::Position position, char styleValue) noexcept;
- bool SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept;
+ /// @return range where style of characters changed.
+ ChangedRange SetStyles(Sci::Position position, const char *styles, Sci::Position length) noexcept;
+ ChangedRange SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept;
const char *DeleteChars(Sci::Position position, Sci::Position deleteLength, bool &startSequence);
diff --git a/src/Document.cxx b/src/Document.cxx
index ab4da0179..d4754233e 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -2571,10 +2571,10 @@ bool SCI_METHOD Document::SetStyleFor(Sci_Position length, char style) {
return false;
}
enteredStyling++;
- const Sci::Position prevEndStyled = endStyled;
- if (cb.SetStyleFor(endStyled, length, style)) {
+ const ChangedRange cr = cb.SetStyleFor(endStyled, length, style);
+ if (!cr.Empty()) {
const DocModification mh(ModificationFlags::ChangeStyle | ModificationFlags::User,
- prevEndStyled, length);
+ cr.start, cr.end - cr.start + 1);
NotifyModified(mh);
}
endStyled += length;
@@ -2587,22 +2587,11 @@ bool SCI_METHOD Document::SetStyles(Sci_Position length, const char *styles) {
return false;
}
enteredStyling++;
- bool didChange = false;
- Sci::Position startMod = 0;
- Sci::Position endMod = 0;
- for (int iPos = 0; iPos < length; iPos++, endStyled++) {
- PLATFORM_ASSERT(endStyled < Length());
- if (cb.SetStyleAt(endStyled, styles[iPos])) {
- if (!didChange) {
- startMod = endStyled;
- }
- didChange = true;
- endMod = endStyled;
- }
- }
- if (didChange) {
+ const ChangedRange cr = cb.SetStyles(endStyled, styles, length);
+ endStyled += length;
+ if (!cr.Empty()) {
const DocModification mh(ModificationFlags::ChangeStyle | ModificationFlags::User,
- startMod, endMod - startMod + 1);
+ cr.start, cr.end - cr.start + 1);
NotifyModified(mh);
}
enteredStyling--;