Load into the piece table's original store; save and copy without materializing
A loaded file's bytes are adopted as the piece table's original storage instead of being appended to the add buffer: the first keystroke no longer reallocates and copies the whole file (140 ms at 200 MB), and the read buffer is not copied again. Save writes the pieces in order instead of materializing the buffer (a second full copy that then stayed resident). Buffer::Bytes() assembles a copy from the pieces and replaces four hand-rolled copies (swap snapshots, recovery comparison, Command.cc's per-row join, the tests' accessor). A single-piece table (an unedited file) is viewed in place; GetLineView serves a line from its piece when it lies within one, so it no longer copies the whole buffer after every edit. Code that needed the whole text contiguous says so with ContentView(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -185,6 +185,7 @@ void
|
||||
PieceTable::Clear()
|
||||
{
|
||||
pieces_.clear();
|
||||
std::string().swap(original_);
|
||||
add_.clear();
|
||||
materialized_.clear();
|
||||
total_size_ = 0;
|
||||
@@ -198,6 +199,52 @@ PieceTable::Clear()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PieceTable::AdoptOriginal(std::string &&bytes)
|
||||
{
|
||||
Clear();
|
||||
std::string().swap(add_); // release a previous content's capacity
|
||||
std::string().swap(materialized_);
|
||||
original_ = std::move(bytes);
|
||||
total_size_ = original_.size();
|
||||
if (total_size_ > 0)
|
||||
pieces_.push_back(Piece{Source::Original, 0, total_size_});
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
PieceTable::ContentView() const
|
||||
{
|
||||
if (total_size_ == 0)
|
||||
return {};
|
||||
if (pieces_.size() == 1) {
|
||||
const Piece &p = pieces_.front();
|
||||
return {(p.src == Source::Original ? original_ : add_).data() + p.start, p.len};
|
||||
}
|
||||
materialize();
|
||||
return {materialized_.data(), materialized_.size()};
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
PieceTable::View(std::size_t byte_offset, std::size_t len) const
|
||||
{
|
||||
if (byte_offset >= total_size_ || len == 0)
|
||||
return {};
|
||||
len = std::min(len, total_size_ - byte_offset);
|
||||
if (dirty_) {
|
||||
// Materialized text is stale: serve the range from its piece when it
|
||||
// fits in one, rather than copying the whole buffer.
|
||||
auto [idx, inner] = locate(byte_offset);
|
||||
if (idx < pieces_.size() && inner + len <= pieces_[idx].len) {
|
||||
const Piece &p = pieces_[idx];
|
||||
return {(p.src == Source::Original ? original_ : add_).data() + p.start + inner, len};
|
||||
}
|
||||
}
|
||||
return ContentView().substr(byte_offset, len);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PieceTable::addPieceBack(const Source src, const std::size_t start, const std::size_t len)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user