#ifndef LINE_MAP_H #define LINE_MAP_H #include "syntax/decl.h" struct LineKey { uint32_t line; uint32_t version; bool operator==(const LineKey &other) const { return line == other.line && version == other.version; } }; struct LineKeyHash { size_t operator()(const LineKey &key) const { uint64_t combined = (uint64_t(key.line) << 32) | key.version; return std::hash()(combined); } }; struct EditDelta { uint32_t start_line; int64_t delta; }; struct LineMap { LineMap() : current_version(0) { edit_log.push_back({0, 0}); } LineData *at(uint32_t line) { auto key_opt = resolve_line(line); if (!key_opt) return nullptr; LineKey key = *key_opt; if (key.version == current_version) return lines[key].get(); auto data_ptr = std::move(lines[key]); lines.erase(key); key = {line, current_version}; lines[key] = std::move(data_ptr); return lines[key].get(); } LineData *create_at(uint32_t line) { auto key_opt = resolve_line(line); LineKey key; std::unique_ptr data_ptr; if (key_opt) { key = *key_opt; if (key.version == current_version) return lines[key].get(); data_ptr = std::move(lines[key]); lines.erase(key); } else { data_ptr = std::make_unique(); } key = {line, current_version}; lines[key] = std::move(data_ptr); return lines[key].get(); } void apply_edit(uint32_t start, int64_t delta) { if (delta < 0) { int64_t count = -delta; for (int64_t i = 0; i < count; i++) { auto key = resolve_line(start + i); if (!key) continue; lines.erase(*key); } } current_version++; edit_log.push_back({start, delta}); } private: std::unordered_map, LineKeyHash> lines; std::vector edit_log; uint32_t current_version; std::optional resolve_line(uint32_t line) { uint32_t current_line = line; for (int64_t v = current_version; v >= 0; v--) { LineKey key = {current_line, (uint32_t)v}; if (lines.find(key) != lines.end()) return key; const auto &edit = edit_log[v]; if (edit.delta > 0) { if (current_line >= edit.start_line) { if (current_line < edit.start_line + edit.delta) return std::nullopt; current_line -= edit.delta; } } else { if (current_line >= edit.start_line) current_line -= edit.delta; } } return std::nullopt; } }; #endif