Improve XmlWriter::writeAttribute overload set for string-like types

Previously, string literals and `std::string`s would match the
template variant, which would serialize them into a stream and then
call the `StringRef` overload for resulting string. This caused
bunch of codebloat and unnecessary pessimization for common usage.
This commit is contained in:
Martin Hořeňovský 2021-05-30 13:05:07 +02:00
parent d9f72868b2
commit 41ad0fda11
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
2 changed files with 36 additions and 7 deletions

View File

@ -217,6 +217,14 @@ namespace {
return *this; return *this;
} }
XmlWriter::ScopedElement&
XmlWriter::ScopedElement::writeAttribute( StringRef name,
StringRef attribute ) {
m_writer->writeAttribute( name, attribute );
return *this;
}
XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
{ {
writeDeclaration(); writeDeclaration();
@ -276,7 +284,13 @@ namespace {
} }
XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) { XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; writeAttribute(name, (attribute ? "true"_sr : "false"_sr));
return *this;
}
XmlWriter& XmlWriter::writeAttribute( StringRef name,
char const* attribute ) {
writeAttribute( name, StringRef( attribute ) );
return *this; return *this;
} }

View File

@ -61,7 +61,15 @@ namespace Catch {
XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting fmt = XmlFormatting::Newline |
XmlFormatting::Indent ); XmlFormatting::Indent );
template<typename T> ScopedElement& writeAttribute( StringRef name,
StringRef attribute );
template <typename T,
// Without this SFINAE, this overload is a better match
// for `std::string`, `char const*`, `char const[N]` args.
// While it would still work, it would cause code bloat
// and multiple iteration over the strings
typename = typename std::enable_if_t<
!std::is_convertible<T, StringRef>::value>>
ScopedElement& writeAttribute( StringRef name, ScopedElement& writeAttribute( StringRef name,
T const& attribute ) { T const& attribute ) {
m_writer->writeAttribute( name, attribute ); m_writer->writeAttribute( name, attribute );
@ -91,15 +99,22 @@ namespace Catch {
//! Writes the attribute as "true/false" //! Writes the attribute as "true/false"
XmlWriter& writeAttribute( StringRef name, bool attribute ); XmlWriter& writeAttribute( StringRef name, bool attribute );
//! The attribute value must provide op<<(ostream&, T). Resulting //! The attribute content is XML-encoded
XmlWriter& writeAttribute( StringRef name, char const* attribute );
//! The attribute value must provide op<<(ostream&, T). The resulting
//! serialization is XML-encoded //! serialization is XML-encoded
template<typename T> template <typename T,
// Without this SFINAE, this overload is a better match
// for `std::string`, `char const*`, `char const[N]` args.
// While it would still work, it would cause code bloat
// and multiple iteration over the strings
typename = typename std::enable_if_t<
!std::is_convertible<T, StringRef>::value>>
XmlWriter& writeAttribute( StringRef name, T const& attribute ) { XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
ReusableStringStream rss; ReusableStringStream rss;
rss << attribute; rss << attribute;
// We need to explicitly convert the string to StringRef to return writeAttribute( name, rss.str() );
// guarantee the right overload is picked
return writeAttribute( name, StringRef(rss.str()) );
} }
XmlWriter& writeText( StringRef text, XmlWriter& writeText( StringRef text,