aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/utility/Getters.hpp
blob: 5d06a8da782df352df7b5a18035abc053e3cf22e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#pragma once

#include <array>
#include <concepts>
#include <cstddef>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>

namespace OpenVic::utility {
   template<std::size_t... Idxs>
   constexpr auto substring_as_array(std::string_view str, std::index_sequence<Idxs...>) {
      return std::array { str[Idxs]... };
   }

   template<typename T>
   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<name.size()> {});
   }

   template<typename T>
   struct type_name_holder {
      static inline constexpr auto value = type_name_array<T>();
   };

   template<typename T>
   constexpr auto type_name() -> std::string_view {
      constexpr auto& value = type_name_holder<T>::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<typename T>
   struct Reader {
      friend auto adl_GetSelfType(Reader<T>);
   };

   template<typename T, typename U>
   struct Writer {
      friend auto adl_GetSelfType(Reader<T>) {
         return U {};
      }
   };
#if !defined(_MSC_VER)
#pragma GCC diagnostic pop
#endif

   inline void adl_GetSelfType() {}

   template<typename T>
   using Read = std::remove_pointer_t<decltype(adl_GetSelfType(Reader<T> {}))>;
}

#define OV_DETAIL_GET_TYPE_BASE_CLASS(CLASS) \
   static constexpr std::string_view get_type_static() { \
      return ::OpenVic::utility::type_name<CLASS>(); \
   } \
   constexpr virtual std::string_view get_type() const = 0; \
   static constexpr std::string_view get_base_type_static() { \
      return ::OpenVic::utility::type_name<CLASS>(); \
   } \
   constexpr virtual std::string_view get_base_type() const { \
      return get_base_type_static(); \
   } \
   template<typename T> \
   constexpr bool is_type() const { \
      return get_type().compare(::OpenVic::utility::type_name<T>()) == 0; \
   } \
   template<typename T> \
   constexpr bool is_derived_from() const { \
      return is_type<T>() || get_base_type().compare(::OpenVic::utility::type_name<T>()) == 0; \
   } \
   template<typename T> \
   constexpr T* cast_to() { \
      if (is_derived_from<T>() || is_type<CLASS>()) \
         return (static_cast<T*>(this)); \
      return nullptr; \
   } \
   template<typename T> \
   constexpr const T* const cast_to() const { \
      if (is_derived_from<T>() || is_type<CLASS>()) \
         return (static_cast<const T*>(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<type>(); \
   } \
   constexpr std::string_view get_type() const override { \
      return ::OpenVic::utility::type_name<std::decay_t<decltype(*this)>>(); \
   }

#define OV_DETAIL_GET_BASE_TYPE(CLASS) \
   static constexpr std::string_view get_base_type_static() { \
      return ::OpenVic::utility::type_name<CLASS>(); \
   } \
   constexpr std::string_view get_base_type() const override { \
      return ::OpenVic::utility::type_name<std::decay_t<decltype(*this)>>(); \
   }

/* 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<typename T>
   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<typename decl, typename T>
   inline constexpr decltype(auto) _get_property(const T& property) {
      if constexpr (std::is_reference_v<decl>) {
         /* Return const reference */
         return property;
      } else if constexpr (std::same_as<T, std::string>) {
         /* Return std::string_view looking at std::string */
         return std::string_view { property };
      } else if constexpr (std::integral<T> || std::floating_point<T> || std::is_enum_v<T> || ReturnByValue<T>) {
         /* Return value */
         return T { property };
      } else if constexpr (std::is_pointer_v<T>) {
         /* Return const pointer */
         return static_cast<std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>>(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<int> PROPERTY(sizes);   // std::vector<int> sizes;    std::vector<int> 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<decltype(NAME)>(NAME)) { \
      return OpenVic::_get_property<decltype(NAME)>(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: