Skip to content

Commit 7470c2d

Browse files
Daniel Levinjbeder
Daniel Levin
authored andcommitted
emitter: Support std::string_view
Accept Emitter::operator<<(std::string_view). ABI remains C++11 compatible by exposing new method Emitter::Write(const char*, size_t). All affected calls optimized to pass std::string values as pointer + size tuple into appropriate routines.
1 parent 8a9a7b7 commit 7470c2d

File tree

9 files changed

+107
-60
lines changed

9 files changed

+107
-60
lines changed

include/yaml-cpp/emitter.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99

1010
#include <cmath>
1111
#include <cstddef>
12+
#include <cstring>
1213
#include <limits>
1314
#include <memory>
1415
#include <sstream>
1516
#include <string>
1617
#include <type_traits>
1718

19+
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
20+
#include <string_view>
21+
#endif
22+
1823
#include "yaml-cpp/binary.h"
1924
#include "yaml-cpp/dll.h"
2025
#include "yaml-cpp/emitterdef.h"
@@ -68,6 +73,7 @@ class YAML_CPP_API Emitter {
6873
Emitter& SetLocalPrecision(const _Precision& precision);
6974

7075
// overloads of write
76+
Emitter& Write(const char* str, std::size_t size);
7177
Emitter& Write(const std::string& str);
7278
Emitter& Write(bool b);
7379
Emitter& Write(char ch);
@@ -201,8 +207,13 @@ inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
201207
}
202208

