From 00b7386cfb8f379671e0d60cb4c61f1541091f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E5=87=8C=E6=B1=90?= Date: Thu, 19 Dec 2024 01:36:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86ActionManager?= =?UTF-8?q?=E7=B1=BB=EF=BC=8C=E7=94=A8=E4=BA=8E=E7=AE=A1=E7=90=86=E6=92=A4?= =?UTF-8?q?=E5=9B=9E=E3=80=81=E9=87=8D=E5=81=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mystl/my_vector.h | 26 +++++++ utils/ActionManager.h | 140 ++++++++++++++++++++++++++++++++++- utils/ActionManager_test.cpp | 23 ++++++ 3 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 utils/ActionManager_test.cpp diff --git a/mystl/my_vector.h b/mystl/my_vector.h index 862a3f4..c5eb386 100644 --- a/mystl/my_vector.h +++ b/mystl/my_vector.h @@ -211,6 +211,24 @@ public: long long operator-(iterator other) const { return ptr - other.ptr; } + + iterator& operator+=(size_t n) { + ptr += n; + return *this; + } + iterator& operator-=(size_t n) { + ptr -= n; + return *this; + } + + friend iterator operator++(iterator& ite) { + ++ite.ptr; + return ite; + } + friend iterator operator--(iterator& ite) { + --ite.ptr; + return ite; + } }; iterator begin() { @@ -224,6 +242,14 @@ public: void erase(iterator target) { erase(target - begin()); } + + void reverse() { + MyVector tmp = *this; + for (size_t i = 0; i < m_size / 2; ++i) { + std::swap(tmp[i], tmp[m_size - i - 1]); + } + *this = tmp; + } }; #endif // MY_VECTOR_H diff --git a/utils/ActionManager.h b/utils/ActionManager.h index 0ebc330..979dc24 100644 --- a/utils/ActionManager.h +++ b/utils/ActionManager.h @@ -1,14 +1,148 @@ #ifndef ACTIONMANAGER_H #define ACTIONMANAGER_H -enum class EditAction { +#include "../mystl/my_stack.h" +#include + +enum class EditActiontype { Initialize, Insert, Delete, }; -class ActionManager { +struct EditAction { + EditActiontype type; + int pos; + std::string content; +}; -} +class ActionManager { +private: + MyStack> undoStack_, redoStack_; + std::string content_; + + MyVector calculateEditActions(const std::string &str1, const std::string &str2) { // 规定Editor只会在删除或者插入时提交,因此只会同时存在一种操作 + int m = str1.length(); + int n = str2.length(); + MyVector> dp(m + 1, MyVector(n + 1)); + + for (int i = 0; i <= m; ++i) { + dp[i][0] = i; + } + for (int j = 0; j <= n; ++j) { + dp[0][j] = j; + } + + for (int i = 1; i <= m; ++i) { + for (int j = 1; j <= n; ++j) { + if (str1[i - 1] == str2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = std::min(dp[i - 1][j], dp[i][j - 1]) + 1; + } + } + } + + // 回溯以找到编辑操作 + MyVector actions; + int i = m, j = n; + while (i > 0 && j > 0) { + if (str1[i - 1] == str2[j - 1]) { + --i; + --j; + } else if (dp[i][j] == dp[i - 1][j] + 1) { + actions.push_back({EditActiontype::Delete, i - 1, std::string(1, str1[i - 1])}); + --i; + } else if (dp[i][j] == dp[i][j - 1] + 1) { + actions.push_back({EditActiontype::Insert, i, std::string(1, str2[j - 1])}); + --j; + } + } + + while (i > 0) { + actions.push_back({EditActiontype::Delete, i - 1, std::string(1, str1[i - 1])}); + --i; + } + + while (j > 0) { + actions.push_back({EditActiontype::Insert, i, std::string(1, str2[j - 1])}); + --j; + } + + actions.reverse(); + + // 考虑到先前进行的插入和删除操作,对随后插入和删除的位置进行修正 + int offset = 0; + for (int i = 0; i < actions.size(); ++i) { + if (actions[i].type == EditActiontype::Insert) { + actions[i].pos += offset; + offset++; + } else if (actions[i].type == EditActiontype::Delete) { + actions[i].pos += offset; + offset--; + } + } + + return actions; + } + + std::string applyEditAction(MyVector &actions, std::string &content) { + std::string newContent = content; + for(int i = 0; i < actions.size(); i++) { + if(actions[i].type == EditActiontype::Insert) { + newContent.insert(actions[i].pos, actions[i].content); + } else if(actions[i].type == EditActiontype::Delete) { + newContent.erase(actions[i].pos, actions[i].content.size()); + } + } + return newContent; + } + +public: + ActionManager() { + } + ActionManager(const std::string &content) { + content_ = content; + } + + void updateContent(const std::string &content) { + redoStack_.clear(); + MyVector actions = calculateEditActions(content_, content); + content_ = content; + undoStack_.push(actions); + } + + void undo() { + if (undoStack_.empty()) { + return; + } + MyVector actions = undoStack_.top(); + undoStack_.pop(); + std::string newContent = applyEditAction(actions, content_); + redoStack_.push(calculateEditActions(content_, newContent)); + content_ = newContent; + } + + void redo() { + if (redoStack_.empty()) { + return; + } + MyVector actions = redoStack_.top(); + redoStack_.pop(); + std::string newContent = applyEditAction(actions, content_); + undoStack_.push(calculateEditActions(content_, newContent)); + content_ = newContent; + } + + void setContent(const std::string &content) { + content_ = content; + undoStack_.clear(); + redoStack_.clear(); + } + + std::string getContent() { + return content_; + } +}; #endif \ No newline at end of file diff --git a/utils/ActionManager_test.cpp b/utils/ActionManager_test.cpp new file mode 100644 index 0000000..9cfbe3f --- /dev/null +++ b/utils/ActionManager_test.cpp @@ -0,0 +1,23 @@ +#include +#include "ActionManager.h" +#include "../mystl/my_vector.h" + +using namespace std; + +int main() { + ActionManager am; + MyVector v; + v = am.calculateEditActions("i can see you, but u dont love me", "i cant hug u, but i love you"); + printf("Actions: %zu\n", v.size()); + //replay test + std::string s1 = "i can see you, but u dont love me"; + for(int i = 0; i < v.size(); i++) { + if(v[i].type == EditActiontype::Insert) { + s1.insert(v[i].pos, v[i].content); + } else if(v[i].type == EditActiontype::Delete) { + s1.erase(v[i].pos, v[i].content.size()); + } + } + printf("%s\n", s1.c_str()); + return 0; +} \ No newline at end of file