1 | #ifndef SIMDJSON_INTERNAL_JSONFORMATUTILS_H |
---|---|
2 | #define SIMDJSON_INTERNAL_JSONFORMATUTILS_H |
3 | |
4 | #include <iomanip> |
5 | #include <ostream> |
6 | #include <sstream> |
7 | |
8 | namespace simdjson { |
9 | namespace internal { |
10 | |
11 | class escape_json_string; |
12 | |
13 | inline std::ostream& operator<<(std::ostream& out, const escape_json_string &str); |
14 | |
15 | class escape_json_string { |
16 | public: |
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(); } |
19 | private: |
20 | std::string_view str; |
21 | friend std::ostream& operator<<(std::ostream& out, const escape_json_string &unescaped); |
22 | }; |
23 | |
24 | inline 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 |