Skip to content

Commit

Permalink
support custom reflection struct[struct_pb]
Browse files Browse the repository at this point in the history
  • Loading branch information
bbbgan committed May 3, 2024
1 parent eadde96 commit 6bc92b1
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 71 deletions.
33 changes: 17 additions & 16 deletions frozen/bits/pmh.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
#ifndef FROZEN_LETITGO_PMH_H
#define FROZEN_LETITGO_PMH_H

#include "frozen/bits/algorithms.h"
#include "frozen/bits/basic_types.h"

#include <array>
#include <limits>

#include "frozen/bits/algorithms.h"
#include "frozen/bits/basic_types.h"

namespace frozen {

namespace bits {
Expand All @@ -47,9 +47,10 @@ struct bucket_size_compare {
// hash function.
// pmh_buckets represents the initial placement into buckets.

template <size_t M> struct pmh_buckets {
template <size_t M>
struct pmh_buckets {
// Step 0: Bucket max is 2 * sqrt M
// TODO: Come up with justification for this, should it not be O(log M)?
// : Come up with justification for this, should it not be O(log M)?
static constexpr auto bucket_max = 2 * (1u << (log(M) / 2));

using bucket_t = cvector<std::size_t, bucket_max>;
Expand Down Expand Up @@ -135,14 +136,14 @@ constexpr bool all_different_from(cvector<T, N> &data, T &a) {
struct seed_or_index {
using value_type = uint64_t;

private:
private:
static constexpr value_type MINUS_ONE =
(std::numeric_limits<value_type>::max)();
static constexpr value_type HIGH_BIT = ~(MINUS_ONE >> 1);

value_type value_ = 0;

public:
public:
constexpr value_type value() const { return value_; }
constexpr bool is_seed() const { return value_ & HIGH_BIT; }

Expand All @@ -155,7 +156,8 @@ struct seed_or_index {
};

// Represents the perfect hash function created by pmh algorithm
template <std::size_t M, class Hasher> struct pmh_tables {
template <std::size_t M, class Hasher>
struct pmh_tables {
uint64_t first_seed_;
carray<seed_or_index, M> first_table_;
carray<std::size_t, M> second_table_;
Expand All @@ -175,7 +177,7 @@ template <std::size_t M, class Hasher> struct pmh_tables {
first_table_[hasher(key, static_cast<size_t>(first_seed_)) % M];
if (!d.is_seed()) {
return static_cast<std::size_t>(d.value());
} // this is narrowing uint64 -> size_t but should be fine
} // this is narrowing uint64 -> size_t but should be fine
else {
return second_table_[hasher(key, static_cast<std::size_t>(d.value())) %
M];
Expand All @@ -196,7 +198,7 @@ pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &items,
auto buckets = step_one.get_sorted_buckets();

// G becomes the first hash table in the resulting pmh function
carray<seed_or_index, M> G; // Default constructed to "index 0"
carray<seed_or_index, M> G; // Default constructed to "index 0"

// H becomes the second hash table in the resulting pmh function
constexpr std::size_t UNUSED = (std::numeric_limits<std::size_t>::max)();
Expand All @@ -211,8 +213,8 @@ pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &items,
// Store index to the (single) item in G
// assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
G[bucket.hash] = {false, static_cast<uint64_t>(bucket[0])};
} else if (bsize > 1) {

}
else if (bsize > 1) {
// Repeatedly try different H of d until we find a hash function
// that places all items in the bucket into free slots
seed_or_index d{true, prg()};
Expand All @@ -235,8 +237,7 @@ pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &items,
// Put successful seed in G, and put indices to items in their slots
// assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
G[bucket.hash] = d;
for (std::size_t i = 0; i < bsize; ++i)
H[bucket_slots[i]] = bucket[i];
for (std::size_t i = 0; i < bsize; ++i) H[bucket_slots[i]] = bucket[i];
}
}

Expand All @@ -251,8 +252,8 @@ pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &items,
return {step_one.seed, G, H, hash};
}

} // namespace bits
} // namespace bits

} // namespace frozen
} // namespace frozen

#endif
34 changes: 17 additions & 17 deletions iguana/pb_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,9 @@ constexpr inline size_t variant_intergal_size(U value) {
}
}

template <typename T, typename F>
constexpr void for_each_tp(T&& t, F&& f) {
constexpr auto tp = get_members<T, false>();
using Tuple = decltype(tp);
for_each(tp, std::forward<F>(f),
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
template <typename F, size_t... I>
constexpr void for_each_n(F&& f, std::index_sequence<I...>) {
(std::forward<F>(f)(std::integral_constant<size_t, I>{}), ...);
}

// cache the size of reflection type
Expand All @@ -343,23 +340,26 @@ auto& get_set_size_cache(T& t) {
return cache[reinterpret_cast<size_t>(&t)];
}

// TODO: support user-defined struct
// returns size = key_size + optional(len_size) + len
// when key_size == 0, return len
template <size_t key_size = 0, typename T>
inline size_t pb_item_size(T&& t) {
using value_type = std::remove_const_t<std::remove_reference_t<T>>;
if constexpr (is_reflection_v<value_type>) {
if constexpr (is_reflection_v<value_type> ||
is_custom_reflection_v<value_type>) {
size_t len = 0;
for_each_tp(t, [&len, &t](const auto& val, auto i) {
constexpr static auto tp = get_members_impl<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>());
constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key);
len += pb_item_size<sub_keysize>(value.value(t));
});
constexpr auto tp = get_members_impl<value_type>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tp)>>;
for_each_n(
[&len, &t, &tp](auto i) {
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_item_size<sub_keysize>(value.value(t));
},
std::make_index_sequence<SIZE>{});
get_set_size_cache(t) = len;
if constexpr (key_size == 0) {
return len;
Expand Down
22 changes: 13 additions & 9 deletions iguana/pb_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ inline void encode_pair_value(V&& val, Stream& out, size_t size) {
template <uint32_t key, typename Type, typename Stream>
inline void to_pb_impl(Type& t, Stream& out) {
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (is_reflection_v<T>) {
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
// TODO: improve the key serialize
auto len = pb_load_size(t);
if (len == 0) {
Expand All @@ -60,14 +60,18 @@ inline void to_pb_impl(Type& t, Stream& out) {
serialize_varint(key, out);
serialize_varint(len, out);
}
for_each_tp(t, [&t, &out](const auto& val, auto i) {
constexpr static auto tp = get_members_impl<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);
});
// TODO: constexpr static auto tp
constexpr auto tp = get_members_impl<T>();
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tp)>>;
for_each_n(
[&t, &out, &tp](auto i) {
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);
},
std::make_index_sequence<SIZE>{});
}
else if constexpr (is_sequence_container<T>::value) {
// TODO support std::array
Expand Down
38 changes: 23 additions & 15 deletions iguana/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,18 @@ template <typename T, typename = void>
struct is_custom_reflection : std::false_type {};

template <typename T>
struct is_custom_reflection<T, std::void_t<decltype(get_members_impl(std::declval<T*>()))>> : std::true_type {};
struct is_custom_reflection<
T, std::void_t<decltype(get_members_impl(std::declval<T *>()))>>
: std::true_type {};

template <typename T, typename = void>
struct is_reflection : std::false_type {};

template <typename T>
inline constexpr bool is_reflection_v = is_reflection<T>::value;

template <typename T>
inline constexpr bool is_custom_reflection_v = is_custom_reflection<T>::value;

struct field_helper {
template <typename T, typename U, size_t... I>
Expand All @@ -749,10 +760,16 @@ struct field_helper {

template <typename T>
constexpr inline auto get_members_impl() {
using reflect_members = decltype(iguana_reflect_type(std::declval<T>()));
using Tuple = decltype(reflect_members::apply_impl());
return field_helper{}(reflect_members::apply_impl(), reflect_members::arr(),
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
if constexpr (is_reflection_v<T>) {
using reflect_members = decltype(iguana_reflect_type(std::declval<T>()));
using Tuple = decltype(reflect_members::apply_impl());
return field_helper{}(reflect_members::apply_impl(), reflect_members::arr(),
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
else if constexpr (is_custom_reflection_v<T>) {
using U = std::remove_const_t<std::remove_reference_t<T>>;
return get_members_impl((U *)nullptr);
}
}

template <typename T, size_t Size>
Expand All @@ -766,9 +783,6 @@ struct member_helper {
}
};

template <typename T, typename = void>
struct is_reflection : std::false_type {};

template <typename T, bool is_return_map = true>
constexpr inline auto get_members() {
if constexpr (is_reflection<T>::value) {
Expand All @@ -784,7 +798,7 @@ constexpr inline auto get_members() {
return get_members_impl<T>();
}
}
else if constexpr (is_custom_reflection<T>::value) {
else if constexpr (is_custom_reflection_v<T>) {
using U = std::remove_const_t<std::remove_reference_t<T>>;
constexpr size_t Size = iguana_member_count((U *)nullptr);
using value_type = typename user_field_type_t<decltype(get_members_impl(
Expand Down Expand Up @@ -928,12 +942,6 @@ inline auto iguana_reflect_type(const T &t) {
}
}

template <typename T>
inline constexpr bool is_reflection_v = is_reflection<T>::value;

template <typename T>
inline constexpr bool is_custom_reflection_v = is_custom_reflection<T>::value;

template <std::size_t index, template <typename...> typename Condition,
typename Tuple, typename Owner>
constexpr int element_index_helper() {
Expand Down
28 changes: 14 additions & 14 deletions test/test_pb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct inner_struct {
int z;
};

inline auto get_members_impl(inner_struct *) {
constexpr inline auto get_members_impl(inner_struct *) {
return std::make_tuple(iguana::field_t{&inner_struct::x, 7, "a"},
iguana::field_t{&inner_struct::y, 9, "b"},
iguana::field_t{&inner_struct::z, 12, "c"});
Expand Down Expand Up @@ -173,19 +173,19 @@ struct numer_st {
REFLECTION(numer_st, a, b, c);

TEST_CASE("test struct_pb") {
// {
// my_space::inner_struct inner{41, 42, 43};

// std::string str;
// iguana::to_pb(inner, str);
// // CHECK(str.size() == iguana::detail::pb_item_size(inner));

// my_space::inner_struct inner1;
// iguana::from_pb(inner1, str);
// CHECK(inner.x == inner1.x);
// CHECK(inner.y == inner1.y);
// CHECK(inner.z == inner1.z);
// }
{
my_space::inner_struct inner{41, 42, 43};

std::string str;
iguana::to_pb(inner, str);
CHECK(str.size() == iguana::detail::pb_item_size(inner));

my_space::inner_struct inner1;
iguana::from_pb(inner1, str);
CHECK(inner.x == inner1.x);
CHECK(inner.y == inner1.y);
CHECK(inner.z == inner1.z);
}

{
test_pb_st1 st1{41, {42}, {43}};
Expand Down

0 comments on commit 6bc92b1

Please sign in to comment.