Skip to content

Commit

Permalink
support oneof by std::variant[struct_pb]
Browse files Browse the repository at this point in the history
  • Loading branch information
bbbgan committed May 7, 2024
1 parent 4e046a6 commit 81aafed
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 90 deletions.
32 changes: 31 additions & 1 deletion iguana/detail/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

#include "iguana/define.h"


namespace iguana {

template <class T>
Expand Down Expand Up @@ -71,5 +70,36 @@ struct has_type<T, std::tuple<Us...>>
template <typename T>
inline constexpr bool is_int64_v =
std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>;

template <typename T>
struct is_variant : std::false_type {};

template <typename... T>
struct is_variant<std::variant<T...>> : std::true_type {};

template <class T>
struct member_traits {
using value_type = T;
};

template <class T, class Owner>
struct member_traits<T Owner::*> {
using owner_type = Owner;
using value_type = T;
};

template <typename T, std::size_t I, typename = void>
struct variant_type_at {
using type = T;
};

template <typename T, std::size_t I>
struct variant_type_at<T, I, std::enable_if_t<is_variant<T>::value>> {
using type = std::variant_alternative_t<I, T>;
};
template <typename T, std::size_t I>
using variant_type_at_t =
typename variant_type_at<typename member_traits<T>::value_type, I>::type;

} // namespace iguana
#endif // SERIALIZE_TRAITS_HPP
22 changes: 16 additions & 6 deletions iguana/pb_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ inline void from_pb_impl(T& val, std::string_view& pb_str, uint32_t field_no) {
}
}

template <typename T, typename Field>
inline void parse_oneof(T& t, Field& f, std::string_view& pb_str) {
using item_type = typename std::decay_t<Field>::value_type;
item_type item{};
from_pb_impl(item, pb_str, f.field_no);
t = std::move(item);
}

} // namespace detail

template <typename T>
Expand All @@ -189,18 +197,20 @@ inline void from_pb(T& t, std::string_view pb_str) {
pb_str = pb_str.substr(pos);

const static auto& map = get_members<T>();
uint32_t sub_val = 1;
if constexpr (!is_reflection_v<T>) {
sub_val = 0;
}
auto& member = map.at(field_number - sub_val);
auto& member = map.at(field_number);
std::visit(
[&t, &pb_str, wire_type](auto& val) {
using value_type = typename std::decay_t<decltype(val)>::value_type;
if (wire_type != detail::get_wire_type<value_type>()) {
throw std::runtime_error("unmatched wire_type");
}
detail::from_pb_impl<value_type>(val.value(t), pb_str, val.field_no);
using v_type = typename std::decay_t<decltype(val.value(t))>;
if constexpr (variant_v<v_type>) {
detail::parse_oneof(val.value(t), val, pb_str);
}
else {
detail::from_pb_impl(val.value(t), pb_str, val.field_no);
}
},
member);
}
Expand Down
41 changes: 33 additions & 8 deletions iguana/pb_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ constexpr inline WireType get_wire_type() {
return get_wire_type<typename T::value_type>();
}
else {
return WireType::Unknown;
throw std::runtime_error("unknown type");
}
}

Expand Down Expand Up @@ -322,6 +322,25 @@ inline size_t numeric_size(T&& t) {
}
}

template <size_t key_size, typename T>
inline size_t pb_key_value_size(T&& t);

template <size_t field_no, typename T>
inline size_t pb_oneof_size(T&& t) {
int len = 0;
std::visit(
[&len](auto&& value) {
using value_type =
std::remove_const_t<std::remove_reference_t<decltype(value)>>;
constexpr uint32_t key =
(field_no << 3) |
static_cast<uint32_t>(get_wire_type<value_type>());
len = pb_key_value_size<key>(std::forward<value_type>(value));
},
std::forward<T>(t));
return len;
}

// returns size = key_size + optional(len_size) + len
// when key_size == 0, return len
template <size_t key_size, typename T>
Expand All @@ -330,17 +349,23 @@ inline size_t pb_key_value_size(T&& t) {
if constexpr (is_reflection_v<value_type> ||
is_custom_reflection_v<value_type>) {
size_t len = 0;
constexpr auto tuple = get_members_impl<value_type>();
constexpr auto tuple = get_field_tuple<value_type>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
for_each_n(
[&len, &t](auto i) {
constexpr static auto tp = get_members_impl<value_type>();
constexpr static auto tp = get_field_tuple<value_type>();
constexpr auto value = std::get<decltype(i)::value>(tp);
using U = typename std::decay_t<decltype(value)>::value_type;
constexpr uint32_t sub_key =
(value.field_no << 3) | static_cast<uint32_t>(get_wire_type<U>());
constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key);
len += pb_key_value_size<sub_keysize>(value.value(t));
using U = typename std::decay_t<decltype(value.value(t))>;
if constexpr (variant_v<U>) {
len += pb_oneof_size<value.field_no>(value.value(t));
}
else {
constexpr uint32_t sub_key =
(value.field_no << 3) |
static_cast<uint32_t>(get_wire_type<U>());
constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key);
len += pb_key_value_size<sub_keysize>(value.value(t));
}
},
std::make_index_sequence<SIZE>{});
get_set_size_cache(t) = len;
Expand Down
51 changes: 45 additions & 6 deletions iguana/pb_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,39 @@ inline void encode_numeric_field(T t, Stream& out) {
}
}

template <typename Variant, typename T, size_t I>
constexpr size_t get_variant_index() {
if constexpr (I == 0) {
static_assert(std::is_same_v<std::variant_alternative_t<0, Variant>, T>,
"Type T is not found in Variant");
return 0;
}
else if constexpr (std::is_same_v<std::variant_alternative_t<I, Variant>,
T>) {
return I;
}
else {
return get_variant_index<Variant, T, I - 1>();
}
}

template <uint32_t field_no, typename Type, typename Stream>
inline void render_variant(Type&& t, Stream& out) {
std::visit(
[&out](auto&& value) {
using value_type =
std::remove_const_t<std::remove_reference_t<decltype(value)>>;
constexpr size_t offset =
get_variant_index<std::decay_t<Type>, value_type,
std::variant_size_v<std::decay_t<Type>> - 1>();
constexpr uint32_t key =
((field_no + offset) << 3) |
static_cast<uint32_t>(get_wire_type<value_type>());
to_pb_impl<key, true>(std::forward<value_type>(value), out);
},
std::forward<Type>(t));
}

// omit_default_val = true indicates to omit the default value in searlization
template <uint32_t key, bool omit_default_val, typename Type, typename Stream>
inline void to_pb_impl(Type&& t, Stream& out) {
Expand All @@ -91,16 +124,22 @@ inline void to_pb_impl(Type&& t, Stream& out) {
return;
}
}
constexpr auto tuple = get_members_impl<T>();
constexpr auto tuple = get_field_tuple<T>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
for_each_n(
[&t, &out](auto i) {
constexpr static auto tp = get_members_impl<T>();
constexpr static auto tp = get_field_tuple<T>();
constexpr auto value = std::get<decltype(i)::value>(tp);
using U = typename std::decay_t<decltype(value)>::value_type;
constexpr uint32_t sub_key =
(value.field_no << 3) | static_cast<uint32_t>(get_wire_type<U>());
to_pb_impl<sub_key>(value.value(t), out);
using U = typename std::decay_t<decltype(value.value(t))>;
if constexpr (variant_v<U>) {
render_variant<value.field_no>(value.value(t), out);
}
else {
constexpr uint32_t sub_key =
(value.field_no << 3) |
static_cast<uint32_t>(get_wire_type<U>());
to_pb_impl<sub_key>(value.value(t), out);
}
},
std::make_index_sequence<SIZE>{});
}
Expand Down
Loading

0 comments on commit 81aafed

Please sign in to comment.