constexpr size_info inline calculate_one_size()

in include/ylt/struct_pack/calculate_size.hpp [40:183]


constexpr size_info inline calculate_one_size(const T &item) {
  constexpr auto id = get_type_id<remove_cvref_t<T>, parent_tag>();
  static_assert(id != detail::type_id::type_end_flag);
  using type = remove_cvref_t<decltype(item)>;
  static_assert(!std::is_pointer_v<type>);
  size_info ret{};
  if constexpr (id == type_id::monostate_t) {
  }
  else if constexpr (id == type_id::user_defined_type) {
    ret.total = sp_get_needed_size(item);
  }
  else if constexpr (detail::varint_t<type, parent_tag>) {
    if constexpr (is_enable_fast_varint_coding(parent_tag)) {
      // skip it. It has been calculated in parent.
    }
    else {
      ret.total = detail::calculate_varint_size(item);
    }
  }
  else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
                     id == type_id::int128_t || id == type_id::uint128_t ||
                     id == type_id::bitset_t) {
    ret.total = sizeof(type);
  }
  else if constexpr (is_trivial_view_v<type>) {
    return calculate_one_size(item.get());
  }
  else if constexpr (id == type_id::array_t) {
    if constexpr (is_trivial_serializable<type>::value) {
      ret.total = sizeof(type);
    }
    else {
      for (auto &i : item) {
        ret += calculate_one_size(i);
      }
    }
  }
  else if constexpr (container<type>) {
    ret.size_cnt += 1;
    ret.max_size = item.size();
    if constexpr (trivially_copyable_container<type>) {
      using value_type = typename type::value_type;
      ret.total = item.size() * sizeof(value_type);
    }
    else {
      for (auto &&i : item) {
        ret += calculate_one_size(i);
      }
    }
  }
  else if constexpr (container_adapter<type>) {
    static_assert(!sizeof(type), "the container adapter type is not supported");
  }
  else if constexpr (!pair<type> && tuple<type> && !is_trivial_tuple<type>) {
    std::apply(
        [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
          ret += calculate_payload_size(items...);
        },
        item);
  }
  else if constexpr (ylt::reflection::optional<type>) {
    ret.total = sizeof(char);
    if (item) {
      ret += calculate_one_size(*item);
    }
  }
  else if constexpr (unique_ptr<type>) {
    ret.total = sizeof(char);
    if (item) {
      if constexpr (is_base_class<typename type::element_type>) {
        ret.total += sizeof(uint32_t);
        bool is_ok = false;
        auto index = search_type_by_md5<typename type::element_type>(
            item->get_struct_pack_id(), is_ok);
        if SP_UNLIKELY (!is_ok) {
          throw std::runtime_error{
              "illegal struct_pack_id in virtual function."};
        }
        ret += ylt::reflection::template_switch<
            calculate_one_size_derived_class_helper<
                derived_class_set_t<typename type::element_type>>>(index,
                                                                   item.get());
      }
      else {
        ret += calculate_one_size(*item);
      }
    }
  }
  else if constexpr (is_variant_v<type>) {
    ret.total = sizeof(uint8_t);
    ret += std::visit(
        [](const auto &e) {
          return calculate_one_size(e);
        },
        item);
  }
  else if constexpr (ylt::reflection::expected<type>) {
    ret.total = sizeof(bool);
    if (item.has_value()) {
      if constexpr (!std::is_same_v<typename type::value_type, void>)
        ret += calculate_one_size(item.value());
    }
    else {
      ret += calculate_one_size(item.error());
    }
  }
  else if constexpr (std::is_class_v<type>) {
    if constexpr (!pair<type> && !is_trivial_tuple<type>) {
      if constexpr (!user_defined_refl<type>)
        static_assert(std::is_aggregate_v<remove_cvref_t<type>>,
                      "struct_pack only support aggregated type, or you should "
                      "add macro YLT_REFL(Type,field1,field2...)");
    }
    if constexpr (is_trivial_serializable<type>::value) {
      ret.total = sizeof(type);
    }
    else if constexpr (is_trivial_serializable<type, true>::value) {
      visit_members(item, [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
        ret += calculate_payload_size(items...);
        ret.total += align::total_padding_size<type>;
      });
    }
    else {
      constexpr uint64_t tag = get_parent_tag<type>();
      if constexpr (is_enable_fast_varint_coding(tag)) {
        ret.total +=
            visit_members(item, [](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
              constexpr uint64_t tag =
                  get_parent_tag<type>();  // to pass msvc with c++17
              return calculate_fast_varint_size<tag>(items...);
            });
      }
      ret += visit_members(item, [](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
        constexpr uint64_t tag =
            get_parent_tag<type>();  // to pass msvc with c++17
        return calculate_payload_size<tag>(items...);
      });
    }
  }
  else {
    static_assert(!sizeof(type), "the type is not supported yet");
  }
  return ret;
}