Some ideas to optimize selection serialization and deserialization, may not worth it.
sv.find(tag) by change serialization to following form: [selType] [# mainRange ,] [anchor [v virtualSpace] [- caret [v virtualSpace]]] [, [anchor [v virtualSpace] [- caret [v virtualSpace]]]]
std::from_chars() returns pointer after all digits, it can be used to advance std::string_view sv to next tag or separator character.
serialization can be implemented with local buffer + std::to_chars() (which returns pointer after last written byte), when local buffer does not have enough space to write a SelectionRange, copy local buffer to result string.
number (only non-negative size_t and Sci::Position) can be serialized in more compact form, e.g. with following ULEB128 like encoding:
char *to_string(char *p, size_t value) noexcept {
do {
*p++ = static_cast<char>(0x80 | (value & 0x7f));
value >>= 7;
} while (value);
return p;
}
Putting the main range first may be OK but it adds an extra ','. It went at the end as it's not needed for some uses so could be optional.
Using
from_chars_result::ptrfor advancement is good if it can be done without adding much more code. Its unlikelystring_view::findis expensive in any realistic scenarios.Most of the detail level
SelectionPosition::ToString,SelectionRange::ToStringare going to fit inside the small string optimization limit and avoid allocation. Without some strong problem cases, complicating the code with explicit buffer management isn't worth it.Readable, easily debugged text seems reasonable for the intensity of use of this feature.
to_stringabove should include masking the last byte inside the function as its confusing otherwise. Unless it's relying on low-byte values always being structuring punctuation.The main alternative I've considered is using a single string for the whole history with '\n' between items to make it easy to serialize the whole history to/from files. Either with explicit
<index>:prefixes on lines or many empty lines for multi-change steps. Since its mostly treated as a stack, almost all work occurs just on the end so there wouldn't be much scanning.Here is at least one
SelectionRange, the comma is needed to separate numbers.mainRangeis decoded first and used for both branches insideSelection(std::string_view sv), so it looks good to encode it first.using
sv.find()(memchrlike, should has not performance problem) to separate numbers / ranges looks to me just decode from random position and discard any non-digits, so not strict.All number has prefixed with a tag or separator, the binary result with above
to_stringcan't be saved to external file.Patch without forward lookup, it makes Scintilla.dll smaller.
There's some
sv.front()that may need protection with!sv.empty().The unit tests in
scintilla\test\unit\testSelection.cxxneed updating.Updated test code, removed redundant
res.ptr == sv.data()check inSelection-0629.diff(std::from_chars()returnserrc::invalid_argumentwhen no digit is found) .sv.empty()check formainRangeblock can be omitted since here should be at least one digit afterselTypeormainRange.Last edit: Zufu Liu 2025-07-01
Committed with [b19406].
Related
Commit: [b19406]