#pragma once #include #include #include #include #include #define OV_DETAIL_GET_TYPE_BASE_CLASS(CLASS) \ static constexpr std::string_view get_type_static() { return ::ovdl::detail::type_name(); } \ constexpr virtual std::string_view get_type() const = 0; \ static constexpr std::string_view get_base_type_static() { return ::ovdl::detail::type_name(); } \ constexpr virtual std::string_view get_base_type() const { return get_base_type_static(); } \ template constexpr bool is_type() const { \ return get_type().compare(::ovdl::detail::type_name()) == 0; } \ template constexpr bool is_derived_from() const { \ return is_type() || get_base_type().compare(::ovdl::detail::type_name()) == 0; } \ template constexpr T* cast_to() { \ if (is_derived_from() || is_type()) return (static_cast(this)); \ return nullptr; } \ template constexpr const T* const cast_to() const { \ if (is_derived_from() || is_type()) return (static_cast(this)); \ return nullptr; } #define OV_DETAIL_GET_TYPE \ struct _self_type_tag {}; \ constexpr auto _self_type_helper()->decltype(::ovdl::detail::Writer<_self_type_tag, decltype(this)> {}); \ using type = ::ovdl::detail::Read<_self_type_tag>; \ static constexpr std::string_view get_type_static() { return ::ovdl::detail::type_name(); } \ constexpr std::string_view get_type() const override { \ return ::ovdl::detail::type_name>(); } #define OV_DETAIL_GET_BASE_TYPE(CLASS) \ static constexpr std::string_view get_base_type_static() { return ::ovdl::detail::type_name(); } \ constexpr std::string_view get_base_type() const override { \ return ::ovdl::detail::type_name>(); } #define REF_GETTERS(var) \ constexpr decltype(var)& get_##var() { \ return var; \ } \ constexpr decltype(var) const& get_##var() const { \ return var; \ } namespace OpenVic { struct ReturnByValueProperty {}; /* * Template function used to choose the return type and provide the implementation * for variable getters created using the PROPERTY macro. */ template inline constexpr decltype(auto) _get_property(const T& property) { if constexpr(std::is_reference_v) { /* Return const reference */ return property; } else if constexpr (std::same_as) { /* Return std::string_view looking at std::string */ return std::string_view { property }; } else if constexpr ( std::integral || std::floating_point || std::is_enum::value || std::derived_from ) { /* Return value */ return T { property }; } else if constexpr(std::is_pointer::value) { /* Return const pointer */ return static_cast>>>(property); } else { /* Return const reference */ return property; } } /* * Use this on a variable declaration to generate a getter function. PROPERTY assumes the variable is private and so * sets the accessibility modifier state back to private after declaring the getter as public; use PROPERTY_ACCESS to * manually specify the accessibility level, if your variable deviates from this norm; use PROPERTY_CUSTOM_NAME when * you wish to manually specify the getter name; use PROPERTY_FULL if you want to specify everything. * Examples: * int PROPERTY(x); // int x; int get_x() const; * const std::string PROPERTY(name); // const std::string name; std::string_view get_name() const; * std::vector PROPERTY(sizes); // std::vector sizes; std::vector const& get_sizes() const; * uint8_t const* PROPERTY(data); // uint8_t const* data; uint8_t const* get_data() const; * colour_t* PROPERTY(pixels); // colour_t* pixels; colour_t const* get_pixels() const; * CultureGroup const& PROPERTY(group);// CultureGroup const& group; CultureGroup const& get_group() const; * Province& PROPERTY(province); // Province& province; Province const& get_province() const; */ #define PROPERTY(NAME) PROPERTY_ACCESS(NAME, private) #define PROPERTY_CUSTOM_NAME(NAME, GETTER_NAME) PROPERTY_FULL(NAME, GETTER_NAME, private) #define PROPERTY_ACCESS(NAME, ACCESS) PROPERTY_FULL(NAME, get_##NAME, ACCESS) #define PROPERTY_FULL(NAME, GETTER_NAME, ACCESS) \ NAME; \ public: \ auto GETTER_NAME() const -> decltype(OpenVic::_get_property(NAME)) { \ return OpenVic::_get_property(NAME); \ } \ ACCESS: // TODO: Special logic to decide argument type and control assignment. #define PROPERTY_RW(NAME) PROPERTY_RW_ACCESS(NAME, private) #define PROPERTY_RW_CUSTOM_NAME(NAME, GETTER_NAME, SETTER_NAME) PROPERTY_RW_FULL(NAME, GETTER_NAME, SETTER_NAME, private) #define PROPERTY_RW_ACCESS(NAME, ACCESS) PROPERTY_RW_FULL(NAME, get_##NAME, set_##NAME, ACCESS) #define PROPERTY_RW_FULL(NAME, GETTER_NAME, SETTER_NAME, ACCESS) \ PROPERTY_FULL(NAME, GETTER_NAME, ACCESS) \ public: \ void SETTER_NAME(decltype(NAME) new_##NAME) { \ NAME = new_##NAME; \ } \ ACCESS: }