The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
variant_value.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15#pragma once
16
18#include "formula_variant.hpp"
19#include "utils/any.hpp"
20#include "utils/general.hpp"
21
22#include <functional>
23#include <map>
24#include <vector>
25#include <boost/range/iterator_range.hpp>
26
27namespace utils
28{
29template<typename To, typename From>
30inline To& cast_as(To&, From& value)
31{
32 return static_cast<To&>(value);
33}
34
35} // namespace utils
36
37namespace wfl
38{
39class variant_value_base;
40class variant_iterator;
41class variant;
42
43#define IMPLEMENT_VALUE_TYPE(value) \
44 static constexpr auto value_type = value; \
45 formula_variant::type get_type() const override \
46 { \
47 return value_type; \
48 }
49
50/**
51 * Base class for all variant types.
52 *
53 * This provides a common interface for all type classes to implement, as well as
54 * giving variant a base pointer type for its value member. It also serves as the
55 * implementation of the 'null' variant value.
56 *
57 * Do note this class should *not* implement any data members.
58 */
60{
61public:
62 /** Returns the number of elements in a type. Not relevant for every derivative. */
63 virtual std::size_t num_elements() const
64 {
65 return 0;
66 }
67
68 /** Whether the stored value is considered empty or not. */
69 virtual bool is_empty() const
70 {
71 return true;
72 }
73
74 /** Returns the stored variant value in plain string form. */
75 virtual std::string string_cast() const
76 {
77 return "0";
78 }
79
80 /** Returns the stored variant value in formula syntax. */
81 virtual std::string get_serialized_string() const
82 {
83 return "null()";
84 }
85
86 /** Returns debug info for the variant value. */
87 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const
88 {
89 return get_serialized_string();
90 }
91
92 /** Returns a bool expression of the variant value. */
93 virtual bool as_bool() const
94 {
95 return false;
96 }
97
98 /**
99 * Called to determine if this variant is equal to another _of the same type_.
100 * This function is _only_ called if get_type() returns the same result for both arguments.
101 */
102 virtual bool equals(const variant_value_base& /*other*/) const
103 {
104 return true; // null is equal to null
105 }
106
107 /**
108 * Called to determine if this variant is less than another _of the same type_.
109 * This function is _only_ called if get_type() returns the same result for both arguments.
110 */
111 virtual bool less_than(const variant_value_base& /*other*/) const
112 {
113 return false; // null is not less than null
114 }
115
116 /** Each 'final' derived class should define a static type flag. */
117 static constexpr auto value_type = formula_variant::type::null;
118
119 /** Returns the id of the variant type */
120 virtual formula_variant::type get_type() const
121 {
122 return value_type;
123 }
124
125 /**
126 * Creates an iterator pair that can be used for iteration.
127 * For an iterable type, it should use the two-argument constructor of variant-iterator,
128 * passing the underlying iterator as the utils::any parameter.
129 *
130 * This creates both the begin and end iterator, but the variant implementation
131 * discards one of the two.
132 */
133 virtual boost::iterator_range<variant_iterator> make_iterator() const;
134
135 /**
136 * Implements the dereference functionality of variant_iterator
137 * for a value of this type.
138 *
139 * @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
140 */
141 virtual variant deref_iterator(const utils::any& iter) const;
142
143 /**
144 * Implements the increment functionality of variant_iterator
145 * for a value of this type.
146 *
147 * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
148 */
149 virtual void iterator_inc(utils::any&) const {}
150
151 /**
152 * Implements the decrement functionality of variant_iterator
153 * for a value of this type.
154 *
155 * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
156 */
157 virtual void iterator_dec(utils::any&) const {}
158
159 /**
160 * Implements the equality functionality of variant_iterator
161 * for a value of this type.
162 *
163 * Note that this is only called if the two iterators are already known to be of the same type.
164 *
165 * The first parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
166 * The second parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
167 */
168 virtual bool iterator_equals(const utils::any& /*first*/, const utils::any& /*second*/) const
169 {
170 return true;
171 }
172
174};
175
176
177/**
178 * Base class for numeric variant values. Currently only supports a value stored as an
179 * integer, but for now, that's all that's necessary.
180 */
182{
183public:
184 explicit variant_numeric(int value) : value_(value) {}
185
186 virtual bool as_bool() const override
187 {
188 return value_ != 0;
189 }
190
192 {
193 return value_;
194 }
195
196 virtual bool equals(const variant_value_base& other) const override
197 {
198 return value_ == utils::cast_as(*this, other).value_;
199 }
200
201 virtual bool less_than(const variant_value_base& other) const override
202 {
203 return value_ < utils::cast_as(*this, other).value_;
204 }
205
206protected:
208};
209
210
212{
213public:
215
216 variant build_range_variant(int limit) const;
217
218 virtual std::string string_cast() const override
219 {
220 return std::to_string(value_);
221 }
222
223 virtual std::string get_serialized_string() const override
224 {
225 return string_cast();
226 }
227
228 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
229 {
230 return string_cast();
231 }
232
233 /** Required by variant_value_base. */
234 IMPLEMENT_VALUE_TYPE(formula_variant::type::integer)
235};
236
237
239{
240public:
242
244 {
245 value *= 1000;
246 value_ = static_cast<int>(value);
247 value -= value_;
248
249 if(value > 0.5) {
250 value_++;
251 } else if(value < -0.5) {
252 value_--;
253 }
254 }
255
256 virtual std::string string_cast() const override
257 {
258 return to_string_impl(false);
259 }
260
261 virtual std::string get_serialized_string() const override
262 {
263 return to_string_impl(false);
264 }
265
266 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
267 {
268 return to_string_impl(true);
269 }
270
271 /** Required by variant_value_base. */
272 IMPLEMENT_VALUE_TYPE(formula_variant::type::decimal)
273
274private:
275 std::string to_string_impl(const bool sign_value) const;
276};
277
278
280{
281public:
284
285 virtual bool as_bool() const override
286 {
287 return callable_ != nullptr;
288 }
289
290 virtual std::size_t num_elements() const override
291 {
292 return 1;
293 }
294
296 {
297 return callable_;
298 }
299
300 virtual std::string string_cast() const override
301 {
302 return "(object)";
303 }
304
305 virtual std::string get_serialized_string() const override;
306
307 virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
308
309 virtual bool equals(const variant_value_base& other) const override;
310 virtual bool less_than(const variant_value_base& other) const override;
311
312 /** Required by variant_value_base. */
313 IMPLEMENT_VALUE_TYPE(formula_variant::type::object)
314
315 virtual boost::iterator_range<variant_iterator> make_iterator() const override;
316 virtual variant deref_iterator(const utils::any& iter) const override;
317
318 virtual void iterator_inc(utils::any& iter) const override;
319 virtual void iterator_dec(utils::any& iter) const override;
320 virtual bool iterator_equals(const utils::any& /*first*/, const utils::any& /*second*/) const override
321 {
322 return true; // TODO: implement
323 }
324
325private:
326 void notify_dead() override {callable_.reset();}
327
328 mutable formula_input_vector inputs; // for iteration
330};
331
332
334{
335public:
336 explicit variant_string(const std::string& str) : string_(str) {}
337 explicit variant_string(std::string&& str) : string_(std::move(str)) {}
338
339 virtual bool is_empty() const override
340 {
341 return string_.empty();
342 }
343
344 virtual bool as_bool() const override
345 {
346 return !is_empty();
347 }
348
349 const std::string& get_string() const
350 {
351 return string_;
352 }
353
354 virtual std::string string_cast() const override
355 {
356 return string_;
357 }
358
359 virtual std::string get_serialized_string() const override;
360
361 virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
362 {
363 return string_;
364 }
365
366 virtual bool equals(const variant_value_base& other) const override
367 {
368 return string_ == utils::cast_as(*this, other).string_;
369 }
370
371 virtual bool less_than(const variant_value_base& other) const override
372 {
373 return string_ < utils::cast_as(*this, other).string_;
374 }
375
376 /** Required by variant_value_base. */
377 IMPLEMENT_VALUE_TYPE(formula_variant::type::string)
378
379private:
380 std::string string_;
381};
382
383/**
384 * Generalized interface for container variants.
385 */
386template<typename Container>
388{
389public:
390 explicit variant_container(const Container& c)
391 : container_(c)
392 {
393 }
394
395 explicit variant_container(Container&& c)
396 : container_(std::move(c))
397 {
398 }
399
400 const Container& get_container() const
401 {
402 return container_;
403 }
404
405 virtual bool is_empty() const override
406 {
407 return container_.empty();
408 }
409
410 virtual std::size_t num_elements() const override
411 {
412 return container_.size();
413 }
414
415 virtual bool as_bool() const override
416 {
417 return !is_empty();
418 }
419
420 virtual std::string string_cast() const override;
421 virtual std::string get_serialized_string() const override;
422 virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
423
424 // We implement these here since the interface is the same for all
425 // specializations and leave the deref function to the derived classes.
426 virtual boost::iterator_range<variant_iterator> make_iterator() const override;
427
428 virtual void iterator_inc(utils::any&) const override;
429 virtual void iterator_dec(utils::any&) const override;
430 virtual bool iterator_equals(const utils::any& first, const utils::any& second) const override;
431
432 /** Inherited from variant_value_base. */
433 virtual bool equals(const variant_value_base& other) const override
434 {
435 return container_ == utils::cast_as(*this, other).container_;
436 }
437
438 /** Inherited from variant_value_base. */
439 virtual bool less_than(const variant_value_base& other) const override
440 {
441 return container_ < utils::cast_as(*this, other).container_;
442 }
443
444protected:
445 using iterator = typename Container::iterator;
446 using const_iterator = typename Container::const_iterator;
447
448 /** Casts opaque @a iter to a mutable const_iterator reference. */
449 static const_iterator& as_container_iterator(utils::any& iter)
450 {
451 return utils::any_cast<const_iterator&>(iter);
452 }
453
454 /** Casts opaque @a iter to a constant const_iterator reference. */
455 static const const_iterator& as_container_iterator(const utils::any& iter)
456 {
457 return utils::any_cast<const const_iterator&>(iter);
458 }
459
460private:
461 Container container_;
462};
463
464
465class variant_list : public variant_container<std::vector<variant>>
466{
467public:
468 explicit variant_list(const std::vector<variant>& vec)
469 : variant_container(vec)
470 {
471 }
472
473 explicit variant_list(std::vector<variant>&& vec)
474 : variant_container(std::move(vec))
475 {
476 }
477
478 /** Required by variant_value_base. */
479 IMPLEMENT_VALUE_TYPE(formula_variant::type::list)
480
481 virtual variant deref_iterator(const utils::any&) const override;
482};
483
484
485class variant_map : public variant_container<std::map<variant, variant>>
486{
487public:
488 explicit variant_map(const std::map<variant, variant>& map)
489 : variant_container(map)
490 {
491 }
492
493 explicit variant_map(std::map<variant, variant>&& map)
494 : variant_container(std::move(map))
495 {
496 }
497
498 /** Required by variant_value_base. */
499 IMPLEMENT_VALUE_TYPE(formula_variant::type::map)
500
501 virtual variant deref_iterator(const utils::any&) const override;
502};
503
504#undef IMPLEMENT_VALUE_TYPE
505
506} // namespace wfl
MacOS doesn't support std::any_cast when targing MacOS < 10.14 (currently we target 10....
void notify_dead() override
virtual bool equals(const variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) const override
Returns debug info for the variant value.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
virtual bool iterator_equals(const utils::any &, const utils::any &) const override
Implements the equality functionality of variant_iterator for a value of this type.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual variant deref_iterator(const utils::any &iter) const override
Implements the dereference functionality of variant_iterator for a value of this type.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual void iterator_inc(utils::any &iter) const override
Implements the increment functionality of variant_iterator for a value of this type.
virtual std::size_t num_elements() const override
Returns the number of elements in a type.
virtual boost::iterator_range< variant_iterator > make_iterator() const override
Required by variant_value_base.
formula_input_vector inputs
virtual void iterator_dec(utils::any &iter) const override
Implements the decrement functionality of variant_iterator for a value of this type.
const_formula_callable_ptr callable_
const_formula_callable_ptr get_callable() const
virtual bool less_than(const variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
Generalized interface for container variants.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual void iterator_dec(utils::any &) const override
Implements the decrement functionality of variant_iterator for a value of this type.
typename Container::const_iterator const_iterator
variant_container(Container &&c)
static const_iterator & as_container_iterator(utils::any &iter)
Casts opaque iter to a mutable const_iterator reference.
virtual bool less_than(const variant_value_base &other) const override
Inherited from variant_value_base.
virtual bool is_empty() const override
Whether the stored value is considered empty or not.
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) const override
Returns debug info for the variant value.
static const const_iterator & as_container_iterator(const utils::any &iter)
Casts opaque iter to a constant const_iterator reference.
variant_container(const Container &c)
virtual boost::iterator_range< variant_iterator > make_iterator() const override
Creates an iterator pair that can be used for iteration.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
virtual std::size_t num_elements() const override
Returns the number of elements in a type.
const Container & get_container() const
typename Container::iterator iterator
virtual bool iterator_equals(const utils::any &first, const utils::any &second) const override
Implements the equality functionality of variant_iterator for a value of this type.
virtual void iterator_inc(utils::any &) const override
Implements the increment functionality of variant_iterator for a value of this type.
virtual bool equals(const variant_value_base &other) const override
Inherited from variant_value_base.
std::string to_string_impl(const bool sign_value) const
Required by variant_value_base.
variant_decimal(double value)
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
variant build_range_variant(int limit) const
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
variant_list(const std::vector< variant > &vec)
virtual variant deref_iterator(const utils::any &) const override
Required by variant_value_base.
variant_list(std::vector< variant > &&vec)
virtual variant deref_iterator(const utils::any &) const override
Required by variant_value_base.
variant_map(std::map< variant, variant > &&map)
variant_map(const std::map< variant, variant > &map)
Base class for numeric variant values.
int get_numeric_value() const
virtual bool less_than(const variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
virtual bool equals(const variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual bool equals(const variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
variant_string(const std::string &str)
const std::string & get_string() const
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
variant_string(std::string &&str)
virtual bool is_empty() const override
Whether the stored value is considered empty or not.
virtual bool less_than(const variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
std::string string_
Required by variant_value_base.
Base class for all variant types.
virtual bool equals(const variant_value_base &) const
Called to determine if this variant is equal to another of the same type.
virtual std::string get_debug_string(formula_seen_stack &, bool) const
Returns debug info for the variant value.
virtual bool iterator_equals(const utils::any &, const utils::any &) const
Implements the equality functionality of variant_iterator for a value of this type.
virtual boost::iterator_range< variant_iterator > make_iterator() const
Creates an iterator pair that can be used for iteration.
virtual bool as_bool() const
Returns a bool expression of the variant value.
virtual formula_variant::type get_type() const
Returns the id of the variant type.
virtual bool less_than(const variant_value_base &) const
Called to determine if this variant is less than another of the same type.
virtual variant deref_iterator(const utils::any &iter) const
Implements the dereference functionality of variant_iterator for a value of this type.
virtual std::string string_cast() const
Returns the stored variant value in plain string form.
virtual void iterator_dec(utils::any &) const
Implements the decrement functionality of variant_iterator for a value of this type.
static constexpr auto value_type
Each 'final' derived class should define a static type flag.
virtual void iterator_inc(utils::any &) const
Implements the increment functionality of variant_iterator for a value of this type.
virtual std::size_t num_elements() const
Returns the number of elements in a type.
virtual std::string get_serialized_string() const
Returns the stored variant value in formula syntax.
virtual bool is_empty() const
Whether the stored value is considered empty or not.
STL namespace.
To & cast_as(To &, From &value)
std::vector< const_formula_callable_ptr > formula_seen_stack
std::vector< formula_input > formula_input_vector
std::shared_ptr< const formula_callable > const_formula_callable_ptr
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
#define IMPLEMENT_VALUE_TYPE(value)
#define c