diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-19 14:45:40 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-19 14:45:40 +0100 |
commit | 17ee71b537bf65923acc021a1ed382ab76df9f98 (patch) | |
tree | 1f6fad88a6a3dc10df29271b18bfae258b515d40 | |
parent | 9c1d2bb7979776c42248b47832e5a9d71a305e68 (diff) |
entity: finish adding non-erased constraints
Now only erased ones remain.
-rw-r--r-- | entity/constraints.hpp | 7 | ||||
-rw-r--r-- | entity/erased-constraints.hpp | 4 | ||||
-rw-r--r-- | entity/metadata.hpp | 68 | ||||
-rw-r--r-- | test/entity.cpp | 31 |
4 files changed, 80 insertions, 30 deletions
diff --git a/entity/constraints.hpp b/entity/constraints.hpp index 171c555a..bc991dfc 100644 --- a/entity/constraints.hpp +++ b/entity/constraints.hpp @@ -13,11 +13,12 @@ template<typename T> struct range using limits = std::numeric_limits<T>; T min = limits::min(), max = limits::max(); - constexpr operator erased_constraints::range() const; + constexpr operator erased_constraints::range() const noexcept; + constexpr operator std::pair<T, T>() const noexcept; }; template<typename T> -constexpr range<T>::operator erased_constraints::range() const +constexpr range<T>::operator erased_constraints::range() const noexcept { using enum erased_constraints::range::type_; if constexpr (std::is_floating_point_v<T>) @@ -29,6 +30,8 @@ constexpr range<T>::operator erased_constraints::range() const return { {}, {}, type_none }; } +template<typename T> constexpr range<T>::operator std::pair<T, T>() const noexcept { return { min, max }; } + using length = erased_constraints::length; using group = erased_constraints::group; diff --git a/entity/erased-constraints.hpp b/entity/erased-constraints.hpp index d0fdecab..f462472a 100644 --- a/entity/erased-constraints.hpp +++ b/entity/erased-constraints.hpp @@ -52,10 +52,14 @@ template<typename T> constexpr std::pair<T, T> range::convert() const struct length final { std::size_t value = std::numeric_limits<std::size_t>::max(); + constexpr operator std::size_t() const { return value; } }; struct group final { StringView group_name; + constexpr operator StringView() const { return group_name; } + constexpr group() = default; + constexpr group(StringView name) : group_name{name} {} }; } // namespace floormat::entities::erased_constraints diff --git a/entity/metadata.hpp b/entity/metadata.hpp index b425d0a1..60e9c458 100644 --- a/entity/metadata.hpp +++ b/entity/metadata.hpp @@ -4,6 +4,7 @@ #include "constraints.hpp" #include "util.hpp" #include "concepts.hpp" +#include "compat/defs.hpp" #include <cstddef> #include <concepts> #include <type_traits> @@ -65,9 +66,6 @@ template<typename Obj, typename Type, typename Default, std::size_t I, typename requires FieldReader<F, Obj, Type> struct find_reader<Obj, Type, Default, I, F, Fs...> { using type = F; static constexpr std::size_t index = I; }; -template<typename Obj, typename Type, typename... Fs> -using find_reader2 = find_reader<Obj, Type, Type, 0, Fs...>; - } // namespace floormat::entities::detail namespace floormat::entities { @@ -81,11 +79,17 @@ template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, struct entity_field : entity_field_base<Obj, Type> { private: static constexpr auto default_predicate = constantly<Obj, field_status::enabled>; + static constexpr auto default_c_range = constantly<Obj, constraints::range<Type>{}>; + static constexpr auto default_c_length = constantly<Obj, constraints::length{std::size_t(-1)}>; + static constexpr auto default_c_group = [](const Obj&) constexpr { return StringView{}; }; using default_predicate_t = std::decay_t<decltype(default_predicate)>; + using default_c_range_t = std::decay_t<decltype(default_c_range)>; + using default_c_length_t = std::decay_t<decltype(default_c_length)>; + using default_c_group_t = std::decay_t<decltype(default_c_group)>; using c_predicate = detail::find_reader<Obj, field_status, default_predicate_t, 0, Ts...>; - using c_range = detail::find_reader2<Obj, constraints::range<Type>, Ts...>; - using c_length = detail::find_reader2<Obj, constraints::length, Ts...>; - using c_group = detail::find_reader2<Obj, constraints::group, Ts...>; + using c_range = detail::find_reader<Obj, constraints::range<Type>, default_c_range_t, 0, Ts...>; + using c_length = detail::find_reader<Obj, constraints::length, default_c_length_t, 0, Ts...>; + using c_group = detail::find_reader<Obj, constraints::group, default_c_group_t, 0, Ts...>; static constexpr std::size_t good_arguments = unsigned(c_predicate::index != sizeof...(Ts)) + unsigned(c_range::index != sizeof...(Ts)) + @@ -95,13 +99,13 @@ private: public: using ObjectType = Obj; - using FieldType = Type; - using Reader = R; - using Writer = W; - using Predicate = typename c_predicate::type; - using Range = typename c_range::type; - using Length = typename c_length::type; - using Group = typename c_group::type; + using FieldType = Type; + using Reader = R; + using Writer = W; + using Predicate = typename c_predicate::type; + using Range = typename c_range::type; + using Length = typename c_length::type; + using Group = typename c_group::type; StringView name; [[no_unique_address]] R reader; @@ -111,20 +115,30 @@ public: [[no_unique_address]] Length length; [[no_unique_address]] Group group; - constexpr entity_field(const entity_field&) = default; - constexpr entity_field& operator=(const entity_field&) = default; + fm_DECLARE_DEFAULT_MOVE_COPY_ASSIGNMENTS(entity_field); + 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); 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, Ts...>::writer)>; + static constexpr field_status is_enabled(const Predicate & p, const Obj& x); + constexpr field_status is_enabled(const Obj& x) const { return is_enabled(predicate, x); } + + static constexpr std::pair<Type, Type> get_range(const Range& r, const Obj& x); + constexpr std::pair<Type, Type> get_range(const Obj& x) const { return get_range(range, x); } + static constexpr std::size_t get_max_length(const Length& l, const Obj& x); + constexpr std::size_t get_max_length(const Obj& x) const { return get_max_length(length, x); } + static constexpr StringView get_group(const Group& g, const Obj& x); + constexpr StringView get_group(const Obj& x) const { return get_group(group, x); } + constexpr entity_field(StringView name, R r, W w, Ts&&... ts) noexcept : name{name}, reader{r}, writer{w}, - predicate{std::get<c_predicate::index>(std::forward_as_tuple(ts..., default_predicate))}, - range{std::get<c_range::index>(std::forward_as_tuple(ts..., constraints::range<Type>{}))}, - length{std::get<c_length::index>(std::forward_as_tuple(ts..., constraints::length{}))}, - group{std::get<c_length::index>(std::forward_as_tuple(ts..., constraints::group{}))} + predicate { std::get<c_predicate::index>(std::forward_as_tuple(ts..., default_predicate)) }, + range { std::get<c_range::index> (std::forward_as_tuple(ts..., default_c_range)) }, + length { std::get<c_length::index> (std::forward_as_tuple(ts..., default_c_length)) }, + group { std::get<c_group::index> (std::forward_as_tuple(ts..., default_c_group)) } {} constexpr erased_accessor erased() const; }; @@ -174,9 +188,19 @@ constexpr erased_accessor entity_field<Obj, Type, R, W, Ts...>::erased() const template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts> constexpr field_status entity_field<Obj, Type, R, W, Ts...>::is_enabled(const Predicate& p, const Obj& x) -{ - return detail::read_field<Obj, field_status, Predicate>::read(x, p); -} +{ return detail::read_field<Obj, field_status, Predicate>::read(x, p); } + +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts> +constexpr std::pair<Type, Type> entity_field<Obj, Type, R, W, Ts...>::get_range(const Range& r, const Obj& x) +{ return detail::read_field<Obj, constraints::range<Type>, Range>::read(x, r); } + +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts> +constexpr std::size_t entity_field<Obj, Type, R, W, Ts...>::get_max_length(const Length& l, const Obj& x) +{ return detail::read_field<Obj, constraints::length, Length>::read(x, l); } + +template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts> +constexpr StringView entity_field<Obj, Type, R, W, Ts...>::get_group(const Group& g, const Obj& x) +{ return detail::read_field<Obj, constraints::group, Group>::read(x, g); } template<typename Obj> struct Entity final { diff --git a/test/entity.cpp b/test/entity.cpp index faaa0d41..d09c94ba 100644 --- a/test/entity.cpp +++ b/test/entity.cpp @@ -146,13 +146,12 @@ void test_type_name() static_assert(name_of<foobar2>.data() == name_of<foobar>.data()); } -constexpr bool test_null_writer() +[[maybe_unused]] constexpr void test_null_writer() { constexpr auto foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, nullptr}; static_assert(foo.writer == nullptr); static_assert(!foo.can_write); static_assert(std::get<0>(TestAccessors::accessors()).can_write); - return true; } void test_predicate() @@ -160,14 +159,14 @@ void test_predicate() constexpr TestAccessors x{0, 0, 0}; constexpr auto foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, [](const TestAccessors&) { return field_status::hidden; }}; - static_assert(foo.is_enabled(foo.predicate, x) == field_status::hidden); + static_assert(foo.is_enabled(x) == field_status::hidden); fm_assert(foo.erased().is_enabled(x) == field_status::hidden); constexpr auto foo2 = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, [](const TestAccessors&) { return field_status::readonly; }}; - static_assert(foo2.is_enabled(foo2.predicate, x) == field_status::readonly); + static_assert(foo2.is_enabled(x) == field_status::readonly); fm_assert(foo2.erased().is_enabled(x) == field_status::readonly); constexpr auto foo3 = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; - static_assert(foo3.is_enabled(foo3.predicate, x) == field_status::enabled); + static_assert(foo3.is_enabled(x) == field_status::enabled); fm_assert(foo3.erased().is_enabled(x) == field_status::enabled); } @@ -187,19 +186,39 @@ constexpr bool test_names() return true; } +constexpr void test_range() +{ + constexpr auto x = TestAccessors{}; + constexpr auto foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly<TestAccessors, constraints::length{42}>, + constantly<TestAccessors, constraints::range<int>{37, 42}>, + [](const TestAccessors&) constexpr -> constraints::group { return "foo"_s; }}; + + using limits = std::numeric_limits<int>; + + static_assert(foo.get_range(x) == std::pair<int, int>{37, 42}); + static_assert(foo.get_max_length(x) == 42); + static_assert(foo.get_group(x) == "foo"_s); + + static_assert(m_foo.get_range(x) == std::pair<int, int>{limits::min(), limits::max()}); + static_assert(m_foo.get_max_length(x) == (std::size_t)-1); + static_assert(m_foo.get_group(x) == ""_s); +} + } // namespace void test_app::test_entity() { static_assert(test_accessors()); static_assert(test_visitor()); - static_assert(test_null_writer()); + test_null_writer(); static_assert(test_names()); test_predicate(); test_fun2(); test_erasure(); test_type_name(); test_metadata(); + test_range(); } } // namespace floormat |