Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 43 additions & 20 deletions include/reflection-cpp/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,17 +456,27 @@ inline constexpr decltype(auto) ToTuple(T&& t) noexcept
// clang-format on
}

template <auto I, typename T>
constexpr decltype(auto) GetMemberAt(T&& t)
{
return std::get<I>(ToTuple(std::forward<T>(t)));
}

/// Represents the type of the member at index I of type Object
template <auto I, typename Object>
using MemberTypeOf = std::remove_cvref_t<decltype(std::get<I>(ToTuple(Object {})))>;

template <class T>
struct WrappedPointer final
{
const T* ptr;
T* pointer;
};

template <size_t N, class T>
constexpr auto GetElementPtrAt(T&& t) noexcept
{
auto& p = get<N>(ToTuple(t));
return WrappedPointer<std::remove_cvref_t<decltype(p)>> { &p };
auto& p = GetMemberAt<N>(std::forward<T>(t));
return WrappedPointer<std::remove_reference_t<decltype(p)>> { &p };
}

namespace detail
Expand Down Expand Up @@ -673,7 +683,7 @@ consteval auto GetName()
std::string_view str = REFLECTION_PRETTY_FUNCTION;
str = str.substr(str.rfind("::") + 2);
str = str.substr(0, str.find('>'));
return str.substr(str.find('<')+1);
return str.substr(str.find('<') + 1);
#else
constexpr auto MarkerStart = std::string_view { "E = " };
std::string_view str = REFLECTION_PRETTY_FUNCTION;
Expand All @@ -683,18 +693,32 @@ consteval auto GetName()
#endif
}

/// Calls a callable on each member of an object with the index of the member as the first argument.
/// and the member's default-constructed value as the second argument.
template <typename Object, typename Callable>
constexpr void EnumerateMembers(Object& object, Callable&& callable)
{
template_for<0, CountMembers<Object>>([&]<auto I>() { callable.template operator()<I>(GetMemberAt<I>(object)); });
}

/// Calls a callable on each member of an object with the index and member's type as template arguments.
template <typename Object, typename Callable>
void CallOnMembers(Object const& object, Callable&& callable)
constexpr void EnumerateMembers(Callable&& callable)
{
template_for<0, Reflection::CountMembers<Object>>(
[&]<auto I>() { callable(Reflection::MemberNameOf<I, Object>, std::get<I>(Reflection::ToTuple(object))); });
// clang-format off
template_for<0, CountMembers<Object>>(
[&]<auto I>() {
callable.template operator()<I, MemberTypeOf<I, Object>>();
}
);
// clang-format on
}

template <typename Object, typename Callable>
void CallOnMembers(Object& object, Callable&& callable)
{
template_for<0, Reflection::CountMembers<Object>>(
[&]<auto I>() { callable(Reflection::MemberNameOf<I, Object>, std::get<I>(Reflection::ToTuple(object))); });
EnumerateMembers<Object>(object,
[&]<size_t I, typename T>(T&& value) { callable(MemberNameOf<I, Object>, value); });
}

/// Folds over the members of a type without an object of it.
Expand All @@ -709,11 +733,9 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
{
// clang-format off
ResultType result = initialValue;
template_for<0, Reflection::CountMembers<Object>>(
[&]<size_t I>() {
result = callable(Reflection::MemberNameOf<I, Object>,
std::get<I>(Reflection::ToTuple(Object {})),
result);
EnumerateMembers<Object>(
[&]<size_t I, typename MemberType>() {
result = callable.template operator()<I, MemberTypeOf<I, Object>>(result);
}
);
// clang-format on
Expand All @@ -729,15 +751,16 @@ constexpr ResultType FoldMembers(ResultType initialValue, Callable const& callab
///
/// @return The result of the fold
template <typename Object, typename Callable, typename ResultType>
constexpr ResultType FoldMembers(Object const& object, ResultType initialValue, Callable const& callable)
constexpr ResultType FoldMembers(Object& object, ResultType initialValue, Callable const& callable)
{
// clang-format off
ResultType result = initialValue;
template_for<0, Reflection::CountMembers<Object>>([&]<size_t I>() {
result = callable(Reflection::MemberNameOf<I, Object>,
std::get<I>(Reflection::ToTuple(object)),
result);
});
EnumerateMembers<Object>(
object,
[&]<size_t I, typename MemberType>(MemberType&& value) {
result = callable(MemberNameOf<I, Object>, value, result);
}
);
return result;
// clang-format on
}
Expand Down
15 changes: 12 additions & 3 deletions test-reflection-cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ TEST_CASE("nested", "[reflection]")
TEST_CASE("FoldMembers.type", "[reflection]")
{
// clang-format off
auto const result = Reflection::FoldMembers<TestStruct>(0, [](auto&& /*name*/, auto&& /*value*/, auto&& result) {
return result + 1;
auto const result = Reflection::FoldMembers<TestStruct>(size_t{0}, []<size_t I, typename T>(auto&& result) {
return result + I;
});
// clang-format on
CHECK(result == 5);
CHECK(result == 0 + 0 + 1 + 2 + 3 + 4);
}

struct S
Expand All @@ -93,3 +93,12 @@ TEST_CASE("FoldMembers.value", "[reflection]")

CHECK(result == 6);
}

TEST_CASE("MemberTypeOf", "[reflection]")
{
static_assert(std::same_as<Reflection::MemberTypeOf<0, TestStruct>, int>);
static_assert(std::same_as<Reflection::MemberTypeOf<1, TestStruct>, float>);
static_assert(std::same_as<Reflection::MemberTypeOf<2, TestStruct>, double>);
static_assert(std::same_as<Reflection::MemberTypeOf<3, TestStruct>, std::string>);
static_assert(std::same_as<Reflection::MemberTypeOf<4, TestStruct>, Person>);
}
Loading