Serialize JSON directly to cout

This commit is contained in:
Kovid Goyal 2023-01-24 17:34:42 +05:30
parent 61a16f78a8
commit 20f58d7211
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -105,26 +105,24 @@ parse_id(std::wstring_view const& s) {
}
static std::string
serialize_string_for_json(std::string const &src) {
std::string ans("\"");
ans.reserve(src.size() + 16);
static void
serialize_string_for_json(std::string const &src, std::ostream &out) {
out << '"';
for (auto ch : src) {
switch(ch) {
case '\\':
ans += "\\\\"; break;
out << "\\\\"; break;
case '"':
ans += "\\\""; break;
out << "\\\""; break;
case '\n':
ans += "\\n"; break;
out << "\\n"; break;
case '\r':
ans += "\\r"; break;
out << "\\r"; break;
default:
ans += ch; break;
out << ch; break;
}
}
ans += '"';
return ans;
out << '"';
}
class json_val { // {{{
@ -181,41 +179,38 @@ public:
}
}
std::string serialize() const {
void serialize(std::ostream &out) const {
switch(type) {
case DT_NONE:
return "nil";
out << "nil"; break;
case DT_BOOL:
return b ? "true" : "false";
out << b ? "true" : "false"; break;
case DT_INT:
// this is not really correct since JS has various limits on numeric types, but good enough for us
return std::to_string(i);
out << i; break;
case DT_STRING:
return serialize_string_for_json(s);
return serialize_string_for_json(s, out);
case DT_LIST: {
std::string ans("[");
ans.reserve(list.size() * 32);
out << '[';
for (auto const &i : list) {
ans += i.serialize();
ans += ", ";
i.serialize(out);
out << ", ";
}
ans.erase(ans.size() - 2); ans += "]";
return ans;
out << ']';
break;
}
case DT_OBJECT: {
std::string ans("{");
ans.reserve(object.size() * 64);
out << '{';
for (const auto& [key, value]: object) {
ans += serialize_string_for_json(key);
ans += ": ";
ans += value.serialize();
ans += ", ";
serialize_string_for_json(key, out);
out << ": ";
value.serialize(out);
out << ", ";
}
ans.erase(ans.size() - 2); ans += "}";
return ans;
out << '}';
break;
}
}
return "";
}
}; // }}}
@ -223,7 +218,9 @@ static void
output(id_type cmd_id, std::string_view const &msg_type, json_val const &&msg) {
std::scoped_lock sl(output_lock);
try {
std::cout << cmd_id << " " << msg_type << " " << msg.serialize() << std::endl;
std::cout << cmd_id << " " << msg_type << " ";
msg.serialize(std::cout);
std::cout << std::endl;
} catch(...) {}
}
@ -704,30 +701,6 @@ class Synthesizer {
static Synthesizer sx;
static inline std::wstring
decode_utf8(std::string_view const& src) {
std::wstring ans(src.length() + 1, 0);
size_t count = MultiByteToWideChar(CP_UTF8, 0, src.data(), (int)src.length(), ans.data(), (int)ans.length());
if (count == 0) {
switch(GetLastError()) {
case ERROR_INSUFFICIENT_BUFFER:
throw std::exception("Could not convert UTF-8 to UTF-16: buffer too small");
case ERROR_INVALID_PARAMETER:
throw std::exception("Could not convert UTF-8 to UTF-16: invalid parameter");
case ERROR_NO_UNICODE_TRANSLATION:
throw std::exception("Could not convert UTF-8 to UTF-16: invalid UTF-8 encountered");
default:
throw std::exception("Could not convert UTF-8 to UTF-16: unknown error");
}
}
count++; // ensure trailing null
if (ans.length() > count) {
auto extra = ans.length() - count;
ans.erase(ans.length() - extra, extra);
}
return ans;
}
static void
handle_speak(id_type cmd_id, std::vector<std::wstring_view> &parts) {
bool is_ssml = false, is_shm = false;