aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/CellBuffer.cxx
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 /src/CellBuffer.cxx
parenta00464fbff54f486efa3ee103948e3526548fc46 (diff)
downloadscintilla-mirror-f07caccbf33acd188cbe4961ece30251102351cc.tar.gz
Feature [feature-requests:#1582]. Improve performance of Document::SetStyles.
Report changed range for Document::SetStyleFor.
Diffstat (limited to 'src/CellBuffer.cxx')
-rw-r--r--src/CellBuffer.cxx103
1 files changed, 79 insertions, 24 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