diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-19 12:38:40 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-19 12:38:40 +0100 |
commit | 3393e34574e1a30ffc4f7a8d24ec081d0cea6170 (patch) | |
tree | fd4dc830725aad8a2bc54269e718484d2a8b013c /entity | |
parent | b848223b881c8cc2f0e519fd294f151d5def5369 (diff) |
entity: wip optional arguments
Diffstat (limited to 'entity')
-rw-r--r-- | entity/accessor.hpp | 10 | ||||
-rw-r--r-- | entity/constraints.hpp | 78 | ||||
-rw-r--r-- | entity/metadata.hpp | 92 |
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...>; }; }; |