diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-16 15:46:51 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-16 15:46:56 +0100 |
commit | 65b3b6603e8761a9629f7da19c352384bad2d4bf (patch) | |
tree | 217953be2dd647c061fd01444cfe5c0ec55a3b16 | |
parent | 060168dd1181bb38126e61819ca199b85f7c8fed (diff) |
entity: add type erasure support
-rw-r--r-- | src/entity.hpp | 45 | ||||
-rw-r--r-- | test/entity.cpp | 29 |
2 files changed, 62 insertions, 12 deletions
diff --git a/src/entity.hpp b/src/entity.hpp index a5c9aa90..f1c38397 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -5,6 +5,7 @@ #include <type_traits> #include <utility> #include <tuple> +#include <typeinfo> #include <compat/function2.hpp> #include <Corrade/Containers/StringView.h> @@ -138,6 +139,16 @@ constexpr CORRADE_ALWAYS_INLINE bool find_in_tuple(F&& fun, Tuple&& tuple) } // namespace detail +struct erased_accessors final { + struct erased_reader_t; + struct erased_writer_t; + const erased_reader_t* reader; + const erased_writer_t* writer; + const char *object_type, *field_type; + void(*read_fun)(const void*, const erased_reader_t*, void*); + void(*write_fun)(void*, const erased_writer_t*, void*); +}; + struct EntityBase {}; template<typename Obj> @@ -161,15 +172,37 @@ struct Entity final : EntityBase { using Writer = W; StringView name; - [[no_unique_address]] Reader reader; - [[no_unique_address]] Writer writer; + [[no_unique_address]] R reader; + [[no_unique_address]] W writer; constexpr field(const field&) = default; constexpr field& operator=(const field&) = default; - constexpr decltype(auto) read(const Obj& x) const { return detail::read_field<Obj, Type, R>::read(x, reader); } - constexpr void write(Obj& x, move_qualified<Type> v) const { detail::write_field<Obj, Type, W>::write(x, writer, v); } - - constexpr field(StringView name, Reader r, Writer w) noexcept : name{name}, reader{r}, writer{w} {} + static constexpr decltype(auto) read(const R& reader, const Obj& x) { return detail::read_field<Obj, Type, R>::read(x, reader); } + static constexpr void write(const W& writer, Obj& x, move_qualified<Type> v) { detail::write_field<Obj, Type, W>::write(x, writer, v); } + constexpr decltype(auto) read(const Obj& x) const { return read(reader, x); } + constexpr void write(Obj& x, move_qualified<Type> value) const { write(writer, x, value); } + consteval field(StringView name, R r, W w) noexcept : name{name}, reader{r}, writer{w} {} + + erased_accessors accessors() const { + using reader_t = typename erased_accessors::erased_reader_t; + using writer_t = typename erased_accessors::erased_writer_t; + return erased_accessors { + reinterpret_cast<const reader_t*>(&reader), reinterpret_cast<const writer_t*>(&writer), + typeid(Obj).name(), typeid(Type).name(), + [](const void* obj, const reader_t* reader, void* value) { + const auto& obj_ = *reinterpret_cast<const Obj*>(obj); + const auto& reader_ = *reinterpret_cast<const R*>(reader); + auto& value_ = *reinterpret_cast<Type*>(value); + value_ = read(reader_, obj_); + }, + [](void* obj, const writer_t* writer, void* value) { + auto& obj_ = *reinterpret_cast<Obj*>(obj); + const auto& writer_ = *reinterpret_cast<const W*>(writer); + auto&& value_ = std::move(*reinterpret_cast<Type*>(value)); + write(writer_, obj_, value_); + }, + }; + } }; template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> diff --git a/test/entity.cpp b/test/entity.cpp index 8f762d73..1bfed35b 100644 --- a/test/entity.cpp +++ b/test/entity.cpp @@ -65,23 +65,40 @@ static constexpr bool test_visitor() } static void test_fun2() { - auto x = TestAccessors{1, 2, 3}; - static constexpr auto read_fn = [](const TestAccessors& x) { return x.bar(); }; - static constexpr auto write_fn = [](TestAccessors& x, int value) { x.set_bar(value); }; - static constexpr auto read_bar = fu2::function_view<int(const TestAccessors&) const>{read_fn}; - static constexpr auto write_bar = fu2::function_view<void(TestAccessors&, int) const>{write_fn}; - static constexpr auto m_bar2 = entity::type<int>::field{"bar"_s, read_bar, write_bar}; + static constexpr auto read_fn = [](const TestAccessors& x) constexpr { return x.bar(); }; + static constexpr auto write_fn = [](TestAccessors& x, int value) constexpr { x.set_bar(value); }; + constexpr auto read_bar = fu2::function_view<int(const TestAccessors&) const>{read_fn}; + constexpr auto write_bar = fu2::function_view<void(TestAccessors&, int) const>{write_fn}; + constexpr auto m_bar2 = entity::type<int>::field{"bar"_s, read_bar, write_bar}; + auto x = TestAccessors{1, 2, 3}; fm_assert(m_bar2.read(x) == 2); m_bar2.write(x, 22); fm_assert(m_bar2.read(x) == 22); } +static void test_erasure() { + erased_accessors accessors[] = { + m_foo.accessors(), + m_bar.accessors(), + m_baz.accessors(), + }; + auto obj = TestAccessors{1, 2, 3}; + int value = 0; + accessors[1].read_fun(&obj, accessors[1].reader, &value); + fm_assert(value == 2); + int value2 = 22222, value2_ = 0; + accessors[1].write_fun(&obj, accessors[1].writer, &value2); + accessors[1].read_fun(&obj, accessors[1].reader, &value2_); + fm_assert(value2 == value2_); +} + void test_app::test_entity() { static_assert(test_accessors()); static_assert(test_visitor()); test_fun2(); + test_erasure(); } } // namespace floormat |