203209
// overloads of insertion
210+
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
211+
inline Emitter& operator<<(Emitter& emitter, const std::string_view& v) {
212+
return emitter.Write(v.data(), v.size());
213+
}
214+
#endif
204215
inline Emitter& operator<<(Emitter& emitter, const std::string& v) {
205-
return emitter.Write(v);
216+
return emitter.Write(v.data(), v.size());
206217
}
207218
inline Emitter& operator<<(Emitter& emitter, bool v) {
208219
return emitter.Write(v);
@@ -233,7 +244,7 @@ inline Emitter& operator<<(Emitter& emitter, const Binary& b) {
233244
}
234245

235246
inline Emitter& operator<<(Emitter& emitter, const char* v) {
236-
return emitter.Write(std::string(v));
247+
return emitter.Write(v, std::strlen(v));
237248
}
238249

239250
inline Emitter& operator<<(Emitter& emitter, int v) {

include/yaml-cpp/null.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#endif
99

1010
#include "yaml-cpp/dll.h"
11-
#include <string>
11+
#include <cstddef>
1212

1313
namespace YAML {
1414
class Node;
@@ -18,7 +18,7 @@ inline bool operator==(const _Null&, const _Null&) { return true; }
1818
inline bool operator!=(const _Null&, const _Null&) { return false; }
1919

2020
YAML_CPP_API bool IsNull(const Node& node); // old API only
21-
YAML_CPP_API bool IsNullString(const std::string& str);
21+
YAML_CPP_API bool IsNullString(const char* str, std::size_t size);
2222

2323
extern YAML_CPP_API _Null Null;
2424
}

src/emitter.cpp

+14-10
Original file line numberDiff line numberDiff line change
@@ -716,33 +716,33 @@ StringEscaping::value GetStringEscapingStyle(const EMITTER_MANIP emitterManip) {
716716
}
717717
}
718718

719-
Emitter& Emitter::Write(const std::string& str) {
719+
Emitter& Emitter::Write(const char* str, std::size_t size) {
720720
if (!good())
721721
return *this;
722722

723723
StringEscaping::value stringEscaping = GetStringEscapingStyle(m_pState->GetOutputCharset());
724724

725725
const StringFormat::value strFormat =
726-
Utils::ComputeStringFormat(str, m_pState->GetStringFormat(),
726+
Utils::ComputeStringFormat(str, size, m_pState->GetStringFormat(),
727727
m_pState->CurGroupFlowType(), stringEscaping == StringEscaping::NonAscii);
728728

729-
if (strFormat == StringFormat::Literal || str.size() > 1024)
729+
if (strFormat == StringFormat::Literal || size > 1024)
730730
m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);
731731

732732
PrepareNode(EmitterNodeType::Scalar);
733733

734734
switch (strFormat) {
735735
case StringFormat::Plain:
736-
m_stream << str;
736+
m_stream.write(str, size);
737737
break;
738738
case StringFormat::SingleQuoted:
739-
Utils::WriteSingleQuotedString(m_stream, str);
739+
Utils::WriteSingleQuotedString(m_stream, str, size);
740740
break;
741741
case StringFormat::DoubleQuoted:
742-
Utils::WriteDoubleQuotedString(m_stream, str, stringEscaping);
742+
Utils::WriteDoubleQuotedString(m_stream, str, size, stringEscaping);
743743
break;
744744
case StringFormat::Literal:
745-
Utils::WriteLiteralString(m_stream, str,
745+
Utils::WriteLiteralString(m_stream, str, size,
746746
m_pState->CurIndent() + m_pState->GetIndent());
747747
break;
748748
}
@@ -752,6 +752,10 @@ Emitter& Emitter::Write(const std::string& str) {
752752
return *this;
753753
}
754754

755+
Emitter& Emitter::Write(const std::string& str) {
756+
return Write(str.data(), str.size());
757+
}
758+
755759
std::size_t Emitter::GetFloatPrecision() const {
756760
return m_pState->GetFloatPrecision();
757761
}
@@ -865,7 +869,7 @@ Emitter& Emitter::Write(const _Alias& alias) {
865869

866870
PrepareNode(EmitterNodeType::Scalar);
867871

868-
if (!Utils::WriteAlias(m_stream, alias.content)) {
872+
if (!Utils::WriteAlias(m_stream, alias.content.data(), alias.content.size())) {
869873
m_pState->SetError(ErrorMsg::INVALID_ALIAS);
870874
return *this;
871875
}
@@ -888,7 +892,7 @@ Emitter& Emitter::Write(const _Anchor& anchor) {
888892

889893
PrepareNode(EmitterNodeType::Property);
890894

891-
if (!Utils::WriteAnchor(m_stream, anchor.content)) {
895+
if (!Utils::WriteAnchor(m_stream, anchor.content.data(), anchor.content.size())) {
892896
m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
893897
return *this;
894898
}
@@ -937,7 +941,7 @@ Emitter& Emitter::Write(const _Comment& comment) {
937941

938942
if (m_stream.col() > 0)
939943
m_stream << Indentation(m_pState->GetPreCommentIndent());
940-
Utils::WriteComment(m_stream, comment.content,
944+
Utils::WriteComment(m_stream, comment.content.data(), comment.content.size(),
941945
m_pState->GetPostCommentIndent());
942946

943947
m_pState->SetNonContent();

src/emitterutils.cpp

+36-35
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ int Utf8BytesIndicated(char ch) {
8989
bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; }
9090

9191
bool GetNextCodePointAndAdvance(int& codePoint,
92-
std::string::const_iterator& first,
93-
std::string::const_iterator last) {
92+
const char*& first,
93+
const char* last) {
9494
if (first == last)
9595
return false;
9696

@@ -153,23 +153,23 @@ void WriteCodePoint(ostream_wrapper& out, int codePoint) {
153153
}
154154
}
155155

156-
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
156+
bool IsValidPlainScalar(const char* str, std::size_t size, FlowType::value flowType,
157157
bool allowOnlyAscii) {
158158
// check against null
159-
if (IsNullString(str)) {
159+
if (IsNullString(str, size)) {
160160
return false;
161161
}
162162

163163
// check the start
164164
const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow()
165165
: Exp::PlainScalar());
166-
if (!start.Matches(str)) {
166+
if (!start.Matches(StringCharSource(str, size))) {
167167
return false;
168168
}
169169

170170
// and check the end for plain whitespace (which can't be faithfully kept in a
171171
// plain scalar)
172-
if (!str.empty() && *str.rbegin() == ' ') {
172+
if (size != 0 && str[size - 1] == ' ') {
173173
return false;
174174
}
175175

@@ -185,7 +185,7 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
185185
const RegEx& disallowed =
186186
flowType == FlowType::Flow ? disallowed_flow : disallowed_block;
187187

188-
StringCharSource buffer(str.c_str(), str.size());
188+
StringCharSource buffer(str, size);
189189
while (buffer) {
190190
if (disallowed.Matches(buffer)) {
191191
return false;
@@ -199,22 +199,22 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
199199
return true;
200200
}
201201

202-
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) {
202+
bool IsValidSingleQuotedScalar(const char* str, std::size_t size, bool escapeNonAscii) {
203203
// TODO: check for non-printable characters?
204-
return std::none_of(str.begin(), str.end(), [=](char ch) {
204+
return std::none_of(str, str + size, [=](char ch) {
205205
return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch))) ||
206206
(ch == '\n');
207207
});
208208
}
209209

210-
bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType,
210+
bool IsValidLiteralScalar(const char* str, std::size_t size, FlowType::value flowType,
211211
bool escapeNonAscii) {
212212
if (flowType == FlowType::Flow) {
213213
return false;
214214
}
215215

216216
// TODO: check for non-printable characters?
217-
return std::none_of(str.begin(), str.end(), [=](char ch) {
217+
return std::none_of(str, str + size, [=](char ch) {
218218
return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch)));
219219
});
220220
}
@@ -254,10 +254,10 @@ void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint, StringE
254254
out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
255255
}
256256

257-
bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
257+
bool WriteAliasName(ostream_wrapper& out, const char* str, std::size_t size) {
258258
int codePoint;
259-
for (std::string::const_iterator i = str.begin();
260-
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
259+
for (const char* i = str;
260+
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
261261
if (!IsAnchorChar(codePoint)) {
262262
return false;
263263
}
@@ -268,25 +268,25 @@ bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
268268
}
269269
} // namespace
270270

271-
StringFormat::value ComputeStringFormat(const std::string& str,
271+
StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
272272
EMITTER_MANIP strFormat,
273273
FlowType::value flowType,
274274
bool escapeNonAscii) {
275275
switch (strFormat) {
276276
case Auto:
277-
if (IsValidPlainScalar(str, flowType, escapeNonAscii)) {
277+
if (IsValidPlainScalar(str, size, flowType, escapeNonAscii)) {
278278
return StringFormat::Plain;
279279
}
280280
return StringFormat::DoubleQuoted;
281281
case SingleQuoted:
282-
if (IsValidSingleQuotedScalar(str, escapeNonAscii)) {
282+
if (IsValidSingleQuotedScalar(str, size, escapeNonAscii)) {
283283
return StringFormat::SingleQuoted;
284284
}
285285
return StringFormat::DoubleQuoted;
286286
case DoubleQuoted:
287287
return StringFormat::DoubleQuoted;
288288
case Literal:
289-
if (IsValidLiteralScalar(str, flowType, escapeNonAscii)) {
289+
if (IsValidLiteralScalar(str, size, flowType, escapeNonAscii)) {
290290
return StringFormat::Literal;
291291
}
292292
return StringFormat::DoubleQuoted;
@@ -297,11 +297,11 @@ StringFormat::value ComputeStringFormat(const std::string& str,
297297
return StringFormat::DoubleQuoted;
298298
}
299299

300-
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
300+
bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size) {
301301
out << "'";
302302
int codePoint;
303-
for (std::string::const_iterator i = str.begin();
304-
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
303+
for (const char* i = str;
304+
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
305305
if (codePoint == '\n') {
306306
return false; // We can't handle a new line and the attendant indentation
307307
// yet
@@ -317,12 +317,12 @@ bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
317317
return true;
318318
}
319319

320-
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
320+
bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
321321
StringEscaping::value stringEscaping) {
322322
out << "\"";
323323
int codePoint;
324-
for (std::string::const_iterator i = str.begin();
325-
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
324+
for (const char* i = str;
325+
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
326326
switch (codePoint) {
327327
case '\"':
328328
out << "\\\"";
@@ -364,12 +364,12 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
364364
return true;
365365
}
366366

367-
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
367+
bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
368368
std::size_t indent) {
369369
out << "|\n";
370370
int codePoint;
371-
for (std::string::const_iterator i = str.begin();
372-
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
371+
for (const char* i = str;
372+
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
373373
if (codePoint == '\n') {
374374
out << "\n";
375375
} else {
@@ -407,14 +407,14 @@ bool WriteChar(ostream_wrapper& out, char ch, StringEscaping::value stringEscapi
407407
return true;
408408
}
409409

410-
bool WriteComment(ostream_wrapper& out, const std::string& str,
410+
bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
411411
std::size_t postCommentIndent) {
412412
const std::size_t curIndent = out.col();
413413
out << "#" << Indentation(postCommentIndent);
414414
out.set_comment();
415415
int codePoint;
416-
for (std::string::const_iterator i = str.begin();
417-
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
416+
for (const char* i = str;
417+
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
418418
if (codePoint == '\n') {
419419
out << "\n"
420420
<< IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
@@ -426,14 +426,14 @@ bool WriteComment(ostream_wrapper& out, const std::string& str,
426426
return true;
427427
}
428428

429-
bool WriteAlias(ostream_wrapper& out, const std::string& str) {
429+
bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size) {
430430
out << "*";
431-
return WriteAliasName(out, str);
431+
return WriteAliasName(out, str, size);
432432
}
433433

434-
bool WriteAnchor(ostream_wrapper& out, const std::string& str) {
434+
bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size) {
435435
out << "&";
436-
return WriteAliasName(out, str);
436+
return WriteAliasName(out, str, size);
437437
}
438438

439439
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim) {
@@ -490,7 +490,8 @@ bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
490490
}
491491

492492
bool WriteBinary(ostream_wrapper& out, const Binary& binary) {
493-
WriteDoubleQuotedString(out, EncodeBase64(binary.data(), binary.size()),
493+
std::string encoded = EncodeBase64(binary.data(), binary.size());
494+
WriteDoubleQuotedString(out, encoded.data(), encoded.size(),
494495
StringEscaping::None);
495496
return true;
496497
}

src/emitterutils.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ struct StringEscaping {
2929
};
3030

3131
namespace Utils {
32-
StringFormat::value ComputeStringFormat(const std::string& str,
32+
StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
3333
EMITTER_MANIP strFormat,
3434
FlowType::value flowType,
3535
bool escapeNonAscii);
3636

37-
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str);
38-
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
37+
bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size);
38+
bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
3939
StringEscaping::value stringEscaping);
40-
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
40+
bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
4141
std::size_t indent);
4242
bool WriteChar(ostream_wrapper& out, char ch,
4343
StringEscaping::value stringEscapingStyle);
44-
bool WriteComment(ostream_wrapper& out, const std::string& str,
44+
bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
4545
std::size_t postCommentIndent);
46-
bool WriteAlias(ostream_wrapper& out, const std::string& str);
47-
bool WriteAnchor(ostream_wrapper& out, const std::string& str);
46+
bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size);
47+
bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size);
4848
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim);
4949
bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
5050
const std::string& tag);

0 commit comments

Comments
 (0)