add doc write lock and make imgui use it
This commit is contained in:
@@ -37,3 +37,20 @@ CRDTNotes::Doc* CRDTNotes::addDoc(const CRDTAgent& self_agent, const DocID& id)
|
||||
return &doc;
|
||||
}
|
||||
|
||||
void CRDTNotes::writeLockRelease(const DocID& id) {
|
||||
assert(_doc_write_locks.count(id) > 0);
|
||||
_doc_write_locks.erase(id);
|
||||
}
|
||||
|
||||
bool CRDTNotes::isWriteLocked(const DocID& id) const {
|
||||
return _doc_write_locks.count(id);
|
||||
}
|
||||
|
||||
std::optional<CRDTNotes::DocWriteLock> CRDTNotes::writeLockAquire(const DocID& id) {
|
||||
if (_doc_write_locks.count(id)) {
|
||||
return std::nullopt; // replace with exception instead?
|
||||
}
|
||||
|
||||
_doc_write_locks.emplace(id);
|
||||
return DocWriteLock{*this, id};
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
|
||||
using ID32 = std::array<uint8_t, 32>;
|
||||
|
||||
@@ -37,9 +39,23 @@ class CRDTNotes {
|
||||
uint64_t seq{0};
|
||||
};
|
||||
|
||||
// RAII lock wrapper
|
||||
struct DocWriteLock {
|
||||
CRDTNotes* notes;
|
||||
DocID id;
|
||||
|
||||
// ctr assumes lock
|
||||
DocWriteLock(CRDTNotes& notes, const DocID& id) : notes(¬es), id(id) {}
|
||||
DocWriteLock(const DocWriteLock&) = delete;
|
||||
DocWriteLock(DocWriteLock&& other) : notes(other.notes), id(other.id) { other.notes = nullptr; }
|
||||
~DocWriteLock(void) { if (notes) { notes->writeLockRelease(id); } }
|
||||
bool operator==(const DocWriteLock& other) const { return id == other.id; }
|
||||
};
|
||||
|
||||
private:
|
||||
// TODO: add metadata to docs
|
||||
std::unordered_map<DocID, Doc> _docs;
|
||||
std::unordered_set<DocID> _doc_write_locks;
|
||||
|
||||
public:
|
||||
// config?
|
||||
@@ -52,5 +68,16 @@ class CRDTNotes {
|
||||
Doc* getDoc(const DocID& id);
|
||||
|
||||
Doc* addDoc(const CRDTAgent& self_agent, const DocID& doc);
|
||||
|
||||
void writeLockRelease(const DocID& id);
|
||||
bool isWriteLocked(const DocID& id) const;
|
||||
std::optional<DocWriteLock> writeLockAquire(const DocID& id);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<CRDTNotes::DocWriteLock> {
|
||||
std::uint64_t operator()(const CRDTNotes::DocWriteLock& s) const noexcept {
|
||||
return std::hash<ID32>{}(s.id);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -48,6 +48,12 @@ namespace detail {
|
||||
} // detail
|
||||
|
||||
|
||||
std::unordered_set<CRDTNotes::DocWriteLock>::iterator CRDTNotesImGui::findLock(const CRDTNotes::DocID& doc_id) {
|
||||
auto it = _held_locks.begin();
|
||||
for (; it != _held_locks.end() && it->id != doc_id; it++) {}
|
||||
return it;
|
||||
}
|
||||
|
||||
CRDTNotesImGui::CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs) : _notes(notes), _notes_sync(notes_sync), _cs(cs) {
|
||||
}
|
||||
|
||||
@@ -142,17 +148,36 @@ bool CRDTNotesImGui::renderDoc(const CRDTNotes::DocID& doc_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lock_it = findLock(doc_id);
|
||||
bool self_held = lock_it != _held_locks.end();
|
||||
const bool foreign_held = !self_held && _notes.isWriteLocked(doc_id);
|
||||
|
||||
auto text = doc->getText();
|
||||
if (renderDocText(text)) {
|
||||
ImGui::InputTextMultiline(
|
||||
"##doc",
|
||||
&text,
|
||||
{-1,-1},
|
||||
ImGuiInputTextFlags_AllowTabInput |
|
||||
(foreign_held ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_None) |
|
||||
ImGuiInputTextFlags_CallbackAlways
|
||||
//cb,
|
||||
//&text
|
||||
);
|
||||
if (!foreign_held && !self_held && (ImGui::IsItemActive() || ImGui::IsItemEdited())) {
|
||||
// TODO: check
|
||||
_held_locks.emplace(_notes.writeLockAquire(doc_id).value());
|
||||
self_held = true;
|
||||
std::cout << "!!!! imgui lock aquired\n";
|
||||
} else if (!foreign_held && self_held && !(ImGui::IsItemActive() || ImGui::IsItemEdited())) {
|
||||
// release lock
|
||||
_held_locks.erase(lock_it);
|
||||
std::cout << "!!!! imgui lock released\n";
|
||||
}
|
||||
|
||||
if (self_held && ImGui::IsItemEdited()) {
|
||||
_notes_sync.merge(doc_id, text);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRDTNotesImGui::renderDocText(std::string& text) const {
|
||||
// TODO: replace with text editor (zep) or visualize stuff??
|
||||
return ImGui::InputTextMultiline("##doc", &text, {-1,-1}, ImGuiInputTextFlags_AllowTabInput);
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <solanaceae/contact/fwd.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
class CRDTNotesImGui {
|
||||
CRDTNotes& _notes;
|
||||
@@ -13,6 +14,9 @@ class CRDTNotesImGui {
|
||||
bool _show_global_list {true};
|
||||
|
||||
std::set<CRDTNotes::DocID> _open_docs;
|
||||
std::unordered_set<CRDTNotes::DocWriteLock> _held_locks;
|
||||
|
||||
std::unordered_set<CRDTNotes::DocWriteLock>::iterator findLock(const CRDTNotes::DocID& doc_id);
|
||||
|
||||
public:
|
||||
CRDTNotesImGui(CRDTNotes& notes, CRDTNotesSync& notes_sync, ContactStore4I& cs);
|
||||
@@ -22,6 +26,5 @@ class CRDTNotesImGui {
|
||||
bool renderContactListContactSmall(const Contact4 c, const bool selected) const;
|
||||
|
||||
bool renderDoc(const CRDTNotes::DocID& doc_id);
|
||||
bool renderDocText(std::string& text) const;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user