aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/dataloader/NodeTools.hpp
blob: 44ac271e576d6cc73ac6bac734972f4809bc03dd (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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#pragma once

#include <map>

#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>

#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/Vector.hpp"

namespace OpenVic {
   namespace ast = ovdl::v2script::ast;

   /* Template for map from strings to Ts, in which string_views can be
    * searched for without needing to be copied into a string, */
   template<typename T>
   using string_map_t = std::map<std::string, T, std::less<void>>;

   namespace NodeTools {

      template<typename... Args>
      using callback_t = std::function<bool(Args...)>;

      using node_callback_t = callback_t<ast::NodeCPtr>;
      constexpr bool success_callback(ast::NodeCPtr) { return true; }

      using key_value_callback_t = callback_t<std::string_view, ast::NodeCPtr>;
      constexpr bool key_value_success_callback(std::string_view, ast::NodeCPtr) { return true; }
      inline bool key_value_invalid_callback(std::string_view key, ast::NodeCPtr) {
         Logger::error("Invalid dictionary key: ", key);
         return false;
      }

      node_callback_t expect_identifier(callback_t<std::string_view> callback);
      node_callback_t expect_string(callback_t<std::string_view> callback, bool allow_empty = true);
      node_callback_t expect_identifier_or_string(callback_t<std::string_view> callback);

      node_callback_t expect_bool(callback_t<bool> callback);
      node_callback_t expect_int_bool(callback_t<bool> callback);

      node_callback_t expect_int64(callback_t<int64_t> callback);
      node_callback_t expect_uint64(callback_t<uint64_t> callback);

      template<std::signed_integral T>
      node_callback_t expect_int(callback_t<T> callback) {
         return expect_int64([callback](int64_t val) -> bool {
            if (static_cast<int64_t>(std::numeric_limits<T>::lowest()) <= val &&
               val <= static_cast<int64_t>(std::numeric_limits<T>::max())) {
               return callback(val);
            }
            Logger::error("Invalid int: ", val, " (valid range: [",
               static_cast<int64_t>(std::numeric_limits<T>::lowest()), ", ",
               static_cast<int64_t>(std::numeric_limits<T>::max()), "])");
            return false;
         });
      }

      template<std::integral T>
      node_callback_t expect_uint(callback_t<T> callback) {
         return expect_uint64([callback](uint64_t val) -> bool {
            if (val <= static_cast<uint64_t>(std::numeric_limits<T>::max())) {
               return callback(val);
            }
            Logger::error("Invalid uint: ", val, " (valid range: [0, ",
               static_cast<uint64_t>(std::numeric_limits<T>::max()), "])");
            return false;
         });
      }

      node_callback_t expect_fixed_point(callback_t<fixed_point_t> callback);
      node_callback_t expect_colour(callback_t<colour_t> callback);

      node_callback_t expect_date(callback_t<Date> callback);
      node_callback_t expect_years(callback_t<Timespan> callback);
      node_callback_t expect_months(callback_t<Timespan> callback);
      node_callback_t expect_days(callback_t<Timespan> callback);

      node_callback_t expect_ivec2(callback_t<ivec2_t> callback);
      node_callback_t expect_fvec2(callback_t<fvec2_t> callback);
      node_callback_t expect_assign(key_value_callback_t callback);

      using length_callback_t = std::function<size_t(size_t)>;
      constexpr size_t default_length_callback(size_t size) { return size; };

      node_callback_t expect_list_and_length(length_callback_t length_callback, node_callback_t callback);
      node_callback_t expect_list_of_length(size_t length, node_callback_t callback);
      node_callback_t expect_list(node_callback_t callback);
      node_callback_t expect_length(callback_t<size_t> callback);

      node_callback_t expect_key(std::string_view key, node_callback_t callback, bool* key_found = nullptr);

      node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback);
      node_callback_t expect_dictionary(key_value_callback_t callback);

      struct dictionary_entry_t {
         const enum class expected_count_t : uint8_t {
            _MUST_APPEAR = 0b01,
            _CAN_REPEAT = 0b10,

            ZERO_OR_ONE = 0,
            ONE_EXACTLY = _MUST_APPEAR,
            ZERO_OR_MORE = _CAN_REPEAT,
            ONE_OR_MORE = _MUST_APPEAR | _CAN_REPEAT
         } expected_count;
         const node_callback_t callback;
         size_t count;

         dictionary_entry_t(expected_count_t new_expected_count, node_callback_t new_callback)
            : expected_count { new_expected_count }, callback { new_callback }, count { 0 } {}

         constexpr bool must_appear() const {
            return static_cast<uint8_t>(expected_count) & static_cast<uint8_t>(expected_count_t::_MUST_APPEAR);
         }
         constexpr bool can_repeat() const {
            return static_cast<uint8_t>(expected_count) & static_cast<uint8_t>(expected_count_t::_CAN_REPEAT);
         }
      };
      using enum dictionary_entry_t::expected_count_t;
      using key_map_t = string_map_t<dictionary_entry_t>;

      bool add_key_map_entry(key_map_t& key_map, std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback);
      bool remove_key_map_entry(key_map_t& key_map, std::string_view key);
      key_value_callback_t dictionary_keys_callback(key_map_t& key_map, key_value_callback_t default_callback);
      bool check_key_map_counts(key_map_t& key_map);

      node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback);
      node_callback_t expect_dictionary_key_map_and_length(key_map_t key_map, length_callback_t length_callback);
      node_callback_t expect_dictionary_key_map_and_default(key_map_t key_map, key_value_callback_t default_callback);
      node_callback_t expect_dictionary_key_map(key_map_t key_map);

      template<typename... Args>
      node_callback_t expect_dictionary_key_map_and_length_and_default(key_map_t key_map, length_callback_t length_callback, key_value_callback_t default_callback,
         std::string_view key, dictionary_entry_t::expected_count_t expected_count, node_callback_t callback,
         Args... args) {
         // TODO - pass return value back up (part of big key_map_t rewrite?)
         add_key_map_entry(key_map, key, expected_count, callback);
         return expect_dictionary_key_map_and_length_and_default(std::move(key_map), length_callback, default_callback, args...);
      }

      template<typename... Args>
      node_callback_t expect_dictionary_keys_and_length_and_default(length_callback_t length_callback, key_value_callback_t default_callback, Args... args) {
         return expect_dictionary_key_map_and_length_and_default({}, length_callback, default_callback, args...);
      }

      template<typename... Args>
      node_callback_t expect_dictionary_keys_and_length(length_callback_t length_callback, Args... args) {
         return expect_dictionary_key_map_and_length_and_default({}, length_callback, key_value_invalid_callback, args...);
      }

      template<typename... Args>
      node_callback_t expect_dictionary_keys_and_default(key_value_callback_t default_callback, Args... args) {
         return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, default_callback, args...);
      }

      template<typename... Args>
      node_callback_t expect_dictionary_keys(Args... args) {
         return expect_dictionary_key_map_and_length_and_default({}, default_length_callback, key_value_invalid_callback, args...);
      }

      template<typename T>
      concept Reservable = requires(T& t) {
         { t.size() } -> std::same_as<size_t>;
         t.reserve(size_t {});
      };
      template<Reservable T>
      node_callback_t expect_list_reserve_length(T& t, node_callback_t callback) {
         return expect_list_and_length(
            [&t](size_t size) -> size_t {
               t.reserve(t.size() + size);
               return size;
            },
            callback
         );
      }
      template<Reservable T>
      node_callback_t expect_dictionary_reserve_length(T& t, key_value_callback_t callback) {
         return expect_list_reserve_length(t, expect_assign(callback));
      }

      node_callback_t name_list_callback(std::vector<std::string>& list);

      template<typename T>
      callback_t<std::string_view> expect_mapped_string(string_map_t<T> const& map, callback_t<T> callback) {
         return [&map, callback](std::string_view string) -> bool {
            const typename string_map_t<T>::const_iterator it = map.find(string);
            if (it != map.end()) {
               return callback(it->second);
            }
            Logger::error("String not found in map: ", string);
            return false;
         };
      }

      template<typename T, typename U>
      callback_t<T> assign_variable_callback_cast(U& var) {
         return [&var](T val) -> bool {
            var = val;
            return true;
         };
      }

      template<typename T>
      callback_t<T> assign_variable_callback(T& var) {
         return assign_variable_callback_cast<T, T>(var);
      }

      callback_t<std::string_view> assign_variable_callback_string(std::string& var);

      template<typename T>
      callback_t<T&&> move_variable_callback(T& var) {
         return [&var](T&& val) -> bool {
            var = std::move(val);
            return true;
         };
      }

      template<typename T>
      requires requires(T& t) {
         t += T {};
      }
      callback_t<T> add_variable_callback(T& var) {
         return [&var](T val) -> bool {
            var += val;
            return true;
         };
      }

      template<typename T>
      requires requires(T& t) {
         t++;
      }
      key_value_callback_t increment_callback(T& var) {
         return [&var](std::string_view, ast::NodeCPtr) -> bool {
            var++;
            return true;
         };
      }

      template<typename T>
      callback_t<T const&> assign_variable_callback_pointer(T const*& var) {
         return [&var](T const& val) -> bool {
            var = &val;
            return true;
         };
      }
   }
}