diff options
author | Neil <nyamatongwe@gmail.com> | 2024-02-01 12:38:58 +1100 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2024-02-01 12:38:58 +1100 |
commit | fa3f060e142243c7848284f16561d4af9f9ee935 (patch) | |
tree | 55975d3c9f1b13b38686424b4dc2c4daf314a052 /src | |
parent | 252cb0fe25a8cbbce19944033e311203e0fb07dc (diff) | |
download | scintilla-mirror-fa3f060e142243c7848284f16561d4af9f9ee935.tar.gz |
Store undo text in ScrapStack, a single allocation instead of one allocation per
step. This saves about 50% for a long sequence of single byte actions.
Diffstat (limited to 'src')
-rw-r--r-- | src/CellBuffer.cxx | 22 | ||||
-rw-r--r-- | src/UndoHistory.cxx | 72 | ||||
-rw-r--r-- | src/UndoHistory.h | 23 |
3 files changed, 81 insertions, 36 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx index fd6fe55fb..01074d666 100644 --- a/src/CellBuffer.cxx +++ b/src/CellBuffer.cxx @@ -1088,16 +1088,11 @@ int CellBuffer::StartUndo() noexcept { } Action CellBuffer::GetUndoStep() const noexcept { - const UndoAction &actionStep = uh->GetUndoStep(); - Action acta{ actionStep.at, actionStep.mayCoalesce, actionStep.position, nullptr, actionStep.lenData }; - if (actionStep.lenData) { - acta.data = actionStep.data.get(); - } - return acta; + return uh->GetUndoStep(); } void CellBuffer::PerformUndoStep() { - const UndoAction &actionStep = uh->GetUndoStep(); + const Action actionStep = uh->GetUndoStep(); if (changeHistory && uh->BeforeSavePoint()) { changeHistory->StartReversion(); } @@ -1112,7 +1107,7 @@ void CellBuffer::PerformUndoStep() { } BasicDeleteChars(actionStep.position, actionStep.lenData); } else if (actionStep.at == ActionType::remove) { - BasicInsertString(actionStep.position, actionStep.data.get(), actionStep.lenData); + BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); if (changeHistory) { changeHistory->UndoDeleteStep(actionStep.position, actionStep.lenData, uh->AfterDetachPoint()); } @@ -1129,18 +1124,13 @@ int CellBuffer::StartRedo() noexcept { } Action CellBuffer::GetRedoStep() const noexcept { - const UndoAction &actionStep = uh->GetRedoStep(); - Action acta {actionStep.at, actionStep.mayCoalesce, actionStep.position, nullptr, actionStep.lenData}; - if (actionStep.lenData) { - acta.data = actionStep.data.get(); - } - return acta; + return uh->GetRedoStep(); } void CellBuffer::PerformRedoStep() { - const UndoAction &actionStep = uh->GetRedoStep(); + Action actionStep = uh->GetRedoStep(); if (actionStep.at == ActionType::insert) { - BasicInsertString(actionStep.position, actionStep.data.get(), actionStep.lenData); + BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); if (changeHistory) { changeHistory->Insert(actionStep.position, actionStep.lenData, collectingUndo, uh->BeforeSavePoint() && !uh->AfterDetachPoint()); diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx index d667c9b4d..bc1a4d36a 100644 --- a/src/UndoHistory.cxx +++ b/src/UndoHistory.cxx @@ -38,23 +38,50 @@ namespace Scintilla::Internal { UndoAction::UndoAction() noexcept = default; -void UndoAction::Create(ActionType at_, Sci::Position position_, const char *data_, Sci::Position lenData_, bool mayCoalesce_) { +void UndoAction::Create(ActionType at_, Sci::Position position_, Sci::Position lenData_, bool mayCoalesce_) noexcept { position = position_; at = at_; mayCoalesce = mayCoalesce_; lenData = lenData_; - data = nullptr; - if (lenData_) { - data = std::make_unique<char[]>(lenData_); - memcpy(&data[0], data_, lenData_); - } } void UndoAction::Clear() noexcept { - data = nullptr; lenData = 0; } +const char *ScrapStack::Push(const char *text, size_t length) { + if (current < stack.length()) { + stack.resize(current); + } + stack.append(text, length); + current = stack.length(); + return stack.data() + current - length; +} + +void ScrapStack::SetCurrent(size_t position) noexcept { + current = position; +} + +void ScrapStack::MoveForward(size_t length) noexcept { + if ((current + length) <= stack.length()) { + current += length; + } +} + +void ScrapStack::MoveBack(size_t length) noexcept { + if (current >= length) { + current -= length; + } +} + +const char *ScrapStack::CurrentText() const noexcept { + return stack.data() + current; +} + +const char *ScrapStack::TextAt(size_t position) const noexcept { + return stack.data() + position; +} + // The undo history stores a sequence of user operations that represent the user's view of the // commands executed on the text. // Each user operation contains a sequence of text insertion and text deletion actions. @@ -81,10 +108,13 @@ UndoHistory::UndoHistory() { undoSequenceDepth = 0; savePoint = 0; tentativePoint = -1; + scraps = std::make_unique<ScrapStack>(); actions[currentAction].Create(ActionType::start); } +UndoHistory::~UndoHistory() noexcept = default; + void UndoHistory::EnsureUndoRoom() { // Have to test that there is room for 2 more actions in the array // as two actions may be created by the calling function @@ -163,12 +193,12 @@ const char *UndoHistory::AppendAction(ActionType at, Sci::Position position, con currentAction++; } startSequence = oldCurrentAction != currentAction; - const int actionWithData = currentAction; - actions[currentAction].Create(at, position, data, lengthData, mayCoalesce); + const char *dataNew = lengthData ? scraps->Push(data, lengthData) : nullptr; + actions[currentAction].Create(at, position, lengthData, mayCoalesce); currentAction++; actions[currentAction].Create(ActionType::start); maxAction = currentAction; - return actions[actionWithData].data.get(); + return dataNew; } void UndoHistory::BeginUndoAction() { @@ -202,7 +232,7 @@ void UndoHistory::DropUndoSequence() noexcept { undoSequenceDepth = 0; } -void UndoHistory::DeleteUndoHistory() { +void UndoHistory::DeleteUndoHistory() noexcept { for (int i = 1; i < maxAction; i++) actions[i].Clear(); maxAction = 0; @@ -278,11 +308,17 @@ int UndoHistory::StartUndo() noexcept { return currentAction - act; } -const UndoAction &UndoHistory::GetUndoStep() const noexcept { - return actions[currentAction]; +Action UndoHistory::GetUndoStep() const noexcept { + const UndoAction &step = actions[currentAction]; + Action acta {step.at, step.mayCoalesce, step.position, nullptr, step.lenData}; + if (step.lenData) { + acta.data = scraps->CurrentText() - step.lenData; + } + return acta; } void UndoHistory::CompletedUndoStep() noexcept { + scraps->MoveBack(actions[currentAction].lenData); currentAction--; } @@ -303,11 +339,17 @@ int UndoHistory::StartRedo() noexcept { return act - currentAction; } -const UndoAction &UndoHistory::GetRedoStep() const noexcept { - return actions[currentAction]; +Action UndoHistory::GetRedoStep() const noexcept { + const UndoAction &step = actions[currentAction]; + Action acta {step.at, step.mayCoalesce, step.position, nullptr, step.lenData}; + if (step.lenData) { + acta.data = scraps->CurrentText(); + } + return acta; } void UndoHistory::CompletedRedoStep() noexcept { + scraps->MoveForward(actions[currentAction].lenData); currentAction++; } diff --git a/src/UndoHistory.h b/src/UndoHistory.h index 423b50a7f..98df93465 100644 --- a/src/UndoHistory.h +++ b/src/UndoHistory.h @@ -15,14 +15,25 @@ public: ActionType at = ActionType::insert; bool mayCoalesce = false; Sci::Position position = 0; - std::unique_ptr<char[]> data; Sci::Position lenData = 0; UndoAction() noexcept; - void Create(ActionType at_, Sci::Position position_ = 0, const char *data_ = nullptr, Sci::Position lenData_ = 0, bool mayCoalesce_ = true); + void Create(ActionType at_, Sci::Position position_=0, Sci::Position lenData_=0, bool mayCoalesce_=true) noexcept; void Clear() noexcept; }; +class ScrapStack { + std::string stack; + size_t current = 0; +public: + const char *Push(const char *text, size_t length); + void SetCurrent(size_t position) noexcept; + void MoveForward(size_t length) noexcept; + void MoveBack(size_t length) noexcept; + [[nodiscard]] const char *CurrentText() const noexcept; + [[nodiscard]] const char *TextAt(size_t position) const noexcept; +}; + /** * */ @@ -34,18 +45,20 @@ class UndoHistory { int savePoint; int tentativePoint; std::optional<int> detach; + std::unique_ptr<ScrapStack> scraps; void EnsureUndoRoom(); public: UndoHistory(); + ~UndoHistory() noexcept; const char *AppendAction(ActionType at, Sci::Position position, const char *data, Sci::Position lengthData, bool &startSequence, bool mayCoalesce=true); void BeginUndoAction(); void EndUndoAction(); void DropUndoSequence() noexcept; - void DeleteUndoHistory(); + void DeleteUndoHistory() noexcept; /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. @@ -66,11 +79,11 @@ public: /// called that many times. Similarly for redo. bool CanUndo() const noexcept; int StartUndo() noexcept; - const UndoAction &GetUndoStep() const noexcept; + Action GetUndoStep() const noexcept; void CompletedUndoStep() noexcept; bool CanRedo() const noexcept; int StartRedo() noexcept; - const UndoAction &GetRedoStep() const noexcept; + Action GetRedoStep() const noexcept; void CompletedRedoStep() noexcept; }; |