The Battle for Wesnoth  1.19.23+dev
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 
17 #include "formula/callable_fwd.hpp"
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 
27 namespace utils
28 {
29 template<typename To, typename From>
30 inline To& cast_as(To&, From& value)
31 {
32  return static_cast<To&>(value);
33 }
34 
35 } // namespace utils
36 
37 namespace wfl
38 {
39 class variant_value_base;
40 class variant_iterator;
41 class 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 {
61 public:
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 */
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 
173  virtual ~variant_value_base() {}
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 {
183 public:
184  explicit variant_numeric(int value) : value_(value) {}
185 
186  virtual bool as_bool() const override
187  {
188  return value_ != 0;
189  }
190 
191  int get_numeric_value() const
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 
206 protected:
207  int value_;
208 };
209 
210 
212 {
213 public:
214  explicit variant_int(int value) : variant_numeric(value) {}
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 {
240 public:
241  explicit variant_decimal(int value) : variant_numeric(value) {}
242 
243  explicit variant_decimal(double value) : variant_numeric(0)
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 
274 private:
275  std::string to_string_impl(const bool sign_value) const;
276 };
277 
278 
280 {
281 public:
282  explicit variant_callable(const_formula_callable_ptr callable);
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 
325 private:
326  void notify_dead() override {callable_.reset();}
327 
328  mutable formula_input_vector inputs; // for iteration
330 };
331 
332 
334 {
335 public:
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 
379 private:
380  std::string string_;
381 };
382 
383 /**
384  * Generalized interface for container variants.
385  */
386 template<typename Container>
388 {
389 public:
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 
444 protected:
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 
460 private:
461  Container container_;
462 };
463 
464 
465 class variant_list : public variant_container<std::vector<variant>>
466 {
467 public:
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 
485 class variant_map : public variant_container<std::map<variant, variant>>
486 {
487 public:
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.
variant_callable(const_formula_callable_ptr callable)
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)
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.
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.
static const_iterator & as_container_iterator(utils::any &iter)
Casts opaque iter to a mutable const_iterator reference.
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.
const Container & get_container() const
static const const_iterator & as_container_iterator(const utils::any &iter)
Casts opaque iter to a constant const_iterator reference.
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_int(int value)
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)
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.
const std::string & get_string() const
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.
To & cast_as(To &, From &value)
std::string to_string(const Range &range, const Func &op)
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Definition: callable.hpp:26
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
mock_char c
#define IMPLEMENT_VALUE_TYPE(value)