Avoid calculating atom length in DisplayLine::trim_from

Calculating the length of an atom means we need to decode every
codepoint and compute its column width. This can prove quite expensive
in trim_from as we can have full buffer lines, so on buffer with long
lines we might have to go through megabytes of undisplayed data.
This commit is contained in:
Maxime Coste 2022-12-06 17:51:28 +11:00
parent 933e4a599c
commit 93c50b3cd9
2 changed files with 50 additions and 28 deletions

View File

@ -55,24 +55,56 @@ ColumnCount DisplayAtom::length() const
return 0; return 0;
} }
void DisplayAtom::trim_begin(ColumnCount count) bool DisplayAtom::empty() const
{ {
if (m_type == Range) if (m_type == Range)
m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin), return m_range.begin == m_range.end;
get_iterator(*m_buffer, m_range.end),
count).coord();
else else
m_text = m_text.substr(count).str(); return m_text.empty();
} }
void DisplayAtom::trim_end(ColumnCount count) ColumnCount DisplayAtom::trim_begin(ColumnCount count)
{ {
ColumnCount res = 0;
if (m_type == Range) if (m_type == Range)
m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end), {
get_iterator(*m_buffer, m_range.begin), auto it = get_iterator(*m_buffer, m_range.begin);
-count).coord(); auto end = get_iterator(*m_buffer, m_range.end);
while (it != end and res < count)
res += codepoint_width(utf8::read_codepoint(it, end));
m_range.begin = std::min(it.coord(), m_range.end);
}
else else
m_text = m_text.substr(0, m_text.column_length() - count).str(); {
auto it = m_text.begin();
while (it != m_text.end() and res < count)
res += codepoint_width(utf8::read_codepoint(it, m_text.end()));
m_text = String{it, m_text.end()};
}
return res;
}
ColumnCount DisplayAtom::trim_end_to_length(ColumnCount count)
{
ColumnCount res = 0;
if (m_type == Range)
{
auto it = get_iterator(*m_buffer, m_range.begin);
auto end = get_iterator(*m_buffer, m_range.end);
while (it != end and res < count)
res += codepoint_width(utf8::read_codepoint(it, end));
m_range.end = std::min(it.coord(), m_range.end);
}
else
{
auto it = m_text.begin();
while (it != m_text.end() and res < count)
res += codepoint_width(utf8::read_codepoint(it, m_text.end()));
m_text = String{m_text.begin(), it};
}
return res;
} }
DisplayLine::DisplayLine(AtomList atoms) DisplayLine::DisplayLine(AtomList atoms)
@ -222,26 +254,15 @@ bool DisplayLine::trim_from(ColumnCount first_col, ColumnCount front, ColumnCoun
while (front > 0 and it != end()) while (front > 0 and it != end())
{ {
auto len = it->length(); front -= it->trim_begin(front);
if (len <= front) if (it->empty())
{ it = m_atoms.erase(it);
m_atoms.erase(it);
front -= len;
}
else
{
it->trim_begin(front);
front = 0;
}
} }
it = begin(); it = begin();
for (; it != end() and col_count > 0; ++it) for (; it != end() and col_count > 0; ++it)
col_count -= it->length(); col_count -= it->trim_end_to_length(col_count);
bool did_trim = it != end() && col_count == 0;
bool did_trim = it != end() || col_count < 0;
if (col_count < 0)
(it-1)->trim_end(-col_count);
m_atoms.erase(it, end()); m_atoms.erase(it, end());
compute_range(); compute_range();

View File

@ -38,6 +38,7 @@ public:
StringView content() const; StringView content() const;
ColumnCount length() const; ColumnCount length() const;
bool empty() const;
const BufferCoord& begin() const const BufferCoord& begin() const
{ {
@ -74,8 +75,8 @@ public:
Type type() const { return m_type; } Type type() const { return m_type; }
void trim_begin(ColumnCount count); ColumnCount trim_begin(ColumnCount count);
void trim_end(ColumnCount count); ColumnCount trim_end_to_length(ColumnCount count);
bool operator==(const DisplayAtom& other) const bool operator==(const DisplayAtom& other) const
{ {