From 04b5ed7c4f7f899cea256fabfdeb3d43cbe877c7 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 14 Dec 2022 14:56:54 +0100 Subject: [PATCH] add ops, start on text diffing and op gernation, no diffing yet --- version0/list.hpp | 14 ++++ version0/text_document.hpp | 129 ++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/version0/list.hpp b/version0/list.hpp index e6ba7dd..8c4ca31 100644 --- a/version0/list.hpp +++ b/version0/list.hpp @@ -35,6 +35,20 @@ struct List { } }; + // almost the same as entry + struct OpAdd { + ListID id; + + std::optional parent_left; + std::optional parent_right; + + ValueType value; + }; + + struct OpDel { + ListID id; + }; + // TODO: replace with SoA struct Entry { ListID id; diff --git a/version0/text_document.hpp b/version0/text_document.hpp index 1fc626d..072ae43 100644 --- a/version0/text_document.hpp +++ b/version0/text_document.hpp @@ -2,6 +2,10 @@ #include "./list.hpp" +#include +#include +#include + namespace GreenCRDT { template @@ -9,14 +13,18 @@ struct TextDocument { // TODO: determine if char is the best using ListType = List; + using Op = std::variant; + struct Cursor { AgentType who; typename ListType::ListID pos; }; + AgentType local_agent; + ListType state; - std::string getText(void) { + [[nodiscard]] std::string getText(void) const { std::string text; for (const auto& it : state.list) { @@ -27,6 +35,125 @@ struct TextDocument { return text; } + + static std::vector text2adds( + const AgentType& agent, uint64_t& last_seq, + std::optional parent_left, + std::optional parent_right, + std::string_view text + ) { + std::vector ops; + for (size_t i = 0; i < text.size(); i++) { + typename ListType::ListID new_id {agent, ++last_seq}; + + ops.emplace_back(typename ListType::OpAdd{ + new_id, + parent_left, + parent_right, + text[i] + }); + + parent_left = new_id; + } + + return ops; + } + + // adds in tast with specified parents + // returns generated ops + std::vector addText( + std::optional parent_left, + std::optional parent_right, + std::string_view text + ) { + // TODO: look up typesystem and fix (move? decltype?) + std::vector ops = text2adds( + local_agent, state.last_seen_seq[local_agent], + parent_left, + parent_right, + text + ); + + // TODO: make this better + // and apply + for (const auto& op : ops) { + if constexpr (std::holds_alternative(op)) { + const auto& add_op = std::get(op); + state.add(add_op.id, add_op.value, add_op.parent_left, add_op.parent_right); + } else if constexpr (std::holds_alternative(op)) { + const auto& del_op = std::get(op); + state.del(del_op.id); + } else { + assert(false); + } + } + + return ops; // TODO: move? + } + + // deletes everything in range [first, last) + // returns generated ops + std::vector delRange( + std::optional left, + std::optional right + ) { + size_t first_idx = 0; + if (left.has_value()) { + auto res = state.findIdx(left.value()); + if (!res.has_value()) { + assert(false && "cant find left"); + return {}; + } + first_idx = res; + } + + size_t last_idx = state.list.size(); + if (right.has_value()) { + auto res = state.findIdx(right.value()); + if (!res.has_value()) { + assert(false && "cant find right"); + return {}; + } + last_idx = res; + } + + std::vector ops; + + for (size_t i = first_idx; i < last_idx; i++) { + ops.emplace_back(typename ListType::OpDel{ + state.list[i].id + }); + + // TODO: do delets get a seq????? + + state.list[i].value = std::nullopt; + } + + return ops; + } + + // generates ops from the difference + // note: rn it only creates 1 diff patch + std::vector merge(std::string_view other_text) { + if (other_text.empty()) { + return {}; + } + + if (state.list.empty()) { + return addText( + std::nullopt, + std::nullopt, + other_text + ); + } + + // find start and end of changes + // start + size_t list_idx_start = 0; + size_t other_idx_start = 0; + //for (; idx_start < state.list.size(); idx_start++) {} + + } }; } // GreenCRDT