#pragma once #include "util.hpp" #include "erased-constraints.hpp" #include "name-of.hpp" #include #include #include #include namespace floormat::erased_constraints { struct range; struct max_length; struct group; } // namespace floormat::erased_constraints namespace floormat::entities { enum class field_status : unsigned char { hidden, readonly, enabled, }; struct erased_accessor final { using reader_t = void; using writer_t = void; using predicate_t = void; using c_range_t = void; using c_length_t = void; using Object = void; using Value = void; const reader_t* reader = nullptr; const writer_t* writer = nullptr; const predicate_t* predicate = nullptr; const c_range_t* range = nullptr; const c_length_t* length = nullptr; StringView field_name, object_type, field_type; void(*read_fun)(const Object*, const reader_t*, Value*) = nullptr; void(*write_fun)(Object*, const writer_t*, Value*) = nullptr; field_status(*predicate_fun)(const Object*, const predicate_t*) = nullptr; erased_constraints::range(*range_fun)(const Object*, const c_range_t*) = nullptr; erased_constraints::max_length(*length_fun)(const Object*, const c_length_t*) = nullptr; explicit constexpr erased_accessor() noexcept = default; constexpr erased_accessor(const erased_accessor&) = default; constexpr erased_accessor(const reader_t* reader, const writer_t* writer, const predicate_t* predicate, const c_range_t* range, const c_length_t* length, StringView field_name, StringView object_name, StringView field_type_name, void(*read_fun)(const Object*, const reader_t*, Value*), void(*write_fun)(Object*, const writer_t*, Value*), field_status(*predicate_fun)(const Object*, const predicate_t*), erased_constraints::range(*range_fun)(const Object*, const c_range_t*), erased_constraints::max_length(*length_fun)(const Object*, const c_length_t*)) : reader{reader}, writer{writer}, predicate{predicate}, range{range}, length{length}, 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}, range_fun{range_fun}, length_fun{length_fun} {} template [[nodiscard]] static constexpr bool check_name_static(); template [[nodiscard]] constexpr bool check_name() const noexcept; template [[nodiscard]] constexpr bool check_field_type() const noexcept; template constexpr void do_asserts() const; template constexpr void assert_name() const noexcept; template void read_unchecked(const Obj& x, FieldType& value) const noexcept; template requires std::is_default_constructible_v FieldType read_unchecked(const Obj& x) const noexcept; template void write_unchecked(Obj& x, move_qualified value) const noexcept; template requires std::is_default_constructible_v FieldType read(const Obj& x) const noexcept; template void read(const Obj& x, FieldType& value) const noexcept; template void write(Obj& x, move_qualified value) const noexcept; inline field_status is_enabled(const void* x) const noexcept; inline bool can_write() const noexcept { return writer != nullptr; } inline erased_constraints::range get_range(const void* x) const noexcept; inline erased_constraints::max_length get_max_length(const void* x) const noexcept; }; template constexpr bool erased_accessor::check_name_static() { return !std::is_pointer_v && !std::is_reference_v && !std::is_pointer_v && !std::is_reference_v; } template constexpr void erased_accessor::do_asserts() const { static_assert(!std::is_pointer_v && !std::is_reference_v); constexpr auto obj = name_of; fm_assert(obj.data() == object_type.data() || obj == object_type); } template constexpr bool erased_accessor::check_name() const noexcept { static_assert(check_name_static()); constexpr auto obj = name_of, field = name_of; return (obj.data() == object_type.data() && field.data() == field_type.data()) || obj == object_type && field == field_type; } template constexpr bool erased_accessor::check_field_type() const noexcept { constexpr auto name = name_of; return field_type == name; } template constexpr void erased_accessor::assert_name() const noexcept { fm_assert(check_name()); } template void erased_accessor::read_unchecked(const Obj& x, FieldType& value) const noexcept { static_assert(check_name_static()); read_fun(&x, reader, &value); } template requires std::is_default_constructible_v FieldType erased_accessor::read_unchecked(const Obj& x) const noexcept { static_assert(check_name_static()); FieldType value; read_unchecked(x, value); return value; } template void erased_accessor::write_unchecked(Obj& x, move_qualified value) const noexcept { static_assert(check_name_static()); write_fun(&x, writer, &value); } template requires std::is_default_constructible_v FieldType erased_accessor::read(const Obj& x) const noexcept { assert_name(); return read_unchecked(x); } template void erased_accessor::read(const Obj& x, FieldType& value) const noexcept { assert_name(); read_unchecked(x, value); } template void erased_accessor::write(Obj& x, move_qualified value) const noexcept { assert_name(); write_unchecked(x, value); } field_status erased_accessor::is_enabled(const void* x) const noexcept { return predicate_fun(x, predicate); } erased_constraints::range erased_accessor::get_range(const void* x) const noexcept { return range_fun(x,range); } erased_constraints::max_length erased_accessor::get_max_length(const void* x) const noexcept { return length_fun(x,length); } } // namespace floormat::entities