IGUANA_INLINE void xml_parse_item()

in include/ylt/standalone/iguana/xml_reader.hpp [397:486]


IGUANA_INLINE void xml_parse_item(T &value, It &&it, It &&end,
                                  std::string_view name) {
  using U = std::decay_t<T>;
  constexpr auto cdata_idx = get_type_index<is_cdata_t, U>();
  skip_till<'>'>(it, end);
  ++it;
  if (skip_till_close_tag<cdata_idx>(value, it, end)) {
    match_close_tag(it, end, name);
    return;
  }
  auto start = it;
  skip_till_greater_or_space(it, end);
  std::string_view key =
      std::string_view{&*start, static_cast<size_t>(std::distance(start, it))};

  [[maybe_unused]] std::string key_set;
  bool parse_done = false;
  // sequential parse
  ylt::reflection::for_each(value, [&](auto &field, auto st_key, auto index) {
#if defined(_MSC_VER) && _MSVC_LANG < 202002L
    // seems MVSC can't pass a constexpr value to lambda
    constexpr auto cdata_idx = get_type_index<is_cdata_t, U>();
#endif
    using item_type = std::remove_reference_t<decltype(field)>;
    if constexpr (cdata_v<item_type>) {
      return;
    }
    if (parse_done || key != st_key)
      IGUANA_UNLIKELY { return; }
    if constexpr (!cdata_v<item_type>) {
      xml_parse_item(field, it, end, key);
      if constexpr (iguana::has_iguana_required_arr_v<U>) {
        key_set.append(key).append(", ");
      }
    }
    if (skip_till_close_tag<cdata_idx>(value, it, end))
      IGUANA_UNLIKELY {
        match_close_tag(it, end, name);
        parse_done = true;
        return;
      }
    start = it;
    skip_till_greater_or_space(it, end);
    key = std::string_view{&*start,
                           static_cast<size_t>(std::distance(start, it))};
  });
  if (parse_done)
    IGUANA_UNLIKELY {
      check_required<U>(key_set);
      return;
    }
  // map parse
  while (true) {
    static auto frozen_map = ylt::reflection::get_variant_map<U>();
    const auto &member_it = frozen_map.find(key);
    if (member_it != frozen_map.end())
      IGUANA_LIKELY {
        std::visit(
            [&](auto offset) IGUANA__INLINE_LAMBDA {
              using value_type = typename decltype(offset)::type;
              if constexpr (!cdata_v<value_type>) {
                auto member_ptr =
                    (value_type *)((char *)(&value) + offset.value);
                xml_parse_item(*member_ptr, it, end, key);
                if constexpr (iguana::has_iguana_required_arr_v<U>) {
                  key_set.append(key).append(", ");
                }
              }
            },
            member_it->second);
      }
    else
      IGUANA_UNLIKELY {
#ifdef THROW_UNKNOWN_KEY
        throw std::runtime_error("Unknown key: " + std::string(key));
#else
        skip_object_value(it, end, key);
#endif
      }
    if (skip_till_close_tag<cdata_idx>(value, it, end)) {
      match_close_tag(it, end, name);
      check_required<U>(key_set);
      return;
    }
    start = it;
    skip_till_greater_or_space(it, end);
    key = std::string_view{&*start,
                           static_cast<size_t>(std::distance(start, it))};
  }
}