Reduce memory usage and allocations in terminal output code
Store data in unique_ptr instead of vectors as we have fixed sizes Do not allocate new hashes, recompute them on-demand
This commit is contained in:
parent
580869fd49
commit
73da47258d
|
@ -23,22 +23,6 @@ namespace Kakoune
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
|
|
||||||
void TerminalUI::Window::create(const DisplayCoord& p, const DisplayCoord& s)
|
|
||||||
{
|
|
||||||
kak_assert(p.line >= 0 and p.column >= 0);
|
|
||||||
kak_assert(s.line >= 0 and s.column >= 0);
|
|
||||||
pos = p;
|
|
||||||
size = s;
|
|
||||||
lines.resize((int)size.line);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerminalUI::Window::destroy()
|
|
||||||
{
|
|
||||||
pos = DisplayCoord{};
|
|
||||||
size = DisplayCoord{};
|
|
||||||
lines.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TerminalUI::Window::Line
|
struct TerminalUI::Window::Line
|
||||||
{
|
{
|
||||||
struct Atom
|
struct Atom
|
||||||
|
@ -148,17 +132,33 @@ struct TerminalUI::Window::Line
|
||||||
Vector<Atom> atoms;
|
Vector<Atom> atoms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void TerminalUI::Window::create(const DisplayCoord& p, const DisplayCoord& s)
|
||||||
|
{
|
||||||
|
kak_assert(p.line >= 0 and p.column >= 0);
|
||||||
|
kak_assert(s.line >= 0 and s.column >= 0);
|
||||||
|
pos = p;
|
||||||
|
size = s;
|
||||||
|
lines.reset(new Line[(int)size.line]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalUI::Window::destroy()
|
||||||
|
{
|
||||||
|
pos = DisplayCoord{};
|
||||||
|
size = DisplayCoord{};
|
||||||
|
lines.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalUI::Window::blit(Window& target)
|
void TerminalUI::Window::blit(Window& target)
|
||||||
{
|
{
|
||||||
kak_assert(pos.line < target.lines.size());
|
kak_assert(pos.line < target.size.line);
|
||||||
auto target_line = target.lines.begin() + (size_t)pos.line;
|
LineCount line_index = pos.line;
|
||||||
for (auto& line : lines)
|
for (auto& line : ArrayView{lines.get(), (size_t)size.line})
|
||||||
{
|
{
|
||||||
line.resize(size.column);
|
line.resize(size.column);
|
||||||
target_line->resize(target.size.column);
|
auto& target_line = target.lines[(size_t)line_index];
|
||||||
target_line->atoms.insert(target_line->erase_range(pos.column, size.column),
|
target_line.resize(target.size.column);
|
||||||
line.atoms.begin(), line.atoms.end());
|
target_line.atoms.insert(target_line.erase_range(pos.column, size.column), line.atoms.begin(), line.atoms.end());
|
||||||
if (++target_line == target.lines.end())
|
if (++line_index == target.size.line)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ void TerminalUI::Window::draw(DisplayCoord pos,
|
||||||
ConstArrayView<DisplayAtom> atoms,
|
ConstArrayView<DisplayAtom> atoms,
|
||||||
const Face& default_face)
|
const Face& default_face)
|
||||||
{
|
{
|
||||||
if (pos.line >= lines.size()) // We might receive an out of date draw command after a resize
|
if (pos.line >= size.line) // We might receive an out of date draw command after a resize
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lines[(size_t)pos.line].resize(pos.column);
|
lines[(size_t)pos.line].resize(pos.column);
|
||||||
|
@ -245,7 +245,7 @@ void TerminalUI::Screen::set_face(const Face& face, Writer& writer)
|
||||||
|
|
||||||
void TerminalUI::Screen::output(bool force, bool synchronized, Writer& writer)
|
void TerminalUI::Screen::output(bool force, bool synchronized, Writer& writer)
|
||||||
{
|
{
|
||||||
if (lines.empty())
|
if (not lines)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// iTerm2 "begin synchronized update" sequence
|
// iTerm2 "begin synchronized update" sequence
|
||||||
|
@ -254,16 +254,20 @@ void TerminalUI::Screen::output(bool force, bool synchronized, Writer& writer)
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
hashes.clear();
|
std::fill_n(hashes.get(), (size_t)size.line, 0);
|
||||||
writer.write("\033[m");
|
writer.write("\033[m");
|
||||||
m_active_face = Face{};
|
m_active_face = Face{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto hash_line = [](const Line& line) {
|
||||||
|
return (hash_value(line.atoms) << 1) | 1; // ensure non-zero
|
||||||
|
};
|
||||||
|
|
||||||
struct Change { int keep; int add; int del; };
|
struct Change { int keep; int add; int del; };
|
||||||
Vector<Change> changes{Change{}};
|
Vector<Change> changes{Change{}};
|
||||||
auto new_hashes = lines | transform([](auto& line) { return hash_value(line.atoms); }) | gather<Vector>();
|
auto new_hashes = ArrayView{lines.get(), (size_t)size.line} | transform(hash_line);
|
||||||
for_each_diff(hashes.begin(), hashes.size(),
|
for_each_diff(hashes.get(), (int)size.line,
|
||||||
new_hashes.begin(), new_hashes.size(),
|
new_hashes.begin(), (int)size.line,
|
||||||
[&changes](DiffOp op, int len) mutable {
|
[&changes](DiffOp op, int len) mutable {
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
|
@ -278,7 +282,7 @@ void TerminalUI::Screen::output(bool force, bool synchronized, Writer& writer)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
hashes = std::move(new_hashes);
|
std::copy(new_hashes.begin(), new_hashes.end(), hashes.get());
|
||||||
|
|
||||||
int line = 0;
|
int line = 0;
|
||||||
for (auto& change : changes)
|
for (auto& change : changes)
|
||||||
|
@ -590,7 +594,7 @@ void TerminalUI::check_resize(bool force)
|
||||||
|
|
||||||
m_window.create({0, 0}, terminal_size);
|
m_window.create({0, 0}, terminal_size);
|
||||||
m_screen.create({0, 0}, terminal_size);
|
m_screen.create({0, 0}, terminal_size);
|
||||||
m_screen.hashes.clear();
|
m_screen.hashes.reset(new size_t[(int)terminal_size.line]{});
|
||||||
kak_assert(m_window);
|
kak_assert(m_window);
|
||||||
|
|
||||||
m_dimensions = terminal_size - 1_line;
|
m_dimensions = terminal_size - 1_line;
|
||||||
|
|
|
@ -81,10 +81,10 @@ private:
|
||||||
void blit(Window& target);
|
void blit(Window& target);
|
||||||
void draw(DisplayCoord pos, ConstArrayView<DisplayAtom> atoms, const Face& default_face);
|
void draw(DisplayCoord pos, ConstArrayView<DisplayAtom> atoms, const Face& default_face);
|
||||||
|
|
||||||
explicit operator bool() const { return not lines.empty(); }
|
explicit operator bool() const { return (bool)lines; }
|
||||||
|
|
||||||
struct Line;
|
struct Line;
|
||||||
Vector<Line> lines;
|
std::unique_ptr<Line[]> lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Screen : Window
|
struct Screen : Window
|
||||||
|
@ -92,7 +92,7 @@ private:
|
||||||
void output(bool force, bool synchronized, Writer& writer);
|
void output(bool force, bool synchronized, Writer& writer);
|
||||||
void set_face(const Face& face, Writer& writer);
|
void set_face(const Face& face, Writer& writer);
|
||||||
|
|
||||||
Vector<size_t> hashes;
|
std::unique_ptr<size_t[]> hashes;
|
||||||
Face m_active_face;
|
Face m_active_face;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user