summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-16 15:46:51 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-16 15:46:56 +0100
commit65b3b6603e8761a9629f7da19c352384bad2d4bf (patch)
tree217953be2dd647c061fd01444cfe5c0ec55a3b16
parent060168dd1181bb38126e61819ca199b85f7c8fed (diff)
entity: add type erasure support
-rw-r--r--src/entity.hpp45
-rw-r--r--test/entity.cpp29
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