From 50d4d02508767ed3cb67bf1ed424c61c23e44117 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 18 Nov 2022 12:04:26 +0100 Subject: entity: add read-only property support --- entity/accessor.hpp | 1 + entity/entity.hpp | 9 ++++++++- test/entity.cpp | 40 +++++++++++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/entity/accessor.hpp b/entity/accessor.hpp index 9b836420..a097afd4 100644 --- a/entity/accessor.hpp +++ b/entity/accessor.hpp @@ -40,6 +40,7 @@ struct erased_accessor final { template requires std::is_default_constructible_v FieldType read(const Obj& x) const noexcept; template void read(const Obj& x, FieldType& value) const noexcept; template void write(Obj& x, move_qualified value) const noexcept; + constexpr bool can_write() const noexcept { return writer != nullptr; } }; template diff --git a/entity/entity.hpp b/entity/entity.hpp index 4eca858e..30c75c15 100644 --- a/entity/entity.hpp +++ b/entity/entity.hpp @@ -56,7 +56,8 @@ template concept FieldWriter = requires { requires FieldWriter_memfn || FieldWriter_ptr || - FieldWriter_function; + FieldWriter_function || + std::same_as; }; namespace detail { @@ -100,6 +101,11 @@ struct write_field static constexpr void write(Obj& x, F&& fun, move_qualified value) { fun(x, value); } }; +template +struct write_field { + static constexpr void write(Obj&, std::nullptr_t, move_qualified) { fm_abort("no writing for this accessor"); } +}; + template requires std::invocable(std::declval()))> constexpr CORRADE_ALWAYS_INLINE void visit_tuple(F&& fun, Tuple&& tuple) @@ -152,6 +158,7 @@ struct entity_field : entity_field_base { static constexpr void write(const W& writer, Obj& x, move_qualified v) { detail::write_field::write(x, writer, v); } constexpr decltype(auto) read(const Obj& x) const { return read(reader, x); } constexpr void write(Obj& x, move_qualified value) const { write(writer, x, value); } + static constexpr bool can_write = !std::is_same_v::writer)>; constexpr entity_field(StringView name, R r, W w) noexcept : name{name}, reader{r}, writer{w} {} constexpr erased_accessor erased() const; }; diff --git a/test/entity.cpp b/test/entity.cpp index 8f966572..7832eae2 100644 --- a/test/entity.cpp +++ b/test/entity.cpp @@ -7,6 +7,8 @@ using namespace floormat; using namespace floormat::entities; +namespace { + struct TestAccessors { constexpr int bar() const { return _bar; } constexpr void set_bar(int value) { _bar = value; } @@ -32,15 +34,19 @@ constexpr auto TestAccessors::accessors() noexcept } using entity = Entity; -static constexpr auto m_foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; -static constexpr auto m_bar = entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}; -static constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; -static constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; -static constexpr auto m_baz = entity::type::field("baz"_s, r_baz, w_baz); +constexpr auto m_foo = entity::type::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; +constexpr auto m_bar = entity::type::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}; +constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; +constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; +constexpr auto m_baz = entity::type::field("baz"_s, r_baz, w_baz); + +} // namespace namespace floormat { -static constexpr bool test_accessors() +namespace { + +constexpr bool test_accessors() { auto x = TestAccessors{111, 222, 333}; @@ -59,7 +65,7 @@ static constexpr bool test_accessors() return true; } -static constexpr bool test_visitor() +constexpr bool test_visitor() { { constexpr auto tuple = std::make_tuple((unsigned char)1, (unsigned short)2, (int)3, (long)4); @@ -81,7 +87,7 @@ static constexpr bool test_visitor() return true; } -static void test_fun2() { +void test_fun2() { 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{read_fn}; @@ -94,7 +100,7 @@ static void test_fun2() { fm_assert(m_bar2.read(x) == 22); } -static void test_erasure() { +void test_erasure() { erased_accessor accessors[] = { m_foo.erased(), m_bar.erased(), @@ -110,7 +116,7 @@ static void test_erasure() { fm_assert(value2 == value2_); } -static void test_metadata() +void test_metadata() { constexpr auto m = entity_metadata(); fm_assert(m.class_name == name_of); @@ -127,7 +133,7 @@ static void test_metadata() fm_assert(baz2.read(x) == 3); } -static void test_type_name() +void test_type_name() { struct foobar; constexpr StringView name = name_of; @@ -137,10 +143,22 @@ static void test_type_name() static_assert(name_of != name_of); } +constexpr bool test_null_writer() +{ + constexpr auto m_foo = entity::type::field{"foo"_s, &TestAccessors::foo, nullptr}; + static_assert(m_foo.writer == nullptr); + static_assert(!m_foo.can_write); + static_assert(std::get<0>(TestAccessors::accessors()).can_write); + return true; +} + +} // namespace + void test_app::test_entity() { static_assert(test_accessors()); static_assert(test_visitor()); + static_assert(test_null_writer()); test_fun2(); test_erasure(); test_type_name(); -- cgit v1.2.3