Skip to content

Commit

Permalink
Add an ASCII fast-pass to ROW
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Jun 30, 2023
1 parent d628c46 commit de72cb6
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 26 deletions.
73 changes: 66 additions & 7 deletions src/buffer/out/Row.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,28 +538,87 @@ catch (...)

[[msvc::forceinline]] void ROW::WriteHelper::ReplaceText() noexcept
{
// This function starts with a fast-pass for ASCII. ASCII is still predominant in technical areas.
//
// We can infer the "end" from the amount of columns we're given (colLimit - colBeg),
// because ASCII is always 1 column wide per character.
auto it = chars.begin();
const auto end = it + std::min<size_t>(chars.size(), colLimit - colBeg);
size_t ch = chBeg;

for (const auto& s : til::utf16_iterator{ chars })
while (it != end)
{
if (*it >= 0x80) [[unlikely]]
{
_replaceTextUnicode(ch, it);
return;
}

til::at(row._charOffsets, colEnd) = gsl::narrow_cast<uint16_t>(ch);
++colEnd;
++ch;
++it;
}

colEndDirty = colEnd;
charsConsumed = ch - chBeg;
}

[[msvc::forceinline]] void ROW::WriteHelper::_replaceTextUnicode(size_t ch, std::wstring_view::const_iterator it)
{
const auto end = chars.end();

while (it != end)
{
const auto wide = til::at(s, 0) < 0x80 ? false : IsGlyphFullWidth(s);
const auto colEndNew = gsl::narrow_cast<uint16_t>(colEnd + 1u + wide);
unsigned int width = 1;
auto ptr = &*it;
const auto wch = *ptr;
size_t advance = 1;

++it;

// Even in our slow-path we can avoid calling IsGlyphFullWidth if the current character is ASCII.
// It also allows us to skip the surrogate pair decoding at the same time.
if (wch >= 0x80)
{
if (til::is_surrogate(wch))
{
if (it != end && til::is_leading_surrogate(wch) && til::is_trailing_surrogate(*it))
{
advance = 2;
++it;
}
else
{
ptr = &UNICODE_REPLACEMENT;
}
}

width = IsGlyphFullWidth({ ptr, advance }) + 1u;
}

const auto colEndNew = gsl::narrow_cast<uint16_t>(colEnd + width);
if (colEndNew > colLimit)
{
colEndDirty = colLimit;
break;
charsConsumed = ch - chBeg;
return;
}

// Fill our char-offset buffer with 1 entry containing the mapping from the
// current column (colEnd) to the start of the glyph in the string (ch)...
til::at(row._charOffsets, colEnd++) = gsl::narrow_cast<uint16_t>(ch);
if (wide)
// ...followed by 0-N entries containing an indication that the
// columns are just a wide-glyph extension of the preceding one.
while (colEnd < colEndNew)
{
til::at(row._charOffsets, colEnd++) = gsl::narrow_cast<uint16_t>(ch | CharOffsetsTrailer);
}

colEndDirty = colEnd;
ch += s.size();
ch += advance;
}

colEndDirty = colEnd;
charsConsumed = ch - chBeg;
}

Expand Down
22 changes: 3 additions & 19 deletions src/buffer/out/Row.hpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Row.hpp
Abstract:
- data structure for information associated with one row of screen buffer
Author(s):
- Michael Niksa (miniksa) 10-Apr-2014
- Paul Campbell (paulcam) 10-Apr-2014
Revision History:
- From components of output.h/.c
by Therese Stowell (ThereseS) 1990-1991
- Pulled into its own file from textBuffer.hpp/cpp (AustDi, 2017)
--*/
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

Expand Down Expand Up @@ -170,6 +153,7 @@ class ROW final
bool IsValid() const noexcept;
void ReplaceCharacters(til::CoordType width) noexcept;
void ReplaceText() noexcept;
void _replaceTextUnicode(size_t ch, std::wstring_view::const_iterator it);
void CopyTextFrom(const std::span<const uint16_t>& charOffsets) noexcept;
static void _copyOffsets(uint16_t* dst, const uint16_t* src, uint16_t size, uint16_t offset) noexcept;
void Finish();
Expand Down

0 comments on commit de72cb6

Please sign in to comment.