A few places in WebCore use builder.append(String::fromUTF8(...)) to add UTF8 content to a StringBuilder. This makes an extra String allocation per call and can be improved by adding a StringTypeAdapter for this use case to directly convert into the StringBuilder's buffer. Something like: struct FromUTF8Converter { Span<const std::byte> buffer; }; inline FromUTF8Converter fromUTF8(Span<const std::byte> buffer) { return { buffer }; } template<> class StringTypeAdapter<FromUTF8Converter, void> { public: StringTypeAdapter(const FromUTF8Converter& converter) : m_converter { converter } { auto [utf16StringLength, isAllASCII] = computeUTF16StringLengthAreAllASCII(m_converter.buffer.data(), m_converter.buffer.size()) } m_utf16StringLength = utf16StringLength; m_isAllASCII = isAllASCII; } unsigned length() const { if (m_isAllASCII) return m_converter.buffer.size(); return m_utf16StringLength; } bool is8Bit() const { return m_isAllASCII; } void writeTo(LChar* destination) const { ASSERT(m_isAllASCII); memcpy(destination, m_converter.buffer.data(), m_converter.buffer.data() + m_converter.buffer.size(), ); } void writeTo(UChar* destination) const { convertUTF8ToUTF16(m_converter.buffer.data(), m_converter.buffer.size(), destination, destination + m_utf16StringLength); } private: const FromUTF8Converter& m_converter; unsigned m_utf16StringLength; bool m_isAllASCII; }; ... builder.append(fromUTF8(data));
Great idea.
Once we do this we could use this with makeString too, so we don’t really need String::fromUTF8 any more (although of course we can keep it); using it with makeString is more flexible.
<rdar://problem/79888871>
Created attachment 432888 [details] Patch