in include/ylt/struct_pack/packer.hpp [243:531]
constexpr void inline serialize_one(const T &item) {
using type = remove_cvref_t<decltype(item)>;
static_assert(!std::is_pointer_v<type>);
constexpr auto id = get_type_id<type, parent_tag>();
if constexpr (is_trivial_view_v<T>) {
return serialize_one<size_type, version>(item.get());
}
else if constexpr (version == UINT64_MAX) {
if constexpr (id == type_id::compatible_t) {
// do nothing
}
else if constexpr (std::is_same_v<type, std::monostate>) {
// do nothing
}
else if constexpr (id == type_id::user_defined_type) {
sp_serialize_to(writer_, item);
}
else if constexpr (detail::varint_t<type, parent_tag>) {
if constexpr (is_enable_fast_varint_coding(parent_tag)) {
// do nothing
}
else {
detail::serialize_varint(writer_, item);
}
}
else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
id == type_id::int128_t || id == type_id::uint128_t) {
write_wrapper<sizeof(item)>(writer_, (char *)&item);
}
else if constexpr (id == type_id::bitset_t) {
write_bytes_array(writer_, (char *)&item, sizeof(item));
}
else if constexpr (unique_ptr<type>) {
bool has_value = (item != nullptr);
write_wrapper<sizeof(char)>(writer_, (char *)&has_value);
if (has_value) {
if constexpr (is_base_class<typename type::element_type>) {
bool is_ok{};
uint32_t id = item->get_struct_pack_id();
auto index = search_type_by_md5<typename type::element_type>(
item->get_struct_pack_id(), is_ok);
assert(is_ok);
write_wrapper<sizeof(uint32_t)>(writer_, (char *)&id);
ylt::reflection::template_switch<serialize_one_derived_class_helper<
derived_class_set_t<typename type::element_type>,
std::integral_constant<std::size_t, size_type>,
std::integral_constant<std::uint64_t, version>>>(index, this,
item.get());
}
else {
serialize_one<size_type, version>(*item);
}
}
}
else if constexpr (id == type_id::array_t) {
if constexpr (is_trivial_serializable<type>::value &&
is_little_endian_copyable<sizeof(item[0])>) {
write_bytes_array(writer_, (char *)&item, sizeof(type));
}
else {
for (const auto &i : item) {
serialize_one<size_type, version>(i);
}
}
}
else if constexpr (map_container<type> || container<type>) {
auto size = item.size();
if constexpr (size_type == 1) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else {
#ifdef STRUCT_PACK_OPTIMIZE
constexpr bool struct_pack_optimize = true;
#else
constexpr bool struct_pack_optimize = false;
#endif
if constexpr (force_optimize || struct_pack_optimize) {
if constexpr (size_type == 2) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 4) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 8) {
if constexpr (sizeof(std::size_t) >= 8) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else {
std::uint64_t sz = size;
low_bytes_write_wrapper<size_type>(writer_, sz);
}
}
else {
static_assert(!sizeof(item), "illegal size_type.");
}
}
else {
switch ((info_.metainfo() & 0b11000) >> 3) {
case 1:
low_bytes_write_wrapper<2>(writer_, size);
break;
case 2:
low_bytes_write_wrapper<4>(writer_, size);
break;
case 3:
if constexpr (sizeof(std::size_t) >= 8) {
low_bytes_write_wrapper<8>(writer_, size);
}
else {
unreachable();
}
break;
default:
unreachable();
}
}
}
if constexpr (trivially_copyable_container<type> &&
is_little_endian_copyable<sizeof(
typename type::value_type)>) {
write_bytes_array(writer_, (char *)item.data(),
item.size() * sizeof(typename type::value_type));
return;
}
else {
for (const auto &i : item) {
serialize_one<size_type, version>(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 {
serialize_many<size_type, version>(items...);
},
item);
}
else if constexpr (ylt::reflection::optional<type>) {
bool has_value = item.has_value();
write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
if (has_value) {
serialize_one<size_type, version>(*item);
}
}
else if constexpr (is_variant_v<type>) {
static_assert(std::variant_size_v<type> < 256,
"variant's size is too large");
uint8_t index = item.index();
write_wrapper<sizeof(uint8_t)>(writer_, (char *)&index);
std::visit(
[this](auto &&e) {
this->serialize_one<size_type, version>(e);
},
item);
}
else if constexpr (ylt::reflection::expected<type>) {
bool has_value = item.has_value();
write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
if (has_value) {
if constexpr (!std::is_same_v<typename type::value_type, void>)
serialize_one<size_type, version>(item.value());
}
else {
serialize_one<size_type, version>(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 &&
is_little_endian_copyable<sizeof(type)>) {
write_wrapper<sizeof(type)>(writer_, (char *)&item);
}
else if constexpr ((is_trivial_serializable<type>::value &&
!is_little_endian_copyable<sizeof(type)>) ||
is_trivial_serializable<type, true>::value) {
visit_members(item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
int i = 1;
((serialize_one<size_type, version>(items),
write_padding(align::padding_size<type>[i++])),
...);
});
}
else {
constexpr uint64_t tag = get_parent_tag<type>();
if constexpr (is_enable_fast_varint_coding(tag)) {
visit_members(
item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
constexpr uint64_t tag =
get_parent_tag<type>(); // to pass msvc with c++17
this->serialize_fast_varint<tag>(items...);
});
}
visit_members(item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
constexpr uint64_t tag =
get_parent_tag<type>(); // to pass msvc with c++17
this->serialize_many<size_type, version, tag>(items...);
});
}
}
else {
static_assert(!sizeof(type), "the type is not supported yet");
}
}
else if constexpr (exist_compatible_member<type, version>) {
if constexpr (id == type_id::compatible_t) {
if constexpr (version == type::version_number) {
bool has_value = item.has_value();
write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
if (has_value) {
serialize_one<size_type, UINT64_MAX>(*item);
}
}
}
else if constexpr (unique_ptr<type>) {
if (item != nullptr) {
if constexpr (is_base_class<typename type::element_type>) {
bool is_ok{};
auto index = search_type_by_md5<typename type::element_type>(
item->get_struct_pack_id(), is_ok);
assert(is_ok);
ylt::reflection::template_switch<serialize_one_derived_class_helper<
derived_class_set_t<typename type::element_type>,
std::integral_constant<std::size_t, size_type>,
std::integral_constant<std::uint64_t, version>>>(index, this,
item.get());
}
else {
serialize_one<size_type, version>(*item);
}
}
}
else if constexpr (id == type_id::array_t) {
for (const auto &i : item) {
serialize_one<size_type, version>(i);
}
}
else if constexpr (map_container<type> || container<type>) {
for (const auto &i : item) {
serialize_one<size_type, version>(i);
}
}
else if constexpr (!pair<type> && tuple<type> &&
!is_trivial_tuple<type>) {
std::apply(
[&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
serialize_many<size_type, version>(items...);
},
item);
}
else if constexpr (ylt::reflection::optional<type>) {
if (item.has_value()) {
serialize_one<size_type, version>(*item);
}
}
else if constexpr (is_variant_v<type>) {
std::visit(
[this](const auto &e) {
this->serialize_one<size_type, version>(e);
},
item);
}
else if constexpr (ylt::reflection::expected<type>) {
if (item.has_value()) {
if constexpr (!std::is_same_v<typename type::value_type, void>)
serialize_one<size_type, version>(item.value());
}
else {
serialize_one<size_type, version>(item.error());
}
}
else if constexpr (std::is_class_v<type>) {
visit_members(item, [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
serialize_many<size_type, version>(items...);
});
}
}
return;
}