Repository: microsoft/terminal
File: src/host/VtIo.cpp (C++)

Code before:
}

void VtIo::Writer::WriteUTF16(std::wstring_view str) const
{
    if (str.empty())
    {
        return;
    }

    const auto existingUTF8Len = _io->_back.size();
    const auto incomingUTF16Len = str.size();

    // When converting from UTF-16 to UTF-8 the worst case is 3 bytes per UTF-16 code unit.
    const auto incomingUTF8Cap = incomingUTF16Len * 3;
    const auto totalUTF8Cap = existingUTF8Len + incomingUTF8Cap;

    // Since WideCharToMultiByte() only supports `int` lengths, we check for an overflow past INT_MAX/3.
    // We also check for an overflow of totalUTF8Cap just to be sure.
    if (incomingUTF16Len > gsl::narrow_cast<size_t>(INT_MAX / 3) || totalUTF8Cap <= existingUTF8Len)
    {
        THROW_HR_MSG(E_INVALIDARG, "string too large");
    }

    // C++23's resize_and_overwrite is too valuable to not use.
    // It reduce the CPU overhead by roughly half.
#if !defined(_HAS_CXX23) || !_HAS_CXX23
#define resize_and_overwrite _Resize_and_overwrite
#endif

    // NOTE: Throwing inside resize_and_overwrite invokes undefined behavior.
    _io->_back.resize_and_overwrite(totalUTF8Cap, [&](char* buf, const size_t) noexcept {
        const auto len = WideCharToMultiByte(CP_UTF8, 0, str.data(), gsl::narrow_cast<int>(incomingUTF16Len), buf + existingUTF8Len, gsl::narrow_cast<int>(incomingUTF8Cap), nullptr, nullptr);
        return existingUTF8Len + std::max(0, len);
    });

#undef resize_and_overwrite
}

// When DISABLE_NEWLINE_AUTO_RETURN is not set (Bad! Don't do it!) we'll do newline translation for you.
// That's the only difference of this function from WriteUTF16: It does LF -> CRLF translation.
void VtIo::Writer::WriteUTF16TranslateCRLF(std::wstring_view str) const
{
    const auto beg = str.begin();
    const auto end = str.end();
    auto begCopy = beg;
    auto endCopy = beg;

    // Our goal is to prepend a \r in front of \n that don't already have one.
    // There's no point in replacing \n\n\n with \r\n\r\n\r\n, however. It's just fine to do \r\n\n\n.
    // After all we aren't a text file, we're a terminal, and \r\n and \n are identical if we're at the first column.
    for (;;)

Review comment (suggestion):
Using feature test macros instead of MSVC private macros; this will no longer be necessary after upgrading to C++23. The macro [_MSVC_STL_UPDATE](https://github.com/microsoft/STL/wiki/Macro-_MSVC_STL_UPDATE) is documented.

Code after:
}

void VtIo::Writer::WriteUTF16(std::wstring_view str) const
{
    if (str.empty())
    {
        return;
    }

    const auto existingUTF8Len = _io->_back.size();
    const auto incomingUTF16Len = str.size();

    // When converting from UTF-16 to UTF-8 the worst case is 3 bytes per UTF-16 code unit.
    const auto incomingUTF8Cap = incomingUTF16Len * 3;
    const auto totalUTF8Cap = existingUTF8Len + incomingUTF8Cap;

    // Since WideCharToMultiByte() only supports `int` lengths, we check for an overflow past INT_MAX/3.
    // We also check for an overflow of totalUTF8Cap just to be sure.
    if (incomingUTF16Len > gsl::narrow_cast<size_t>(INT_MAX / 3) || totalUTF8Cap <= existingUTF8Len)
    {
        THROW_HR_MSG(E_INVALIDARG, "string too large");
    }

    // C++23's resize_and_overwrite is too valuable to not use.
    // It reduce the CPU overhead by roughly half.
#if !defined(__cpp_lib_string_resize_and_overwrite) && _MSVC_STL_UPDATE >= 202111L
#define resize_and_overwrite _Resize_and_overwrite
#elif !defined(__cpp_lib_string_resize_and_overwrite)
#error "rely on resize_and_overwrite"
#endif
    // NOTE: Throwing inside resize_and_overwrite invokes undefined behavior.
    _io->_back.resize_and_overwrite(totalUTF8Cap, [&](char* buf, const size_t) noexcept {
        const auto len = WideCharToMultiByte(CP_UTF8, 0, str.data(), gsl::narrow_cast<int>(incomingUTF16Len), buf + existingUTF8Len, gsl::narrow_cast<int>(incomingUTF8Cap), nullptr, nullptr);
        return existingUTF8Len + std::max(0, len);
    });

#undef resize_and_overwrite
}

// When DISABLE_NEWLINE_AUTO_RETURN is not set (Bad! Don't do it!) we'll do newline translation for you.
// That's the only difference of this function from WriteUTF16: It does LF -> CRLF translation.
void VtIo::Writer::WriteUTF16TranslateCRLF(std::wstring_view str) const
{
    const auto beg = str.begin();
    const auto end = str.end();
    auto begCopy = beg;
    auto endCopy = beg;

    // Our goal is to prepend a \r in front of \n that don't already have one.
    // There's no point in replacing \n\n\n with \r\n\r\n\r\n, however. It's just fine to do \r\n\n\n.
    // After all we aren't a text file, we're a terminal, and \r\n and \n are identical if we're at the first column.