Skip to content

Commit 32d9ae2

Browse files
committed
JSONWriter deals in StringRefs instead of std::strings
Together with liberal use of `_sr` UDL to compile-time convert string literals into StringRefs, this will reduce the number of allocation and remove most of the strcpy calls inherent in converting string lits into `std::string`s.
1 parent de7ba4e commit 32d9ae2

File tree

4 files changed

+118
-127
lines changed

4 files changed

+118
-127
lines changed

src/catch2/internal/catch_jsonwriter.cpp

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Catch {
2929
JsonObjectWriter::JsonObjectWriter( std::ostream& os,
3030
std::uint64_t indent_level ):
3131
m_os{ os }, m_indent_level{ indent_level } {
32-
m_os << "{";
32+
m_os << '{';
3333
}
3434
JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ):
3535
m_os{ source.m_os },
@@ -47,11 +47,11 @@ namespace Catch {
4747
m_os << '}';
4848
}
4949

50-
JsonValueWriter JsonObjectWriter::write( std::string const& key ) {
50+
JsonValueWriter JsonObjectWriter::write( StringRef key ) {
5151
JsonUtils::appendCommaNewline(
5252
m_os, m_should_comma, m_indent_level + 1 );
5353

54-
m_os << '"' << key << '"' << ": ";
54+
m_os << '"' << key << "\": ";
5555
return JsonValueWriter{ m_os, m_indent_level + 1 };
5656
}
5757

@@ -60,7 +60,7 @@ namespace Catch {
6060
JsonArrayWriter::JsonArrayWriter( std::ostream& os,
6161
std::uint64_t indent_level ):
6262
m_os{ os }, m_indent_level{ indent_level } {
63-
m_os << "[";
63+
m_os << '[';
6464
}
6565
JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ):
6666
m_os{ source.m_os },
@@ -108,8 +108,41 @@ namespace Catch {
108108
return JsonArrayWriter{ m_os, m_indent_level };
109109
}
110110

111+
void JsonValueWriter::write( Catch::StringRef value ) && {
112+
writeImpl( value, true );
113+
}
114+
111115
void JsonValueWriter::write( bool value ) && {
112-
writeImpl( value ? "true" : "false", false );
116+
writeImpl( value ? "true"_sr : "false"_sr, false );
117+
}
118+
119+
void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
120+
if ( quote ) { m_os << '"'; }
121+
for (char c : value) {
122+
// Escape list taken from https://www.json.org/json-en.html,
123+
// string definition.
124+
// Note that while forward slash _can_ be escaped, it does
125+
// not have to be, if JSON is not further embedded somewhere
126+
// where forward slash is meaningful.
127+
if ( c == '"' ) {
128+
m_os << "\\\"";
129+
} else if ( c == '\\' ) {
130+
m_os << "\\\\";
131+
} else if ( c == '\b' ) {
132+
m_os << "\\b";
133+
} else if ( c == '\f' ) {
134+
m_os << "\\f";
135+
} else if ( c == '\n' ) {
136+
m_os << "\\n";
137+
} else if ( c == '\r' ) {
138+
m_os << "\\r";
139+
} else if ( c == '\t' ) {
140+
m_os << "\\t";
141+
} else {
142+
m_os << c;
143+
}
144+
}
145+
if ( quote ) { m_os << '"'; }
113146
}
114147

115148
} // namespace Catch

src/catch2/internal/catch_jsonwriter.hpp

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,45 +37,26 @@ namespace Catch {
3737
void write( T const& value ) && {
3838
writeImpl( value, !std::is_arithmetic<T>::value );
3939
}
40-
40+
void write( StringRef value ) &&;
4141
void write( bool value ) &&;
4242

4343
private:
44-
template <typename T>
44+
void writeImpl( StringRef value, bool quote );
45+
46+
// Without this SFINAE, this overload is a better match
47+
// for `std::string`, `char const*`, `char const[N]` args.
48+
// While it would still work, it would cause code bloat
49+
// and multiple iteration over the strings
50+
template <typename T,
51+
typename = typename std::enable_if_t<
52+
!std::is_convertible<T, StringRef>::value>>
4553
void writeImpl( T const& value, bool quote_value ) {
46-
if ( quote_value ) { m_os << '"'; }
4754
m_sstream << value;
48-
while ( true ) {
49-
char c = m_sstream.get();
50-
if ( m_sstream.eof() ) { break; }
51-
52-
// see https://www.json.org/json-en.html, string definition for the escape list
53-
if ( c == '"' ) {
54-
m_os << "\\\"";
55-
} else if ( c == '\\' ) {
56-
m_os << "\\\\";
57-
// Note that while forward slash _can_ be escaped, it
58-
// does not have to be, if JSON is not further embedded
59-
// somewhere where forward slash is meaningful.
60-
} else if ( c == '\b' ) {
61-
m_os << "\\b";
62-
} else if ( c == '\f' ) {
63-
m_os << "\\f";
64-
} else if ( c == '\n' ) {
65-
m_os << "\\n";
66-
} else if ( c == '\r' ) {
67-
m_os << "\\r";
68-
} else if ( c == '\t') {
69-
m_os << "\\t";
70-
} else {
71-
m_os << c;
72-
}
73-
}
74-
if ( quote_value ) { m_os << '"'; }
55+
writeImpl( m_sstream.str(), quote_value );
7556
}
7657

7758
std::ostream& m_os;
78-
std::stringstream m_sstream{};
59+
std::stringstream m_sstream;
7960
std::uint64_t m_indent_level;
8061
};
8162

@@ -89,7 +70,7 @@ namespace Catch {
8970

9071
~JsonObjectWriter();
9172

92-
JsonValueWriter write( std::string const& key );
73+
JsonValueWriter write( StringRef key );
9374

9475
private:
9576
std::ostream& m_os;

0 commit comments

Comments
 (0)