summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-19 14:45:40 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-19 14:45:40 +0100
commit17ee71b537bf65923acc021a1ed382ab76df9f98 (patch)
tree1f6fad88a6a3dc10df29271b18bfae258b515d40
parent9c1d2bb7979776c42248b47832e5a9d71a305e68 (diff)
entity: finish adding non-erased constraints
Now only erased ones remain.
-rw-r--r--entity/constraints.hpp7
-rw-r--r--entity/erased-constraints.hpp4
-rw-r--r--entity/metadata.hpp68
-rw-r--r--test/entity.cpp31
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