Skip to content

Instantly share code, notes, and snippets.

@tomilov
Created January 6, 2023 22:50
Show Gist options
  • Save tomilov/a653661f165c9912d5e34638d72c064b to your computer and use it in GitHub Desktop.
Save tomilov/a653661f165c9912d5e34638d72c064b to your computer and use it in GitHub Desktop.
struct SourceCodeJsonEscape
{
const char * text;
};
template<>
struct fmt::formatter<engine::SourceCodeJsonEscape> : fmt::formatter<fmt::string_view>
{
template<typename FormatContext>
auto format(const engine::SourceCodeJsonEscape & sourceCodejsonEscape, FormatContext & ctx) const
{
auto out = ctx.out();
std::string_view text = sourceCodejsonEscape.text;
if (std::empty(text)) {
return out;
}
using namespace std::string_view_literals;
const auto append = [&out](std::string_view s) { out = std::copy_n(std::cbegin(s), std::size(s), out); };
while (!std::empty(text)) {
char c = text.front();
switch (c) {
case '\\':
append("\\\\"sv);
break;
case '"':
append("\\\""sv);
break;
case '\b':
append("\\b"sv);
break;
case '\f':
append("\\f"sv);
break;
case '\n':
append("\\n"sv);
break;
case '\r':
append("\\r"sv);
break;
case '\t':
append("\\t"sv);
break;
default: {
if (static_cast<uint8_t>(c) <= 0x1f) {
append("\\u"sv);
char buf[4] = {'0', '0', '0', '0'};
auto r = std::to_chars(std::begin(buf), std::end(buf), static_cast<uint8_t>(c), 16);
INVARIANT(r.ec == std::errc{}, "Failed to convert char('{}') to hexadecimal string of length 4", c);
std::rotate(std::begin(buf), r.ptr, std::end(buf));
append({std::data(buf), std::size(buf)});
} else if (text.starts_with("\xE2\x80\xA8"sv)) {
append("\\u2028"sv);
text.remove_prefix(3);
continue;
} else if (text.starts_with("\xE2\x80\xA9"sv)) {
append("\\u2029"sv);
text.remove_prefix(3);
continue;
} else {
*out++ = c;
}
}
}
text.remove_prefix(1);
}
return out;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment