Skip to content

Commit

Permalink
Merge pull request #284 from bbbgan/master
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored May 28, 2024
2 parents 61c1ee4 + 0b3eb6e commit 137b1fb
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 117 deletions.
182 changes: 101 additions & 81 deletions iguana/pb_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,48 +361,66 @@ IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence<I...>) {
(std::forward<F>(f)(std::integral_constant<size_t, I>{}), ...);
}

template <size_t key_size, bool omit_default_val, typename T>
IGUANA_INLINE size_t numeric_size(T&& t) {
using value_type = std::remove_const_t<std::remove_reference_t<T>>;
if constexpr (omit_default_val) {
if constexpr (is_fixed_v<value_type> || is_signed_varint_v<value_type>) {
if (t.val == 0)
template <size_t key_size, bool omit_default_val, typename Type>
IGUANA_INLINE size_t str_numeric_size(Type&& t) {
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
// string
if constexpr (omit_default_val) {
if (t.size() == 0)
IGUANA_UNLIKELY { return 0; }
}
if constexpr (key_size == 0) {
return t.size();
}
else {
if (t == static_cast<value_type>(0))
IGUANA_UNLIKELY { return 0; }
return key_size + variant_uint32_size(static_cast<uint32_t>(t.size())) +
t.size();
}
}
if constexpr (std::is_integral_v<value_type>) {
if constexpr (std::is_same_v<bool, value_type>) {
return 1 + key_size;
else {
// numeric
if constexpr (omit_default_val) {
if constexpr (is_fixed_v<T> || is_signed_varint_v<T>) {
if (t.val == 0)
IGUANA_UNLIKELY { return 0; }
}
else {
if (t == static_cast<T>(0))
IGUANA_UNLIKELY { return 0; }
}
}
if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_same_v<bool, T>) {
return 1 + key_size;
}
else {
return key_size + variant_intergal_size(t);
}
}
else if constexpr (detail::is_signed_varint_v<T>) {
return key_size + variant_intergal_size(encode_zigzag(t.val));
}
else if constexpr (detail::is_fixed_v<T>) {
return key_size + sizeof(typename T::value_type);
}
else if constexpr (std::is_same_v<T, double> || std::is_same_v<T, float>) {
return key_size + sizeof(T);
}
else if constexpr (std::is_enum_v<T>) {
using U = std::underlying_type_t<T>;
return key_size + variant_intergal_size(static_cast<U>(t));
}
else {
return key_size + variant_intergal_size(t);
static_assert(!sizeof(T), "err");
}
}
else if constexpr (detail::is_signed_varint_v<value_type>) {
return key_size + variant_intergal_size(encode_zigzag(t.val));
}
else if constexpr (detail::is_fixed_v<value_type>) {
return key_size + sizeof(typename value_type::value_type);
}
else if constexpr (std::is_same_v<value_type, double> ||
std::is_same_v<value_type, float>) {
return key_size + sizeof(value_type);
}
else if constexpr (std::is_enum_v<value_type>) {
using U = std::underlying_type_t<value_type>;
return key_size + variant_intergal_size(static_cast<U>(t));
}
else {
static_assert(!sizeof(value_type), "err");
}
}

template <size_t key_size, bool omit_default_val = true, typename T>
IGUANA_INLINE size_t pb_key_value_size(T&& t);
template <size_t key_size, bool omit_default_val = true, typename Type,
typename Arr>
IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr);

template <typename Variant, typename T, size_t I>
constexpr inline size_t get_variant_index() {
Expand All @@ -420,12 +438,12 @@ constexpr inline size_t get_variant_index() {
}
}

template <size_t field_no, typename Type>
IGUANA_INLINE size_t pb_oneof_size(Type&& t) {
template <size_t field_no, typename Type, typename Arr>
IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) {
using T = std::decay_t<Type>;
int len = 0;
std::visit(
[&len](auto&& value) IGUANA__INLINE_LAMBDA {
[&len, &size_arr](auto&& value) IGUANA__INLINE_LAMBDA {
using value_type =
std::remove_const_t<std::remove_reference_t<decltype(value)>>;
constexpr auto offset =
Expand All @@ -434,23 +452,28 @@ IGUANA_INLINE size_t pb_oneof_size(Type&& t) {
((field_no + offset) << 3) |
static_cast<uint32_t>(get_wire_type<value_type>());
len = pb_key_value_size<variant_uint32_size_constexpr(key), false>(
std::forward<value_type>(value));
std::forward<value_type>(value), size_arr);
},
std::forward<Type>(t));
return len;
}

// returns size = key_size + optional(len_size) + len
// when key_size == 0, return len
template <size_t key_size, bool omit_default_val, typename Type>
IGUANA_INLINE size_t pb_key_value_size(Type&& t) {
template <size_t key_size, bool omit_default_val, typename Type, typename Arr>
IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) {
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
size_t len = 0;
static constexpr auto tuple = get_members_tuple<T>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
size_t pre_index = -1;
if constexpr (!inherits_from_pb_base_v<T> && key_size != 0) {
pre_index = size_arr.size();
size_arr.push_back(0); // placeholder
}
for_each_n(
[&len, &t](auto i) IGUANA__INLINE_LAMBDA {
[&len, &t, &size_arr](auto i) IGUANA__INLINE_LAMBDA {
using field_type =
std::tuple_element_t<decltype(i)::value,
std::decay_t<decltype(tuple)>>;
Expand All @@ -462,22 +485,24 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) {
get_variant_index<U, typename field_type::sub_type,
std::variant_size_v<U> - 1>();
if constexpr (offset == 0) {
len += pb_oneof_size<value.field_no>(val);
len += pb_oneof_size<value.field_no>(val, size_arr);
}
}
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>(val);
len += pb_key_value_size<sub_keysize>(val, size_arr);
}
},
std::make_index_sequence<SIZE>{});
static_assert(inherits_from_pb_base_v<T>,
"must be inherited from iguana::pb_base_impl");
t.cache_size = len;

if constexpr (inherits_from_pb_base_v<T>) {
t.cache_size = len;
}
else if constexpr (key_size != 0) {
size_arr[pre_index] = len;
}
if constexpr (key_size == 0) {
// for top level
return len;
Expand All @@ -497,14 +522,14 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) {
size_t len = 0;
if constexpr (is_lenprefix_v<item_type>) {
for (auto& item : t) {
len += pb_key_value_size<key_size, false>(item);
len += pb_key_value_size<key_size, false>(item, size_arr);
}
return len;
}
else {
for (auto& item : t) {
// here 0 to get pakced size
len += numeric_size<0, false>(item);
// here 0 to get pakced size, and item must be numeric
len += str_numeric_size<0, false>(item);
}
if (len == 0) {
return 0;
Expand All @@ -518,8 +543,8 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) {
size_t len = 0;
for (auto& [k, v] : t) {
// the key_size of k and v is constant 1
size_t kv_len =
pb_key_value_size<1, false>(k) + pb_key_value_size<1, false>(v);
auto kv_len = pb_key_value_size<1, false>(k, size_arr) +
pb_key_value_size<1, false>(v, size_arr);
len += key_size + variant_uint32_size(static_cast<uint32_t>(kv_len)) +
kv_len;
}
Expand All @@ -529,60 +554,55 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) {
if (!t.has_value()) {
return 0;
}
return pb_key_value_size<key_size, omit_default_val>(*t);
}
else if constexpr (std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
if constexpr (omit_default_val) {
if (t.size() == 0)
IGUANA_UNLIKELY { return 0; }
}
if constexpr (key_size == 0) {
return t.size();
}
else {
return key_size + variant_uint32_size(static_cast<uint32_t>(t.size())) +
t.size();
}
return pb_key_value_size<key_size, omit_default_val>(*t, size_arr);
}
else {
return numeric_size<key_size, omit_default_val>(t);
return str_numeric_size<key_size, omit_default_val>(t);
}
}

// return the payload size
template <typename T>
IGUANA_INLINE size_t pb_value_size(T&& t) {
using value_type = std::remove_const_t<std::remove_reference_t<T>>;
if constexpr (is_reflection_v<value_type>) {
static_assert(inherits_from_pb_base_v<std::decay_t<T>>,
"must be inherited from iguana::pb_base_impl");
return t.cache_size;
}
else if constexpr (is_sequence_container<value_type>::value) {
using item_type = typename value_type::value_type;
template <bool skip_next = true, typename Type>
IGUANA_INLINE size_t pb_value_size(Type&& t, uint32_t*& sz_ptr) {
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
if constexpr (inherits_from_pb_base_v<T>) {
return t.cache_size;
}
else {
// *sz_ptr is secure and logically guaranteed
if constexpr (skip_next) {
return *(sz_ptr++);
}
else {
return *sz_ptr;
}
}
}
else if constexpr (is_sequence_container<T>::value) {
using item_type = typename T::value_type;
size_t len = 0;
if constexpr (!is_lenprefix_v<item_type>) {
for (auto& item : t) {
len += numeric_size<0, false>(item);
len += str_numeric_size<0, false>(item);
}
return len;
}
else {
static_assert(!sizeof(item_type), "the size of this type is meaningless");
}
}
else if constexpr (is_map_container<value_type>::value) {
static_assert(!sizeof(value_type), "the size of this type is meaningless");
else if constexpr (is_map_container<T>::value) {
static_assert(!sizeof(T), "the size of this type is meaningless");
}
else if constexpr (optional_v<value_type>) {
else if constexpr (optional_v<T>) {
if (!t.has_value()) {
return 0;
}
return pb_value_size(*t);
return pb_value_size(*t, sz_ptr);
}
else {
return pb_key_value_size<0>(t);
return str_numeric_size<0, false>(t);
}
}

Expand Down
Loading

0 comments on commit 137b1fb

Please sign in to comment.