Skip to content

Commit

Permalink
update struct_json and struct_xml (#289)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored May 19, 2023
1 parent 81a6812 commit f05e5c9
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 162 deletions.
7 changes: 3 additions & 4 deletions thirdparty/iguana/iguana/detail/dragonbox_to_chars.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,8 @@ JKJ_FORCEINLINE static void print_9_digits(std::uint32_t s32, int &exponent,
}

template <>
char *to_chars<float, default_float_traits<float>>(std::uint32_t s32,
int exponent,
char *buffer) noexcept {
inline char *to_chars<float, default_float_traits<float>>(
std::uint32_t s32, int exponent, char *buffer) noexcept {
// Print significand.
print_9_digits(s32, exponent, buffer);

Expand Down Expand Up @@ -317,7 +316,7 @@ char *to_chars<float, default_float_traits<float>>(std::uint32_t s32,
}

template <>
char *to_chars<double, default_float_traits<double>>(
inline char *to_chars<double, default_float_traits<double>>(
std::uint64_t const significand, int exponent, char *buffer) noexcept {
// Print significand by decomposing it into a 9-digit block and a 8-digit
// block.
Expand Down
2 changes: 1 addition & 1 deletion thirdparty/iguana/iguana/error_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class iguana_dom_category : public std::error_category {
std::map<iguana::dom_errc, std::string> detail_msg_map_;
};

iguana::iguana_dom_category &dom_category() {
inline iguana::iguana_dom_category &dom_category() {
static iguana::iguana_dom_category instance;
return instance;
}
Expand Down
191 changes: 106 additions & 85 deletions thirdparty/iguana/iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,18 @@ concept num_t = std::floating_point<std::decay_t<T>> || int_t<T>;
template <class T>
concept enum_type_t = std::is_enum_v<std::decay_t<T>>;

template <typename T>
constexpr inline bool is_basic_string_view = false;

template <typename T>
constexpr inline bool is_basic_string_view<std::basic_string_view<T>> = true;

template <typename T>
concept str_view_t = is_basic_string_view<std::remove_reference_t<T>>;

template <class T>
concept str_t = std::convertible_to<std::decay_t<T>, std::string_view>;
concept str_t =
std::convertible_to<std::decay_t<T>, std::string_view> && !str_view_t<T>;

template <typename Type>
constexpr inline bool is_std_vector_v = false;
Expand Down Expand Up @@ -122,6 +132,44 @@ template <refletable T, typename It>
void from_json(T &value, It &&it, It &&end);

namespace detail {

template <str_t U, class It>
IGUANA_INLINE void parse_escape(U &value, It &&it, It &&end) {
if (it == end)
throw std::runtime_error(R"(Expected ")");
if (*it == 'u') {
++it;
if (std::distance(it, end) <= 4)
throw std::runtime_error(R"(Expected 4 hexadecimal digits)");
auto code_point = parse_unicode_hex4(it);
encode_utf8(value, code_point);
}
else if (*it == 'n') {
++it;
value.push_back('\n');
}
else if (*it == 't') {
++it;
value.push_back('\t');
}
else if (*it == 'r') {
++it;
value.push_back('\r');
}
else if (*it == 'b') {
++it;
value.push_back('\b');
}
else if (*it == 'f') {
++it;
value.push_back('\f');
}
else {
value.push_back(*it); // add the escaped character
++it;
}
}

template <refletable U, class It>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
from_json(value, it, end);
Expand Down Expand Up @@ -181,47 +229,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) {
skip_ws(it, end);
match<'"'>(it, end);
}

if constexpr (!std::contiguous_iterator<std::decay_t<It>>) {
const auto cend = value.cend();
for (auto c = value.begin(); c < cend; ++c, ++it) {
if (it == end) [[unlikely]]
throw std::runtime_error(R"(Expected ")");
switch (*it) {
[[unlikely]] case '\\' : {
if (++it == end) [[unlikely]]
throw std::runtime_error(R"(Expected ")");
else [[likely]] {
*c = *it;
}
break;
}
[[unlikely]] case '"' : {
++it;
value.resize(std::distance(value.begin(), c));
return;
}
[[unlikely]] case 'u' : {
++it;
auto start = it;
auto code_point = parse_unicode_hex4(it);
std::string str;
encode_utf8(str, code_point);
std::memcpy(value.data(), str.data(), str.size());
--it;
c += std::distance(start, it) - 1;

break;
}
[[likely]] default : *c = *it;
}
}
}

// growth portion
value.clear();
if constexpr (std::contiguous_iterator<std::decay_t<It>>) {
value.clear(); // Single append on unescaped strings so overwrite opt isnt
// as important
auto start = it;
while (it < end) {
skip_till_escape_or_qoute(it, end);
Expand All @@ -232,50 +241,55 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) {
}
else {
// Must be an escape
// TODO propperly handle this
value.append(&*start, static_cast<size_t>(std::distance(start, it)));
++it; // skip first escape
if (*it == 'u') {
++it;
auto code_point = parse_unicode_hex4(it);
encode_utf8(value, code_point);
start = it;
}
else {
value.push_back(*it); // add the escaped character
++it;
start = it;
}
parse_escape(value, it, end);
start = it;
}
}
}
else {
while (it != end) {
switch (*it) {
[[unlikely]] case '\\' : {
if (++it == end) [[unlikely]]
throw std::runtime_error(R"(Expected ")");
else [[likely]] {
value.push_back(*it);
}
++it;
parse_escape(value, it, end);
break;
}
[[unlikely]] case ']' : { return; }
[[unlikely]] case '"' : {
++it;
return;
}
[[unlikely]] case 'u' : {
[[likely]] default : {
value.push_back(*it);
++it;
auto code_point = parse_unicode_hex4(it);
encode_utf8(value, code_point);
break;
}
[[likely]] default : value.push_back(*it);
}
}
}
}

template <str_view_t U, class It>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, bool skip = false) {
static_assert(std::contiguous_iterator<std::decay_t<It>>,
"must be contiguous");
if (!skip) {
skip_ws(it, end);
match<'"'>(it, end);
}
using T = std::decay_t<U>;
auto start = it;
while (it < end) {
skip_till_escape_or_qoute(it, end);
if (*it == '"') {
value = T(&*start, static_cast<size_t>(std::distance(start, it)));
++it;
return;
}
it += 2;
}
throw std::runtime_error("Expected \""); // is needed?
}

template <fixed_array U, class It>
Expand Down Expand Up @@ -350,6 +364,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
template <map_container U, class It>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
using T = std::remove_reference_t<U>;
using key_type = typename T::key_type;
skip_ws(it, end);

match<'{'>(it, end);
Expand All @@ -366,17 +381,17 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
match<','>(it, end);
}

static thread_local std::string key{};
static thread_local std::string_view key{};
parse_item(key, it, end);

skip_ws(it, end);
match<':'>(it, end);

if constexpr (std::is_same_v<typename T::key_type, std::string>) {
parse_item(value[key], it, end);
if constexpr (str_t<key_type> || str_view_t<key_type>) {
parse_item(value[key_type(key)], it, end);
}
else {
static thread_local typename T::key_type key_value{};
static thread_local key_type key_value{};
parse_item(key_value, key.begin(), key.end());
parse_item(value[key_value], it, end);
}
Expand Down Expand Up @@ -456,7 +471,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
else {
using value_type = typename T::value_type;
value_type t;
if constexpr (str_t<value_type>) {
if constexpr (str_t<value_type> || str_view_t<value_type>) {
parse_item(t, it, end, true);
}
else {
Expand Down Expand Up @@ -558,7 +573,7 @@ IGUANA_INLINE void from_json(T &value, It &&it, It &&end) {
}
else {
static thread_local std::string static_key{};
detail::parse_item(static_key, it, end, true);
detail::parse_item(static_key, it, end, false);
key = static_key;
}

Expand Down Expand Up @@ -643,10 +658,10 @@ IGUANA_INLINE void from_json(T &value, const Byte *data, size_t size,
}
}

template <typename It>
template <bool Is_view = false, typename It>
void parse(jvalue &result, It &&it, It &&end);

template <typename It>
template <bool Is_view = false, typename It>
inline void parse_array(jarray &result, It &&it, It &&end) {
skip_ws(it, end);
match<'['>(it, end);
Expand All @@ -660,7 +675,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) {
}
result.emplace_back();

parse(result.back(), it, end);
parse<Is_view>(result.back(), it, end);

if (*it == ']') [[unlikely]] {
++it;
Expand All @@ -672,7 +687,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) {
throw std::runtime_error("Expected ]");
}

template <typename It>
template <bool Is_view = false, typename It>
inline void parse_object(jobject &result, It &&it, It &&end) {
skip_ws(it, end);
match<'{'>(it, end);
Expand All @@ -696,7 +711,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) {

match<':'>(it, end);

parse(emplaced.first->second, it, end);
parse<Is_view>(emplaced.first->second, it, end);

if (*it == '}') [[unlikely]] {
++it;
Expand All @@ -707,7 +722,7 @@ inline void parse_object(jobject &result, It &&it, It &&end) {
}
}

template <typename It>
template <bool Is_view, typename It>
inline void parse(jvalue &result, It &&it, It &&end) {
skip_ws(it, end);
switch (*it) {
Expand Down Expand Up @@ -740,16 +755,22 @@ inline void parse(jvalue &result, It &&it, It &&end) {
break;
}
case '"':
result.template emplace<std::string>();
detail::parse_item(std::get<std::string>(result), it, end);
if constexpr (Is_view) {
result.template emplace<std::string_view>();
detail::parse_item(std::get<std::string_view>(result), it, end);
}
else {
result.template emplace<std::string>();
detail::parse_item(std::get<std::string>(result), it, end);
}
break;
case '[':
result.template emplace<jarray>();
parse_array(std::get<jarray>(result), it, end);
parse_array<Is_view>(std::get<jarray>(result), it, end);
break;
case '{': {
result.template emplace<jobject>();
parse_object(std::get<jobject>(result), it, end);
parse_object<Is_view>(std::get<jobject>(result), it, end);
break;
}
default:
Expand All @@ -759,26 +780,26 @@ inline void parse(jvalue &result, It &&it, It &&end) {
skip_ws(it, end);
}

template <typename It>
template <bool Is_view = false, typename It>
inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) {
try {
parse(result, it, end);
parse<Is_view>(result, it, end);
ec = {};
} catch (const std::runtime_error &e) {
result.template emplace<std::nullptr_t>();
ec = iguana::make_error_code(e.what());
}
}

template <typename T, json_view View>
template <bool Is_view = false, typename T, json_view View>
inline void parse(T &result, const View &view) {
parse(result, std::begin(view), std::end(view));
parse<Is_view>(result, std::begin(view), std::end(view));
}

template <typename T, json_view View>
template <bool Is_view = false, typename T, json_view View>
inline void parse(T &result, const View &view, std::error_code &ec) noexcept {
try {
parse(result, view);
parse<Is_view>(result, view);
ec = {};
} catch (std::runtime_error &e) {
ec = iguana::make_error_code(e.what());
Expand Down
Loading

0 comments on commit f05e5c9

Please sign in to comment.