Skip to content

Commit

Permalink
[reflection] Add customization point for users to supply reflection info
Browse files Browse the repository at this point in the history
This is useful e.g. in really big structs that can have reflection
info provided by codegen
  • Loading branch information
alexkaratarakis committed Dec 4, 2024
1 parent 2d84a40 commit 5336fe7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 10 deletions.
35 changes: 25 additions & 10 deletions include/fixed_containers/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,28 @@ constexpr auto field_names_of_impl(const T& instance)
return output;
}

template <typename T>
inline constexpr auto FIELD_NAMES =
field_names_of_impl<field_count_of_impl(std::decay_t<T>{})>(std::decay_t<T>{});
} // namespace fixed_containers::reflection_detail

namespace fixed_containers::reflection::customize
{
template <typename T>
struct ReflectionHelper
{
static constexpr auto FIELD_NAMES = fixed_containers::reflection_detail::field_names_of_impl<
fixed_containers::reflection_detail::field_count_of_impl(std::decay_t<T>{})>(
std::decay_t<T>{});

template <typename T2, typename Func>
static constexpr void apply(T2&& instance, Func&& func)
{
auto tuple_view = tuples::as_tuple_view<FIELD_NAMES.size()>(std::forward<T2>(instance));
tuples::for_each_entry(tuple_view,
[&func]<typename Field>(std::size_t index, Field&& field)
{ func(FIELD_NAMES.at(index), std::forward<Field>(field)); });
}
};
} // namespace fixed_containers::reflection::customize

namespace fixed_containers::reflection
{
template <typename T>
Expand All @@ -225,25 +242,23 @@ template <typename T>
requires(Reflectable<std::decay_t<T>>)
constexpr std::size_t field_count_of()
{
return reflection_detail::FIELD_NAMES<std::decay_t<T>>.size();
return fixed_containers::reflection::customize::ReflectionHelper<std::decay_t<T>>::FIELD_NAMES
.size();
}

template <typename T>
requires(Reflectable<std::decay_t<T>>)
constexpr const auto& field_names_of()
{
return reflection_detail::FIELD_NAMES<std::decay_t<T>>;
return fixed_containers::reflection::customize::ReflectionHelper<std::decay_t<T>>::FIELD_NAMES;
}

template <typename T, typename Func>
requires(Reflectable<std::decay_t<T>>)
constexpr void for_each_field(T&& instance, Func&& func)
{
constexpr const auto& FIELD_NAMES = field_names_of<T>();
auto tuple_view = tuples::as_tuple_view<FIELD_NAMES.size()>(instance);
tuples::for_each_entry(tuple_view,
[&func]<typename Field>(std::size_t index, Field&& field)
{ func(FIELD_NAMES.at(index), std::forward<Field>(field)); });
return fixed_containers::reflection::customize::ReflectionHelper<std::decay_t<T>>::apply(
std::forward<T>(instance), std::forward<Func>(func));
}

} // namespace fixed_containers::reflection
31 changes: 31 additions & 0 deletions test/reflection_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,4 +605,35 @@ TEST(Reflection, MockFailingAddressOfOperator)

} // namespace fixed_containers

namespace fixed_containers::reflection::customize
{
struct MyCustomStruct
{
int a{};
int b{};
int c{};
};

template <>
struct ReflectionHelper<MyCustomStruct>
{
static constexpr auto FIELD_NAMES = make_fixed_vector<std::string_view>({
"a",
"b",
"c",
});

template <typename T2, typename Func>
static constexpr void apply(T2&& instance, Func&& func)
{
func(FIELD_NAMES.at(0), instance.a);
func(FIELD_NAMES.at(1), instance.b);
func(FIELD_NAMES.at(2), instance.c);
}
};

static_assert(fixed_containers::reflection::field_names_of<MyCustomStruct>().size() == 3);

} // namespace fixed_containers::reflection::customize

#endif

0 comments on commit 5336fe7

Please sign in to comment.