1
0
mirror of https://github.com/catchorg/Catch2.git synced 2025-01-15 14:48:00 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Martin Hořeňovský
d9f72868b2
Use StringRef instead of std::string in XmlWriter::ScopedElement 2021-05-29 21:47:12 +02:00
Martin Hořeňovský
c7241bb76e
Use StringRef in XmLWriter when the text is not stored 2021-05-29 21:23:24 +02:00
Martin Hořeňovský
1d04427fcd
Use StringRef through XmlEncode
This introduces a potential lifetime risk when using the API, but
the intended way to use the `XmlEncode` class is to use it directly,
e.g. `out << XmlEncode(some-text-argument)`, not to store it around.

The benefit is that we avoid allocations for strings that do not fit
into SSO for given platform.
2021-05-29 16:41:57 +02:00
2 changed files with 41 additions and 18 deletions

View File

@ -77,7 +77,7 @@ namespace {
}
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
XmlEncode::XmlEncode( StringRef str, ForWhat forWhat )
: m_str( str ),
m_forWhat( forWhat )
{}
@ -211,7 +211,8 @@ namespace {
}
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
XmlWriter::ScopedElement&
XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) {
m_writer->writeText( text, fmt );
return *this;
}
@ -267,18 +268,19 @@ namespace {
return *this;
}
XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
XmlWriter& XmlWriter::writeAttribute( StringRef name,
StringRef attribute ) {
if( !name.empty() && !attribute.empty() )
m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
return *this;
}
XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
return *this;
}
XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) {
if( !text.empty() ){
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
@ -291,7 +293,7 @@ namespace {
return *this;
}
XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) {
ensureTagClosed();
if (shouldIndent(fmt)) {
m_os << m_indent;
@ -301,7 +303,7 @@ namespace {
return *this;
}
void XmlWriter::writeStylesheetRef( std::string const& url ) {
void XmlWriter::writeStylesheetRef( StringRef url ) {
m_os << R"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
}

View File

@ -9,6 +9,7 @@
#define CATCH_XMLWRITER_HPP_INCLUDED
#include <catch2/internal/catch_stream.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <vector>
@ -22,18 +23,24 @@ namespace Catch {
XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
/**
* Helper for XML-encoding text (escaping angle brackets, quotes, etc)
*
* Note: doesn't take ownership of passed strings, and thus the
* encoded string must outlive the encoding instance.
*/
class XmlEncode {
public:
enum ForWhat { ForTextNodes, ForAttributes };
XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes );
void encodeTo( std::ostream& os ) const;
friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
private:
std::string m_str;
StringRef m_str;
ForWhat m_forWhat;
};
@ -49,10 +56,14 @@ namespace Catch {
~ScopedElement();
ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
ScopedElement&
writeText( StringRef text,
XmlFormatting fmt = XmlFormatting::Newline |
XmlFormatting::Indent );
template<typename T>
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
ScopedElement& writeAttribute( StringRef name,
T const& attribute ) {
m_writer->writeAttribute( name, attribute );
return *this;
}
@ -74,22 +85,32 @@ namespace Catch {
XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
//! The attribute content is XML-encoded
XmlWriter& writeAttribute( StringRef name, StringRef attribute );
XmlWriter& writeAttribute( std::string const& name, bool attribute );
//! Writes the attribute as "true/false"
XmlWriter& writeAttribute( StringRef name, bool attribute );
//! The attribute value must provide op<<(ostream&, T). Resulting
//! serialization is XML-encoded
template<typename T>
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
ReusableStringStream rss;
rss << attribute;
return writeAttribute( name, rss.str() );
// We need to explicitly convert the string to StringRef to
// guarantee the right overload is picked
return writeAttribute( name, StringRef(rss.str()) );
}
XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeText( StringRef text,
XmlFormatting fmt = XmlFormatting::Newline |
XmlFormatting::Indent );
XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeComment( StringRef text,
XmlFormatting fmt = XmlFormatting::Newline |
XmlFormatting::Indent );
void writeStylesheetRef( std::string const& url );
void writeStylesheetRef( StringRef url );
XmlWriter& writeBlankLine();