diff --git a/version0/crdt/text_document.hpp b/version0/crdt/text_document.hpp index 41e453b..8e9fe5b 100644 --- a/version0/crdt/text_document.hpp +++ b/version0/crdt/text_document.hpp @@ -147,8 +147,13 @@ struct TextDocument { std::vector ops; for (size_t i = first_idx; i < last_idx; i++) { + if (!state.list.at(i).value.has_value()) { + // allready deleted + continue; + } + ops.emplace_back(typename ListType::OpDel{ - state.list[i].id + state.list.at(i).id }); // TODO: do delets get a seq????? @@ -163,7 +168,7 @@ struct TextDocument { // note: rn it only creates 1 diff patch std::vector merge(std::string_view text) { if (text.empty()) { - if (state.list.empty()) { + if (state.list.empty() || state.doc_size == 0) { // no op return {}; } else { @@ -185,6 +190,7 @@ struct TextDocument { // find start and end of changes // start size_t list_start = 0; + size_t list_start_counted = 0; size_t text_start = 0; bool differ = false; for (; list_start < state.list.size() && text_start < text.size();) { @@ -201,6 +207,7 @@ struct TextDocument { list_start++; text_start++; + list_start_counted++; } // doc and text dont differ @@ -214,7 +221,10 @@ struct TextDocument { // +1 so i can have unsigned size_t list_end = state.list.size(); size_t text_end = text.size(); - for (; list_end > 0 && text_end > 0 && list_end >= list_start && text_end >= text_start;) { + //for (; list_end > 0 && text_end > 0 && list_end >= list_start && text_end >= text_start;) { + //while (list_end >= list_start && text_end >= text_start) { + size_t list_end_counted = 0; + while (list_start_counted - list_end_counted > state.doc_size && text_end >= text_start) { // jump over tombstones if (!state.list[list_end-1].value.has_value()) { list_end--; @@ -227,6 +237,7 @@ struct TextDocument { list_end--; text_end--; + list_end_counted++; } //std::cout << "list_end: " << list_end << " text_end: " << text_end << "\n"; @@ -237,7 +248,7 @@ struct TextDocument { if (list_start <= list_end && list_start < state.list.size()) { ops = delRange( state.list[list_start].id, - list_end < state.list.size() ? std::make_optional(state.list[list_end].id) : std::nullopt + (list_start == list_end ? list_end+1 : list_end) < state.list.size() ? std::make_optional(state.list[list_end].id) : std::nullopt ); //std::cout << "deleted: " << ops.size() << "\n"; } diff --git a/version0/test2.cpp b/version0/test2.cpp index db96bb5..68765c9 100644 --- a/version0/test2.cpp +++ b/version0/test2.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // single letter agent, for testing only using Agent = char; @@ -411,6 +412,91 @@ void testBugSame(void) { assert(doc.getText() == new_text2); } +void testBugDoubleDel(void) { + Doc doc; + doc.local_agent = 'A'; + + { + std::string_view new_text{"a"}; + doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{""}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + assert(ops.size() == 1); + assert(std::holds_alternative(ops.front())); + assert(std::get(ops.front()).id.seq == 0); + } + + { + std::string_view new_text{""}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + assert(ops.size() == 0); + } +} + +void testBugSameDel(void) { + Doc doc; + doc.local_agent = 'A'; + + { + std::string_view new_text{"a"}; + doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"aa"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"a"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } +} + +void testBugSameDel2(void) { + Doc doc; + doc.local_agent = 'A'; + + { + std::string_view new_text{"a"}; + doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"aa"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"aaa"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"aa"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } + + { + std::string_view new_text{"a"}; + const auto ops = doc.merge(new_text); + assert(doc.getText() == new_text); + } +} + int main(void) { const size_t loops = 1'000; { @@ -469,10 +555,31 @@ int main(void) { std::cout << std::string(40, '=') << "\n"; { - std::cout << "testBugNLNL:\n"; + std::cout << "testBugSame:\n"; testBugSame(); } + std::cout << std::string(40, '=') << "\n"; + + { + std::cout << "testBugDoubleDel:\n"; + testBugDoubleDel(); + } + + std::cout << std::string(40, '=') << "\n"; + + { + std::cout << "testBugSameDel:\n"; + testBugSameDel(); + } + + std::cout << std::string(40, '=') << "\n"; + + { + std::cout << "testBugSameDel2:\n"; + testBugSameDel2(); + } + return 0; } diff --git a/vim_research/test1.cpp b/vim_research/test1.cpp index 888a502..5d9243a 100644 --- a/vim_research/test1.cpp +++ b/vim_research/test1.cpp @@ -210,8 +210,8 @@ int main(void) { doc.local_agent = remote_address.port; // tmp: use local port as id while (true) { - // 10MiB - auto buffer = std::make_unique>(); + // 100MiB + auto buffer = std::make_unique>(); int64_t bytes_received {0}; bytes_received = zed_net_tcp_socket_receive(&remote_socket, buffer->data(), buffer->size());