summaryrefslogtreecommitdiffhomepage
path: root/entity
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-19 12:38:40 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-19 12:38:40 +0100
commit3393e34574e1a30ffc4f7a8d24ec081d0cea6170 (patch)
treefd4dc830725aad8a2bc54269e718484d2a8b013c /entity
parentb848223b881c8cc2f0e519fd294f151d5def5369 (diff)
entity: wip optional arguments
Diffstat (limited to 'entity')
-rw-r--r--entity/accessor.hpp10
-rw-r--r--entity/constraints.hpp78
-rw-r--r--entity/metadata.hpp92
3 files changed, 142 insertions, 38 deletions
diff --git a/entity/accessor.hpp b/entity/accessor.hpp
index 08f5ddaf..f069cb5b 100644
--- a/entity/accessor.hpp
+++ b/entity/accessor.hpp
@@ -5,6 +5,8 @@
namespace floormat::entities {
+enum class field_status : unsigned char { enabled, hidden, readonly, };
+
struct erased_accessor final {
using erased_reader_t = void;
using erased_writer_t = void;
@@ -18,14 +20,14 @@ struct erased_accessor final {
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*);
+ field_status(*predicate_fun)(const Object*, const erased_predicate_t*);
constexpr erased_accessor(const erased_accessor&) = default;
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*)) :
+ field_status(*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}
@@ -44,7 +46,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;
+ template<typename Obj> field_status is_enabled(const Obj& x) const noexcept;
constexpr bool can_write() const noexcept { return writer != nullptr; }
};
@@ -116,7 +118,7 @@ void erased_accessor::write(Obj& x, move_qualified<FieldType> value) const noexc
}
template<typename Obj>
-bool erased_accessor::is_enabled(const Obj& x) const noexcept
+field_status 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>;
diff --git a/entity/constraints.hpp b/entity/constraints.hpp
new file mode 100644
index 00000000..21d549c5
--- /dev/null
+++ b/entity/constraints.hpp
@@ -0,0 +1,78 @@
+#pragma once
+#include <cmath>
+#include <type_traits>
+#include <utility>
+#include <algorithm>
+#include <Corrade/Containers/StringView.h>
+
+namespace floormat::entities::erased_constraints {
+
+static_assert(sizeof(std::size_t) == sizeof(std::uintptr_t));
+static_assert(sizeof(std::size_t) == sizeof(std::ptrdiff_t));
+
+struct range final {
+ using U = std::size_t;
+ using I = std::make_signed_t<U>;
+ enum type_ : unsigned char { type_none, type_float, type_uint, type_int, };
+ union element {
+ float f;
+ U u;
+ I i;
+ };
+
+ element min {.i = 0}, max {.i = 0};
+ type_ type = type_none;
+
+ template<typename T> constexpr std::pair<T, T> convert() const;
+};
+
+template<typename T> constexpr std::pair<T, T> range::convert() const
+{
+ using limits = std::numeric_limits<T>;
+ switch (type) {
+ case type_float:
+ if constexpr (limits::is_integer())
+ return { T(std::floor(min.f)), T(std::ceil(max.f)) };
+ else
+ return { min.f, max.f };
+ case type_uint: return { std::max(T(min.u), limits::min()), std::min(T(max.u), limits::max()) };
+ case type_int: return { std::max(T(min.i), limits::min()), std::min(T(max.i), limits::max()) };
+ default: case type_none: return { limits::min(), limits::max() };
+ }
+}
+
+struct length final {
+ std::size_t value = (std::size_t)-1;
+};
+
+struct group final {
+ StringView group_name;
+};
+
+} // namespace floormat::entities::erased_constraints
+
+namespace floormat::entities::constraints {
+
+template<typename T> struct range {
+ using limits = std::numeric_limits<T>;
+ T min = limits::min(), max = limits::max();
+
+ constexpr operator erased_constraints::range() const;
+};
+
+template<typename T> constexpr range<T>::operator erased_constraints::range() const
+{
+ using enum erased_constraints::range::type_;
+ if constexpr (std::is_floating_point_v<T>)
+ return { { .f = min }, { .f = max }, type_float };
+ if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>)
+ return { {.u = min}, {.u = max}, type_uint };
+ if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
+ return { {.i = min}, {.i = max}, type_int };
+ return { {}, {}, type_none };
+}
+
+using length = erased_constraints::length;
+using group = erased_constraints::group;
+
+} // namespace floormat::entities::constraints
diff --git a/entity/metadata.hpp b/entity/metadata.hpp
index dc7d9f1d..cbfcd38a 100644
--- a/entity/metadata.hpp
+++ b/entity/metadata.hpp
@@ -1,10 +1,12 @@
#pragma once
#include "name-of.hpp"
#include "accessor.hpp"
+#include "constraints.hpp"
#include "util.hpp"
#include <cstddef>
#include <concepts>
#include <type_traits>
+#include <limits>
#include <utility>
#include <tuple>
#include <array>
@@ -58,11 +60,6 @@ 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>
@@ -142,22 +139,53 @@ template<typename T> using decay_tuple = typename decay_tuple_<T>::type;
template<typename T> struct accessors_for_ { using type = decay_tuple<std::decay_t<decltype(T::accessors())>>; };
template<typename T> using accessors_for = typename accessors_for_<T>::type;
+template<typename Obj, typename Type, typename Default, std::size_t I, typename... Fs> struct find_reader_;
+
+template<typename Obj, typename Type, typename Default, std::size_t I> struct find_reader_<Obj, Type, Default, I> {
+ using type = Default;
+ static constexpr std::size_t index = I;
+};
+
+template<typename Obj, typename Type, typename Default, std::size_t I, typename F, typename... Fs>
+struct find_reader_<Obj, Type, Default, I, F, Fs...> {
+ using type = typename find_reader_<Obj, Type, Default, I+1, Fs...>::type;
+ static constexpr std::size_t index = find_reader_<Obj, Type, Default, I+1, Fs...>::index;
+};
+
+template<typename Obj, typename Type, typename Default, std::size_t I, typename F, typename... Fs>
+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 Default, typename... Fs>
+using find_reader = typename find_reader_<Obj, Type, Default, 0, std::decay_t<Fs>...>::type;
+
+template<typename Obj, typename Type, typename Default, typename... Fs>
+constexpr std::size_t find_reader_index = find_reader_<Obj, Type, Default, 0, std::decay_t<Fs>...>::index;
+
+template<typename Obj, auto constant>
+constexpr auto constantly = [](const Obj&) constexpr { return constant; };
+
+
} // namespace detail
template<typename Obj, typename Type> struct entity_field_base {};
-template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, FieldPredicate<Obj> P = std::nullptr_t>
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
struct entity_field : entity_field_base<Obj, Type> {
+private:
+ static constexpr auto default_predicate = detail::constantly<Obj, field_status::enabled>;
+ using default_predicate_t = std::decay_t<decltype(default_predicate)>;
+public:
using ObjectType = Obj;
using FieldType = Type;
using Reader = R;
using Writer = W;
- using Predicate = P;
+ using Predicate = std::decay_t<detail::find_reader<Obj, field_status, default_predicate_t, Ts...>>;
StringView name;
[[no_unique_address]] R reader;
[[no_unique_address]] W writer;
- [[no_unique_address]] P predicate;
+ [[no_unique_address]] Predicate predicate;
constexpr entity_field(const entity_field&) = default;
constexpr entity_field& operator=(const entity_field&) = default;
@@ -165,25 +193,29 @@ 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, 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} {}
+ 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 entity_field(StringView name, R r, W w, Ts&&... ts) noexcept :
+ name{name}, reader{r}, writer{w},
+ predicate{std::get<detail::find_reader_index<Obj, field_status, default_predicate_t, Ts...>>(std::forward_as_tuple(ts..., default_predicate))}
+ {}
constexpr erased_accessor erased() const;
};
-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)
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr void entity_field<Obj, Type, R, W, Ts...>::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, FieldPredicate<Obj> P>
-constexpr erased_accessor entity_field<Obj, Type, R, W, P>::erased() const
+template<typename Obj, typename Type, FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+constexpr erased_accessor entity_field<Obj, Type, R, W, Ts...>::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>;
+ using P = Predicate;
constexpr auto reader_fn = [](const void* obj, const reader_t* reader, void* value) {
const auto& obj_ = *reinterpret_cast<const Obj*>(obj);
@@ -202,29 +234,21 @@ constexpr erased_accessor entity_field<Obj, Type, R, W, P>::erased() const
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,
- !std::is_same_v<P, std::nullptr_t> ? (const void*)&predicate : nullptr,
+ (void*)&reader, writer ? (void*)&writer : nullptr, (void*)&predicate,
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,
+ reader_fn, writer ? writer_fn : writer_stub_fn, predicate_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)
+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)
{
- if constexpr(std::is_same_v<P, std::nullptr_t>)
- return true;
- else
- return detail::read_field<Obj, Type, P>::read(x, p);
+ return detail::read_field<Obj, field_status, Predicate>::read(x, p);
}
template<typename Obj>
@@ -234,16 +258,16 @@ struct Entity final {
template<typename Type>
struct type final
{
- 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>
+ template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+ struct field final : entity_field<Obj, Type, R, W, Ts...>
{
- 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}
+ constexpr field(StringView field_name, R r, W w, Ts&&... ts) noexcept :
+ entity_field<Obj, Type, R, W, Ts...>{field_name, r, w, std::forward<Ts>(ts)...}
{}
};
- 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>;
+ template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
+ field(StringView name, R r, W w, Ts&&... ts) -> field<R, W, Ts...>;
};
};