diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-18 20:42:50 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-18 20:42:50 +0100 |
commit | 167798dd34886c93657534ac8f976418b455a5d6 (patch) | |
tree | 045f2a1b4f5dfe5086ce746faf13831a6de19030 | |
parent | 5c0742fe7c1e21fb491d5380e6761644a5064c5e (diff) |
entity: add is-enabled predicate
-rw-r--r-- | entity/accessor.hpp | 27 | ||||
-rw-r--r-- | entity/metadata.hpp | 57 |
2 files changed, 63 insertions, 21 deletions
diff --git a/entity/accessor.hpp b/entity/accessor.hpp index b88b6686..08f5ddaf 100644 --- a/entity/accessor.hpp +++ b/entity/accessor.hpp @@ -8,22 +8,27 @@ namespace floormat::entities { struct erased_accessor final { using erased_reader_t = void; using erased_writer_t = void; + using erased_predicate_t = void; using Object = void; using Value = void; const erased_reader_t* reader; const erased_writer_t* writer; + const erased_predicate_t* predicate; StringView field_name, object_type, field_type; void(*read_fun)(const Object*, const erased_reader_t*, Value*); void(*write_fun)(Object*, const erased_writer_t*, Value*); + bool(*predicate_fun)(const Object*, const erased_predicate_t*); constexpr erased_accessor(const erased_accessor&) = default; - constexpr erased_accessor(erased_reader_t* reader, erased_writer_t * writer, StringView field_name, - StringView object_name, StringView field_type_name, - void(*read_fun)(const Object*, const erased_reader_t*, Value*), - void(*write_fun)(Object*, const erased_writer_t*, Value*)) : - reader{reader}, writer{writer}, field_name{field_name}, object_type{object_name}, field_type{field_type_name}, - read_fun{read_fun}, write_fun{write_fun} + constexpr erased_accessor(const erased_reader_t* reader, const erased_writer_t* writer, const erased_predicate_t* predicate, + StringView field_name, StringView object_name, StringView field_type_name, + void(*read_fun)(const Object*, const erased_reader_t*, Value*), + void(*write_fun)(Object*, const erased_writer_t*, Value*), + bool(*predicate_fun)(const Object*, const erased_predicate_t*)) : + reader{reader}, writer{writer}, predicate{predicate}, + field_name{field_name}, object_type{object_name}, field_type{field_type_name}, + read_fun{read_fun}, write_fun{write_fun}, predicate_fun{predicate_fun} {} template<typename T, typename FieldType> @@ -39,6 +44,7 @@ struct erased_accessor final { template<typename Obj, typename FieldType> requires std::is_default_constructible_v<FieldType> FieldType read(const Obj& x) const noexcept; template<typename Obj, typename FieldType> void read(const Obj& x, FieldType& value) const noexcept; template<typename Obj, typename FieldType> void write(Obj& x, move_qualified<FieldType> value) const noexcept; + template<typename Obj> bool is_enabled(const Obj& x) const noexcept; constexpr bool can_write() const noexcept { return writer != nullptr; } }; @@ -109,4 +115,13 @@ void erased_accessor::write(Obj& x, move_qualified<FieldType> value) const noexc write_unchecked<Obj, FieldType>(x, value); } +template<typename Obj> +bool erased_accessor::is_enabled(const Obj& x) const noexcept +{ + static_assert(!std::is_pointer_v<Obj> && !std::is_reference_v<Obj>); + constexpr auto obj = name_of<Obj>; + fm_assert(obj.data() == object_type.data() || obj == object_type); + return predicate_fun(&x, predicate); +} + } // namespace floormat::entities diff --git a/entity/metadata.hpp b/entity/metadata.hpp index 4e18493d..a35e0cc6 100644 --- a/entity/metadata.hpp +++ b/entity/metadata.hpp @@ -58,6 +58,11 @@ concept FieldWriter = requires { std::same_as<F, std::nullptr_t>; }; +template<typename F, typename T> +concept FieldPredicate = requires { + requires FieldReader<F, T, bool> || std::same_as<F, std::nullptr_t>; +}; + namespace detail { template<typename Obj, typename Type, FieldReader<Obj, Type> R> @@ -141,16 +146,18 @@ template<typename T> using accessors_for = typename accessors_for_<T>::type; template<typename Obj, typename Type> struct entity_field_base {}; -template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P = std::nullptr_t> struct entity_field : entity_field_base<Obj, Type> { using ObjectType = Obj; using FieldType = Type; using Reader = R; using Writer = W; + using Predicate = P; StringView name; [[no_unique_address]] R reader; [[no_unique_address]] W writer; + [[no_unique_address]] P predicate; constexpr entity_field(const entity_field&) = default; constexpr entity_field& operator=(const entity_field&) = default; @@ -158,22 +165,24 @@ struct entity_field : entity_field_base<Obj, Type> { static constexpr void write(const W& writer, Obj& x, move_qualified<Type> 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); } - static constexpr bool can_write = !std::is_same_v<std::nullptr_t, decltype(entity_field<Obj, Type, R, W>::writer)>; - constexpr entity_field(StringView name, R r, W w) noexcept : name{name}, reader{r}, writer{w} {} + static constexpr bool can_write = !std::is_same_v<std::nullptr_t, decltype(entity_field<Obj, Type, R, W, P>::writer)>; + static constexpr bool is_enabled(const P& p, const Obj& x); + constexpr entity_field(StringView name, R r, W w, P p = nullptr) noexcept : name{name}, reader{r}, writer{w}, predicate{p} {} constexpr erased_accessor erased() const; }; -template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> -constexpr void entity_field<Obj, Type, R, W>::write(const W& writer, Obj& x, move_qualified<Type> v) +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P> +constexpr void entity_field<Obj, Type, R, W, P>::write(const W& writer, Obj& x, move_qualified<Type> v) { static_assert(can_write); detail::write_field<Obj, Type, W>::write(x, writer, v); } -template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> -constexpr erased_accessor entity_field<Obj, Type, R, W>::erased() const +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P> +constexpr erased_accessor entity_field<Obj, Type, R, W, P>::erased() const { using reader_t = typename erased_accessor::erased_reader_t; using writer_t = typename erased_accessor::erased_writer_t; + using predicate_t = typename erased_accessor::erased_predicate_t ; constexpr auto obj_name = name_of<Obj>, field_name = name_of<Type>; constexpr auto reader_fn = [](const void* obj, const reader_t* reader, void* value) { @@ -188,18 +197,36 @@ constexpr erased_accessor entity_field<Obj, Type, R, W>::erased() const move_qualified<Type> value_ = std::move(*reinterpret_cast<Type*>(value)); write(writer_, obj_, value_); }; + constexpr auto predicate_fn = [](const void* obj, const predicate_t* predicate) { + const auto& obj_ = *reinterpret_cast<const Obj*>(obj); + const auto& predicate_ = *reinterpret_cast<const P*>(predicate); + return is_enabled(predicate_, obj_); + }; + constexpr auto predicate_stub_fn = [](const void*, const predicate_t*) { + return true; + }; constexpr auto writer_stub_fn = [](void*, const writer_t*, void*) { fm_abort("no writer for this accessor"); }; return erased_accessor { (void*)&reader, writer ? (void*)&writer : nullptr, - name, - obj_name, field_name, + std::is_same_v<P, std::nullptr_t> ? (const void*)&predicate : nullptr, + name, obj_name, field_name, reader_fn, writer ? writer_fn : writer_stub_fn, + std::is_same_v<P, std::nullptr_t> ? predicate_fn : predicate_stub_fn, }; } +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P> +constexpr bool entity_field<Obj, Type, R, W, P>::is_enabled(const P& p, const Obj& x) +{ + if constexpr(std::is_same_v<P, std::nullptr_t>) + return true; + else + return detail::read_field<Obj, Type, P>::read(x, p); +} + template<typename Obj> struct Entity final { static_assert(std::is_same_v<Obj, std::decay_t<Obj>>); @@ -207,16 +234,16 @@ struct Entity final { template<typename Type> struct type final { - template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> - struct field final : entity_field<Obj, Type, R, W> + template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P = std::nullptr_t> + struct field final : entity_field<Obj, Type, R, W, P> { - constexpr field(StringView field_name, R r, W w) noexcept : - entity_field<Obj, Type, R, W>{field_name, r, w} + constexpr field(StringView field_name, R r, W w, P p = nullptr) noexcept : + entity_field<Obj, Type, R, W, P>{field_name, r, w, p} {} }; - template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W> - field(StringView name, R r, W w) -> field<R, W>; + template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P = std::nullptr_t> + field(StringView name, R r, W w, P p = nullptr) -> field<R, W, P>; }; }; |