1#ifndef SIMDJSON_INTERNAL_JSONFORMATUTILS_H
2#define SIMDJSON_INTERNAL_JSONFORMATUTILS_H
3
4#include <iomanip>
5#include <ostream>
6#include <sstream>
7
8namespace simdjson {
9namespace internal {
10
11class escape_json_string;
12
13inline std::ostream& operator<<(std::ostream& out, const escape_json_string &str);
14
15class escape_json_string {
16public:
17 escape_json_string(std::string_view _str) noexcept : str{_str} {}
18 operator std::string() const noexcept { std::stringstream s; s << *this; return s.str(); }
19private:
20 std::string_view str;
21 friend std::ostream& operator<<(std::ostream& out, const escape_json_string &unescaped);
22};
23
24inline std::ostream& operator<<(std::ostream& out, const escape_json_string &unescaped) {
25 for (size_t i=0; i<unescaped.str.length(); i++) {
26 switch (unescaped.str[i]) {
27 case '\b':
28 out << "\\b";
29 break;
30 case '\f':
31 out << "\\f";
32 break;
33 case '\n':
34 out << "\\n";
35 break;
36 case '\r':
37 out << "\\r";
38 break;
39 case '\"':
40 out << "\\\"";
41 break;
42 case '\t':
43 out << "\\t";
44 break;
45 case '\\':
46 out << "\\\\";
47 break;
48 default:
49 if (static_cast<unsigned char>(unescaped.str[i]) <= 0x1F) {
50 // TODO can this be done once at the beginning, or will it mess up << char?
51 std::ios::fmtflags f(out.flags());
52 out << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(unescaped.str[i]);
53 out.flags(fmtfl: f);
54 } else {
55 out << unescaped.str[i];
56 }
57 }
58 }
59 return out;
60}
61
62} // namespace internal
63} // namespace simdjson
64
65#endif // SIMDJSON_INTERNAL_JSONFORMATUTILS_H
66