yalantinglibs/include/ylt/standalone/iguana/prettify.hpp

144 lines
2.9 KiB
C++

#pragma once
// https://github.com/stephenberry/glaze/blob/main/include/glaze/json/prettify.hpp
namespace iguana {
namespace detail {
enum class general_state : uint32_t {
NORMAL,
ESCAPED,
STRING,
BEFORE_ASTERISK,
COMMENT,
BEFORE_FSLASH
};
template <typename Out, typename NL>
inline void prettify_normal_state(const char c, Out &out, uint32_t &indent,
NL nl, general_state &state) noexcept {
switch (c) {
case ',':
out += c;
nl();
break;
case '[':
out += c;
++indent;
nl();
break;
case ']':
--indent;
nl();
out += c;
break;
case '{':
out += c;
++indent;
nl();
break;
case '}':
--indent;
nl();
out += c;
break;
case '\\':
out += c;
state = general_state::ESCAPED;
break;
case '\"':
out += c;
state = general_state::STRING;
break;
case '/':
out += " /";
state = general_state::BEFORE_ASTERISK;
break;
case ':':
out += ": ";
break;
case ' ':
case '\n':
case '\r':
case '\t':
break;
default:
out += c;
break;
}
}
inline void prettify_other_states(const char c, general_state &state) noexcept {
switch (state) {
case general_state::ESCAPED:
state = general_state::NORMAL;
break;
case general_state::STRING:
if (c == '"') {
state = general_state::NORMAL;
}
break;
case general_state::BEFORE_ASTERISK:
state = general_state::COMMENT;
break;
case general_state::COMMENT:
if (c == '*') {
state = general_state::BEFORE_FSLASH;
}
break;
case general_state::BEFORE_FSLASH:
if (c == '/') {
state = general_state::NORMAL;
}
else {
state = general_state::COMMENT;
}
break;
default:
break;
}
}
} // namespace detail
/// <summary>
/// pretty print a JSON string
/// </summary>
template <typename In, typename Out>
inline void prettify(const In &in, Out &out, const bool tabs = false,
const uint32_t indent_size = 3) noexcept {
out.reserve(in.size());
uint32_t indent{};
auto nl = [&]() {
out += "\n";
for (uint32_t i = 0; i < indent * (tabs ? 1 : indent_size); i++) {
out += tabs ? "\t" : " ";
}
};
using namespace detail;
general_state state{general_state::NORMAL};
for (auto c : in) {
if (state == general_state::NORMAL) {
prettify_normal_state(c, out, indent, nl, state);
continue;
}
else {
out += c;
prettify_other_states(c, state);
}
}
}
/// <summary>
/// allocating version of prettify
/// </summary>
template <typename In>
inline std::string prettify(const In &in, const bool tabs = false,
const uint32_t indent_size = 3) noexcept {
std::string out{};
prettify(in, out, tabs, indent_size);
return out;
}
} // namespace iguana