From f07caccbf33acd188cbe4961ece30251102351cc Mon Sep 17 00:00:00 2001 From: Neil Date: Mon, 30 Mar 2026 18:30:55 +1100 Subject: Feature [feature-requests:#1582]. Improve performance of Document::SetStyles. Report changed range for Document::SetStyleFor. --- src/CellBuffer.cxx | 103 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 24 deletions(-) (limited to 'src/CellBuffer.cxx') 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 &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 -- cgit v1.2.3