#pragma once #include #include #include #include #include #include #include namespace OpenVic::utility { template constexpr auto substring_as_array(std::string_view str, std::index_sequence) { return std::array { str[Idxs]... }; } template constexpr auto type_name_array() { #if defined(__clang__) constexpr auto prefix = std::string_view { "[T = " }; constexpr auto suffix = std::string_view { "]" }; constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; #elif defined(__GNUC__) constexpr auto prefix = std::string_view { "with T = " }; constexpr auto suffix = std::string_view { "]" }; constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; #elif defined(_MSC_VER) constexpr auto prefix = std::string_view { "type_name_array<" }; constexpr auto suffix = std::string_view { ">(void)" }; constexpr auto function = std::string_view { __FUNCSIG__ }; #else #error Unsupported compiler #endif constexpr auto start = function.find(prefix) + prefix.size(); constexpr auto end = function.rfind(suffix); static_assert(start < end); constexpr auto name = function.substr(start, (end - start)); return substring_as_array(name, std::make_index_sequence {}); } template struct type_name_holder { static inline constexpr auto value = type_name_array(); }; template constexpr auto type_name() -> std::string_view { constexpr auto& value = type_name_holder::value; return std::string_view { value.data(), value.size() }; } #if !defined(_MSC_VER) #pragma GCC diagnostic push #pragma clang diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wnon-template-friend" #endif template struct Reader { friend auto adl_GetSelfType(Reader); }; template struct Writer { friend auto adl_GetSelfType(Reader) { return U {}; } }; #if !defined(_MSC_VER) #pragma GCC diagnostic pop #endif inline void adl_GetSelfType() {} template using Read = std::remove_pointer_t {}))>; } #define OV_DETAIL_GET_TYPE_BASE_CLASS(CLASS) \ static constexpr std::string_view get_type_static() { \ return ::OpenVic::utility::type_name(); \ } \ constexpr virtual std::string_view get_type() const = 0; \ static constexpr std::string_view get_base_type_static() { \ return ::OpenVic::utility::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(::OpenVic::utility::type_name()) == 0; \ } \ template \ constexpr bool is_derived_from() const { \ return is_type() || get_base_type().compare(::OpenVic::utility::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(::OpenVic::utility::Writer<_self_type_tag, decltype(this)> {}); \ using type = ::OpenVic::utility::Read<_self_type_tag>; \ static constexpr std::string_view get_type_static() { \ return ::OpenVic::utility::type_name(); \ } \ constexpr std::string_view get_type() const override { \ return ::OpenVic::utility::type_name>(); \ } #define OV_DETAIL_GET_BASE_TYPE(CLASS) \ static constexpr std::string_view get_base_type_static() { \ return ::OpenVic::utility::type_name(); \ } \ constexpr std::string_view get_base_type() const override { \ return ::OpenVic::utility::type_name>(); \ } /* Create const and non-const reference getters for a variable, applied to its name in its declaration, e * for example: GameManager PROPERTY_REF(game_manager); */ #define PROPERTY_REF(NAME) PROPERTY_REF_FULL(NAME, private) #define PROPERTY_REF_FULL(NAME, ACCESS) \ NAME; \ \ public: \ constexpr decltype(NAME)& get_##NAME() { \ return NAME; \ } \ constexpr decltype(NAME) const& get_##NAME() const { \ return NAME; \ } \ ACCESS: namespace OpenVic { /* Any struct tagged with ov_return_by_value will be returned by value by PROPERTY-generated getter functions, * instead of by const reference as structs are by default. Use this for small structs which don't contain any * dynamically allocated memory, e.g. dates and colours. The tag must be public, as in the example below: * * public: * using ov_return_by_value = void; */ template concept ReturnByValue = requires { typename T::ov_return_by_value; }; /* * 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_v || ReturnByValue) { /* Return value */ return T { property }; } else if constexpr (std::is_pointer_v) { /* 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_PREFIX(NAME, PREFIX) PROPERTY_CUSTOM_NAME(NAME, PREFIX##_##NAME) #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: \ constexpr 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: \ constexpr void SETTER_NAME(decltype(NAME) new_##NAME) { \ NAME = new_##NAME; \ } \ ACCESS: