From b5c312a558a06ffaf9fd468c639764b9b1b9259a Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 16 Dec 2022 16:11:11 +0100 Subject: [PATCH] text diffing and merging and op gen work :D --- version0/test2.cpp | 107 ++++++++++++++++++++++++++++++++----- version0/text_document.hpp | 39 ++++++++++++-- 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/version0/test2.cpp b/version0/test2.cpp index 3b06e13..a3616dc 100644 --- a/version0/test2.cpp +++ b/version0/test2.cpp @@ -201,11 +201,15 @@ void testEmptyDocAdds(size_t seed) { std::cout << "changed_text: " << changed_text << "\n"; + Doc otherdoc = doc; assert(doc.getText().size() == doc.state.doc_size); - doc.merge(changed_text); + const auto merge_ops = doc.merge(changed_text); assert(doc.getText().size() == doc.state.doc_size); assert(doc.getText() == changed_text); + + assert(otherdoc.apply(merge_ops)); + assert(doc.getText() == otherdoc.getText()); } void test1CharDocAdds(size_t seed) { @@ -236,13 +240,17 @@ void test1CharDocAdds(size_t seed) { std::cout << "text: " << doc.getText() << "\n"; std::cout << "changed_text: " << changed_text << "\n"; + Doc otherdoc = doc; assert(doc.getText().size() == doc.state.doc_size); - doc.merge(changed_text); + const auto merge_ops = doc.merge(changed_text); assert(doc.getText().size() == doc.state.doc_size); std::cout << "text after merge: " << doc.getText() << "\n"; - //assert(doc.getText() == changed_text); + assert(doc.getText() == changed_text); + + assert(otherdoc.apply(merge_ops)); + assert(doc.getText() == otherdoc.getText()); } void test1CharDocDels(size_t seed) { @@ -282,13 +290,17 @@ void test1CharDocDels(size_t seed) { std::cout << "text: " << doc.getText() << "\n"; std::cout << "changed_text: " << changed_text << "\n"; + Doc otherdoc = doc; assert(doc.getText().size() == doc.state.doc_size); - doc.merge(changed_text); + const auto merge_ops = doc.merge(changed_text); assert(doc.getText().size() == doc.state.doc_size); std::cout << "text after merge: " << doc.getText() << "\n"; - //assert(doc.getText() == changed_text); + assert(doc.getText() == changed_text); + + assert(otherdoc.apply(merge_ops)); + assert(doc.getText() == otherdoc.getText()); } void test2CharDocAdds(size_t seed) { @@ -321,13 +333,69 @@ void test2CharDocAdds(size_t seed) { std::cout << "text: " << doc.getText() << "\n"; std::cout << "changed_text: " << changed_text << "\n"; + Doc otherdoc = doc; assert(doc.getText().size() == doc.state.doc_size); - doc.merge(changed_text); + const auto merge_ops = doc.merge(changed_text); assert(doc.getText().size() == doc.state.doc_size); std::cout << "text after merge: " << doc.getText() << "\n"; - //assert(doc.getText() == changed_text); + assert(doc.getText() == changed_text); + + assert(otherdoc.apply(merge_ops)); + assert(doc.getText() == otherdoc.getText()); +} + +void testChange1(size_t seed) { + Rng rng(seed); + + Doc doc; + doc.local_agent = 'A'; + + assert(doc.getText().size() == doc.state.doc_size); + doc.addText(std::nullopt, std::nullopt, "012345"); + assert(doc.getText().size() == doc.state.doc_size); + + assert(doc.getText() == "012345"); + + std::string changed_text; + { + // for modifying + Doc doctmp = doc; + + { // dels + const size_t loop_count = (rng() % 4)+1; + for (size_t i = 0; i < loop_count; i++) { + genDel(rng, doctmp); + } + } + + { // adds + const size_t loop_count = (rng() % 4)+1; + for (size_t i = 0; i < loop_count; i++) { + genAdd(rng, doctmp); + } + } + + changed_text = doctmp.getText(); + } + + assert(doc.getText() != changed_text); + + std::cout << "text: " << doc.getText() << "\n"; + std::cout << "changed_text: " << changed_text << "\n"; + + Doc otherdoc = doc; + assert(doc.getText().size() == doc.state.doc_size); + const auto merge_ops = doc.merge(changed_text); + assert(doc.getText().size() == doc.state.doc_size); + + std::cout << "text after merge: " << doc.getText() << "\n"; + + assert(doc.getText() == changed_text); + + assert(otherdoc.apply(merge_ops)); + assert(doc.getText() == otherdoc.getText()); } int main(void) { @@ -338,9 +406,10 @@ int main(void) { testEmptyDocAdds(1337+i); std::cout << std::string(40, '-') << "\n"; } - std::cout << std::string(40, '=') << "\n"; } + std::cout << std::string(40, '=') << "\n"; + { std::cout << "test1CharDocAdds:\n"; for (size_t i = 0; i < 1'000; i++) { @@ -348,27 +417,39 @@ int main(void) { test1CharDocAdds(1337+i); std::cout << std::string(40, '-') << "\n"; } - std::cout << std::string(40, '=') << "\n"; } + std::cout << std::string(40, '=') << "\n"; + { std::cout << "test1CharDocDels:\n"; - for (size_t i = 0; i < 100; i++) { + for (size_t i = 0; i < 1'000; i++) { std::cout << "i " << i << "\n"; test1CharDocDels(1337+i); std::cout << std::string(40, '-') << "\n"; } - std::cout << std::string(40, '=') << "\n"; } + std::cout << std::string(40, '=') << "\n"; + { std::cout << "test2CharDocAdds:\n"; - for (size_t i = 0; i < 10; i++) { + for (size_t i = 0; i < 1'000; i++) { std::cout << "i " << i << "\n"; test2CharDocAdds(1337+i); std::cout << std::string(40, '-') << "\n"; } - std::cout << std::string(40, '=') << "\n"; + } + + std::cout << std::string(40, '=') << "\n"; + + { + std::cout << "testChange1:\n"; + for (size_t i = 0; i < 1'000; i++) { + std::cout << "i " << i << "\n"; + testChange1(1337+i); + std::cout << std::string(40, '-') << "\n"; + } } return 0; diff --git a/version0/text_document.hpp b/version0/text_document.hpp index 171470f..5d51bd3 100644 --- a/version0/text_document.hpp +++ b/version0/text_document.hpp @@ -35,11 +35,33 @@ struct TextDocument { } } - //assert(text.size() == state.doc_size); - return text; } + bool apply(const Op& op) { + if(std::holds_alternative(op)) { + const auto& add_op = std::get(op); + //std::cout << "a:" << add_op.id.id << " s:" << add_op.id.seq << " v:" << add_op.value << "\n"; + return state.add(add_op.id, add_op.value, add_op.parent_left, add_op.parent_right); + } else if (std::holds_alternative(op)) { + const auto& del_op = std::get(op); + return state.del(del_op.id); + } else { + assert(false); + } + } + + bool apply(const std::vector& ops) { + for (const auto& op : ops) { + if (!apply(op)) { + // this is not ideal, since we might have applyed some, and dont report which/howmany + return false; + } + } + + return true; + } + static std::vector text2adds( const AgentType& agent, uint64_t seq, // seq is the first seq std::optional parent_left, @@ -72,7 +94,7 @@ struct TextDocument { ) { // TODO: look up typesystem and fix (move? decltype?) std::vector ops = text2adds( - local_agent, state.last_seen_seq.count(local_agent) ? state.last_seen_seq[local_agent] : 0u, + local_agent, state.last_seen_seq.count(local_agent) ? state.last_seen_seq[local_agent]+1u : 0u, parent_left, parent_right, text @@ -239,7 +261,18 @@ struct TextDocument { std::cout << "deleted: " << ops.size() << "\n"; } + std::cout << "text between: " << getText() << "\n"; + // 2. add range (add all text_start - text_end) + if (text_start < text_end) { + auto tmp_add_ops = addText( + list_start == 0 ? std::nullopt : std::make_optional(state.list[list_start-1].id), + list_start == state.list.size() ? std::nullopt :std::make_optional(state.list.at(list_start).id), + text.substr(text_start, text_end-text_start) + ); + std::cout << "added: " << tmp_add_ops.size() << "\n"; + ops.insert(ops.end(), tmp_add_ops.begin(), tmp_add_ops.end()); + } //assert(false && "implement me"); return ops;