The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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
19#include "formula/variant.hpp"
20#include "log.hpp"
21
22#include <memory>
23#include <set>
24
25namespace wfl
26{
27
28// Interface for objects that can have formulae run on them
30{
31public:
32 explicit formula_callable(bool has_self = true) : type_(FORMULA_C), has_self_(has_self) {}
33
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
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
100protected:
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 ...
169
171
172 mutable std::set<callable_die_subscriber*> dtor_notify;
173
174private:
175 virtual variant get_value(const std::string& key) const = 0;
177};
178
180{
181public:
182 virtual variant execute_self(variant ctxt) = 0;
183};
184
186{
187public:
191
192private:
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
204 {
207 }
208
211};
212
214{
215public:
217 : formula_callable(false), var_(var), backup_(backup)
218 {}
219
220private:
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
232 {
234 }
235
238};
239
241{
242public:
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
275private:
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
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
308using map_formula_callable_ptr = std::shared_ptr<map_formula_callable>;
309using const_map_formula_callable_ptr = std::shared_ptr<const map_formula_callable>;
310
311template<typename T, typename... Args>
312variant make_callable(Args&&... args)
313{
314 return variant{std::make_shared<T>(std::forward<Args>(args)...)};
315}
316
317#ifdef __cpp_concepts
318template<typename T>
319requires std::is_pointer_v<T>
320auto callable_cast(const variant& v)
321#else
322template<typename T>
323auto 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
330template<typename T>
331requires std::is_reference_v<T>
332auto callable_cast(const variant& v)
333#else
334template<typename T>
335auto 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
void get_inputs(formula_input_vector &inputs) const override
Definition callable.hpp:231
map_formula_callable & add(const std::string &key, variant &&value)
Definition callable.hpp:255
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
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
Standard logging facilities (interface).
#define PLAIN_LOG
Definition log.hpp:296
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
std::shared_ptr< const map_formula_callable > const_map_formula_callable_ptr
Definition callable.hpp:309
int main(int, char **)
Definition sdl3.cpp:25
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
mock_party p
#define i
#define d