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;
}
void DisplayAtom::trim_begin(ColumnCount count)
bool DisplayAtom::empty() const
{
if (m_type == Range)
m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin),
get_iterator(*m_buffer, m_range.end),
count).coord();
return m_range.begin == m_range.end;
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)
m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end),
get_iterator(*m_buffer, m_range.begin),
-count).coord();
{
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.begin = std::min(it.coord(), m_range.end);
}
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)
@ -222,26 +254,15 @@ bool DisplayLine::trim_from(ColumnCount first_col, ColumnCount front, ColumnCoun
while (front > 0 and it != end())
{
auto len = it->length();
if (len <= front)
{
m_atoms.erase(it);
front -= len;
}
else
{
it->trim_begin(front);
front = 0;
}
front -= it->trim_begin(front);
if (it->empty())
it = m_atoms.erase(it);
}
it = begin();
for (; it != end() and col_count > 0; ++it)
col_count -= it->length();
bool did_trim = it != end() || col_count < 0;
if (col_count < 0)
(it-1)->trim_end(-col_count);
col_count -= it->trim_end_to_length(col_count);
bool did_trim = it != end() && col_count == 0;
m_atoms.erase(it, end());
compute_range();

View File

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