The Battle for Wesnoth  1.19.23+dev
callable.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2025
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 #include "formula/callable_fwd.hpp"
19 #include "formula/variant.hpp"
20 #include "log.hpp"
21 
22 #include <memory>
23 #include <set>
24 
25 namespace wfl
26 {
27 
28 // Interface for objects that can have formulae run on them
30 {
31 public:
32  explicit formula_callable(bool has_self = true) : type_(FORMULA_C), has_self_(has_self) {}
33 
34  virtual ~formula_callable() {
35  for(auto& d : dtor_notify) {
36  if(d) {
37  d->notify_dead();
38  }
39  }
40  }
41 
43  return formula_callable_ptr(this, [](const formula_callable*){});
44  }
45 
47  return const_formula_callable_ptr(this, [](const formula_callable*){});
48  }
49 
50  variant query_value(const std::string& key) const
51  {
52  if(has_self_ && key == "self") {
53  return variant(fake_ptr());
54  }
55  return get_value(key);
56  }
57 
58  void mutate_value(const std::string& key, const variant& value)
59  {
60  set_value(key, value);
61  }
62 
64  {
66  get_inputs(res);
67  return res;
68  }
69 
70  virtual void get_inputs(formula_input_vector& /*inputs*/) const {}
71 
72  bool equals(const formula_callable& other) const
73  {
74  return do_compare(&other) == 0;
75  }
76 
77  bool less(const formula_callable& other) const
78  {
79  return do_compare(&other) < 0;
80  }
81 
82  bool has_key(const std::string& key) const
83  {
84  return !query_value(key).is_null();
85  }
86 
87  std::string serialize() const
88  {
89  return serialize_to_string();
90  }
91 
93  dtor_notify.insert(d);
94  }
95 
97  dtor_notify.erase(d);
98  }
99 
100 protected:
101  template<typename T, typename K>
102  static variant convert_map(const std::map<T, K>& input_map)
103  {
104  std::map<variant, variant> tmp;
105  for(const auto& p : input_map) {
106  tmp[variant(p.first)] = variant(p.second);
107  }
108 
109  return variant(std::move(tmp));
110  }
111 
112  template<typename T>
113  static variant convert_set(const std::set<T>& input_set)
114  {
115  std::map<variant, variant> tmp;
116  for(const auto& elem : input_set) {
117  tmp[variant(elem)] = variant(1);
118  }
119 
120  return variant(std::move(tmp));
121  }
122 
123  template<typename T>
124  static variant convert_vector(const std::vector<T>& input_vector)
125  {
126  std::vector<variant> tmp;
127  for(const auto& elem : input_vector) {
128  tmp.emplace_back(elem);
129  }
130 
131  return variant(std::move(tmp));
132  }
133 
134  static inline void add_input(formula_input_vector& inputs, const std::string& key, formula_access access_type = formula_access::read_only)
135  {
136  inputs.emplace_back(key, access_type);
137  }
138 
139  virtual void set_value(const std::string& key, const variant& /*value*/)
140  {
141  PLAIN_LOG << "ERROR: cannot set key '" << key << "' on object";
142  }
143 
144  virtual int do_compare(const formula_callable* callable) const
145  {
146  if(type_ < callable->type_) {
147  return -1;
148  }
149 
150  if(type_ > callable->type_) {
151  return 1;
152  }
153 
154  return this < callable ? -1 : (this == callable ? 0 : 1);
155  }
156 
157  virtual std::string serialize_to_string() const
158  {
159  throw type_error("Tried to serialize type which cannot be serialized");
160  }
161 
162  // Priority for objects that are derived from this class, used in do_compare
163  // when comparing objects of different types.
164  // For example: formula_callable < terrain_callable < unit_type_callable ...
165  enum TYPE {
168  };
169 
171 
172  mutable std::set<callable_die_subscriber*> dtor_notify;
173 
174 private:
175  virtual variant get_value(const std::string& key) const = 0;
176  bool has_self_;
177 };
178 
180 {
181 public:
182  virtual variant execute_self(variant ctxt) = 0;
183 };
184 
186 {
187 public:
189  : formula_callable(false), main_(main), backup_(backup)
190  {}
191 
192 private:
193  variant get_value(const std::string& key) const override
194  {
195  variant var = main_.query_value(key);
196  if(var.is_null()) {
197  return backup_.query_value(key);
198  }
199 
200  return var;
201  }
202 
203  void get_inputs(formula_input_vector& inputs) const override
204  {
207  }
208 
211 };
212 
214 {
215 public:
217  : formula_callable(false), var_(var), backup_(backup)
218  {}
219 
220 private:
221  variant get_value(const std::string& key) const override
222  {
223  variant var = var_.get_member(key);
224  if(var.is_null()) {
225  return backup_.query_value(key);
226  }
227 
228  return var;
229  }
230 
231  void get_inputs(formula_input_vector& inputs) const override
232  {
234  }
235 
238 };
239 
241 {
242 public:
244  : formula_callable(false)
245  , values_()
246  , fallback_(fallback)
247  {}
248 
249  map_formula_callable& add(const std::string& key, const variant& value)
250  {
251  values_[key] = value;
252  return *this;
253  }
254 
255  map_formula_callable& add(const std::string& key, variant&& value)
256  {
257  values_[key] = std::move(value);
258  return *this;
259  }
260 
262  {
263  fallback_ = fallback;
264  }
265 
266  bool empty() const { return values_.empty(); }
267 
268  void clear() { values_.clear(); }
269 
270  typedef std::map<std::string,variant>::const_iterator const_iterator;
271 
272  const_iterator begin() const { return values_.begin(); }
273  const_iterator end() const { return values_.end(); }
274 
275 private:
276  void set_value(const std::string& key, const variant& value) override
277  {
278  values_[key] = value;
279  }
280 
281  variant get_value(const std::string& key) const override
282  {
283  auto it = values_.find(key);
284  if(it != values_.end()) {
285  return it->second;
286  } else if(fallback_) {
287  return fallback_->query_value(key);
288  }
289 
290  return variant();
291  }
292 
293  void get_inputs(formula_input_vector& inputs) const override
294  {
295  if(fallback_) {
296  fallback_->get_inputs(inputs);
297  }
298 
299  for(const auto& i : values_) {
301  }
302  }
303 
304  std::map<std::string, variant> values_;
306 };
307 
308 using map_formula_callable_ptr = std::shared_ptr<map_formula_callable>;
309 using const_map_formula_callable_ptr = std::shared_ptr<const map_formula_callable>;
310 
311 template<typename T, typename... Args>
312 variant make_callable(Args&&... args)
313 {
314  return variant{std::make_shared<T>(std::forward<Args>(args)...)};
315 }
316 
317 #ifdef __cpp_concepts
318 template<typename T>
319 requires std::is_pointer_v<T>
320 auto callable_cast(const variant& v)
321 #else
322 template<typename T>
323 auto callable_cast(const variant& v) -> std::enable_if_t<std::is_pointer_v<T>, std::shared_ptr<const std::remove_pointer_t<T>>>
324 #endif
325 {
326  return std::dynamic_pointer_cast<const std::remove_pointer_t<T>>(v.as_callable());
327 }
328 
329 #ifdef __cpp_concepts
330 template<typename T>
331 requires std::is_reference_v<T>
332 auto callable_cast(const variant& v)
333 #else
334 template<typename T>
335 auto callable_cast(const variant& v) -> std::enable_if_t<std::is_reference_v<T>, const std::remove_reference_t<T>>
336 #endif
337 {
338  auto ptr = callable_cast<std::remove_reference_t<T>*>(v);
339  if(!ptr) {
340  throw type_error{"could not convert type"};
341  }
342 
343  return *ptr;
344 }
345 
346 } // namespace wfl
virtual variant execute_self(variant ctxt)=0
const formula_callable & main_
Definition: callable.hpp:209
const formula_callable & backup_
Definition: callable.hpp:210
formula_callable_with_backup(const formula_callable &main, const formula_callable &backup)
Definition: callable.hpp:188
void get_inputs(formula_input_vector &inputs) const override
Definition: callable.hpp:203
variant get_value(const std::string &key) const override
Definition: callable.hpp:193
const_formula_callable_ptr fake_ptr() const
Definition: callable.hpp:46
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
variant query_value(const std::string &key) const
Definition: callable.hpp:50
void mutate_value(const std::string &key, const variant &value)
Definition: callable.hpp:58
void subscribe_dtor(callable_die_subscriber *d) const
Definition: callable.hpp:92
formula_input_vector inputs() const
Definition: callable.hpp:63
static variant convert_map(const std::map< T, K > &input_map)
Definition: callable.hpp:102
std::set< callable_die_subscriber * > dtor_notify
Definition: callable.hpp:172
static void add_input(formula_input_vector &inputs, const std::string &key, formula_access access_type=formula_access::read_only)
Definition: callable.hpp:134
void unsubscribe_dtor(callable_die_subscriber *d) const
Definition: callable.hpp:96
virtual int do_compare(const formula_callable *callable) const
Definition: callable.hpp:144
virtual void set_value(const std::string &key, const variant &)
Definition: callable.hpp:139
virtual ~formula_callable()
Definition: callable.hpp:34
bool less(const formula_callable &other) const
Definition: callable.hpp:77
virtual void get_inputs(formula_input_vector &) const
Definition: callable.hpp:70
static variant convert_vector(const std::vector< T > &input_vector)
Definition: callable.hpp:124
static variant convert_set(const std::set< T > &input_set)
Definition: callable.hpp:113
formula_callable(bool has_self=true)
Definition: callable.hpp:32
bool equals(const formula_callable &other) const
Definition: callable.hpp:72
virtual std::string serialize_to_string() const
Definition: callable.hpp:157
std::string serialize() const
Definition: callable.hpp:87
virtual variant get_value(const std::string &key) const =0
bool has_key(const std::string &key) const
Definition: callable.hpp:82
formula_variant_callable_with_backup(const variant &var, const formula_callable &backup)
Definition: callable.hpp:216
variant get_value(const std::string &key) const override
Definition: callable.hpp:221
const formula_callable & backup_
Definition: callable.hpp:237
void get_inputs(formula_input_vector &inputs) const override
Definition: callable.hpp:231
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:249
void set_value(const std::string &key, const variant &value) override
Definition: callable.hpp:276
variant get_value(const std::string &key) const override
Definition: callable.hpp:281
const_iterator end() const
Definition: callable.hpp:273
void get_inputs(formula_input_vector &inputs) const override
Definition: callable.hpp:293
const_formula_callable_ptr fallback_
Definition: callable.hpp:305
map_formula_callable & add(const std::string &key, variant &&value)
Definition: callable.hpp:255
std::map< std::string, variant > values_
Definition: callable.hpp:304
void set_fallback(const_formula_callable_ptr fallback)
Definition: callable.hpp:261
std::map< std::string, variant >::const_iterator const_iterator
Definition: callable.hpp:270
const_iterator begin() const
Definition: callable.hpp:272
map_formula_callable(const_formula_callable_ptr fallback=nullptr)
Definition: callable.hpp:243
variant get_member(const std::string &name) const
Definition: variant.cpp:321
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:69
std::size_t i
Definition: function.cpp:1031
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:296
Definition: callable.hpp:26
std::vector< formula_input > formula_input_vector
std::shared_ptr< map_formula_callable > map_formula_callable_ptr
Definition: callable.hpp:308
std::shared_ptr< const formula_callable > const_formula_callable_ptr
variant make_callable(Args &&... args)
Definition: callable.hpp:312
std::shared_ptr< formula_callable > formula_callable_ptr
auto callable_cast(const variant &v) -> std::enable_if_t< std::is_pointer_v< T >, std::shared_ptr< const std::remove_pointer_t< T >>>
Definition: callable.hpp:323
formula_access
std::shared_ptr< const map_formula_callable > const_map_formula_callable_ptr
Definition: callable.hpp:309
int main(int, char **)
Definition: sdl2.cpp:25
mock_party p
#define d