From aaba6508b3aef649fe8cc832e823f38893a9c514 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Fri, 30 Jun 2023 16:41:12 +0200 Subject: [PATCH] Add an ASCII fast-pass to ROW --- src/buffer/out/Row.cpp | 71 +++++++++++++++++++++++++++++++++++++----- src/buffer/out/Row.hpp | 22 ++----------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/buffer/out/Row.cpp b/src/buffer/out/Row.cpp index 2d6b3e7b8d5a..295a9b287e6f 100644 --- a/src/buffer/out/Row.cpp +++ b/src/buffer/out/Row.cpp @@ -538,28 +538,85 @@ catch (...) [[msvc::forceinline]] void ROW::WriteHelper::ReplaceText() noexcept { + auto it = chars.begin(); + const auto end = chars.end(); size_t ch = chBeg; - for (const auto& s : til::utf16_iterator{ chars }) + // First a fast-pass for ASCII. ASCII is still predominant in technical areas. + while (it != end) { - const auto wide = til::at(s, 0) < 0x80 ? false : IsGlyphFullWidth(s); - const auto colEndNew = gsl::narrow_cast(colEnd + 1u + wide); + // MSVC is hoists the inlined call outside of the loop and puts it at the end of ROW::ReplaceText(), past WriteHelper::Finish(). + // Inlining the call manually technically improves performance slightly, but is less maintainable. + if (*it >= 0x80) + { + _replaceTextUnicode(ch, it, end); + return; + } + + if (colEnd >= colLimit) + { + colEndDirty = colLimit; + charsConsumed = ch - chBeg; + return; + } + + til::at(row._charOffsets, colEnd) = gsl::narrow_cast(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 std::wstring_view::const_iterator end) +{ + while (it != end) + { + unsigned int width = 1; + auto ptr = &*it; + const auto wch = *ptr; + size_t advance = 1; + + ++it; + + 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(colEnd + width); if (colEndNew > colLimit) { colEndDirty = colLimit; - break; + charsConsumed = ch - chBeg; + return; } til::at(row._charOffsets, colEnd++) = gsl::narrow_cast(ch); - if (wide) + if (colEnd < colEndNew) { til::at(row._charOffsets, colEnd++) = gsl::narrow_cast(ch | CharOffsetsTrailer); } - colEndDirty = colEnd; - ch += s.size(); + ch += advance; } + colEndDirty = colEnd; charsConsumed = ch - chBeg; } diff --git a/src/buffer/out/Row.hpp b/src/buffer/out/Row.hpp index 1ce38c0668ef..ab055611418d 100644 --- a/src/buffer/out/Row.hpp +++ b/src/buffer/out/Row.hpp @@ -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 @@ -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, const std::wstring_view::const_iterator end); void CopyTextFrom(const std::span& charOffsets) noexcept; static void _copyOffsets(uint16_t* dst, const uint16_t* src, uint16_t size, uint16_t offset) noexcept; void Finish();