The Battle for Wesnoth  1.19.0-dev
variant_value.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 - 2024
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 #include "formula/variant.hpp"
17 
18 #include "formula/callable.hpp"
19 #include "formula/function.hpp"
20 
21 namespace wfl
22 {
23 
24 boost::iterator_range<variant_iterator> variant_value_base::make_iterator() const
25 {
26  return {variant_iterator(), variant_iterator()};
27 }
28 
29 variant variant_value_base::deref_iterator(const utils::any& /*iter*/) const
30 {
31  return variant();
32 }
33 
35 {
36  const int len = std::abs(limit - value_) + 1;
37 
38  std::vector<variant> res;
39  res.reserve(len);
40 
41  for(int i = value_; res.size() != res.capacity(); value_ < limit ? ++i : --i) {
42  res.emplace_back(i);
43  }
44 
45  return variant(res);
46 }
47 
48 std::string variant_decimal::to_string_impl(const bool sign_value) const
49 {
50  std::ostringstream ss;
51 
52  int fractional = value_ % 1000;
53  int integer = (value_ - fractional) / 1000;
54 
55  if(sign_value) {
56  // Make sure we get the sign on small negative values.
57  if(integer == 0 && value_ < 0) {
58  ss << '-';
59  }
60  }
61 
62  ss << integer << ".";
63 
64  fractional = std::abs(fractional);
65 
66  if(fractional < 100) {
67  if(fractional < 10) {
68  ss << "00";
69  } else {
70  ss << 0;
71  }
72  }
73 
74  ss << fractional;
75 
76  return ss.str();
77 }
78 
80  : callable_(callable)
81 {
82  if(callable_) {
83  callable_->subscribe_dtor(this);
84  }
85 }
86 
88  if(callable_) {
89  callable_->unsubscribe_dtor(this);
90  }
91 }
92 
94 {
95  // TODO: make serialize return a string.
96  std::string str;
97  if(callable_) {
98  callable_->serialize(str);
99  }
100 
101  return str;
102 }
103 
104 std::string variant_callable::get_debug_string(formula_seen_stack& seen, bool verbose) const
105 {
106  std::ostringstream ss;
107  ss << "{";
108 
109  if(!callable_) {
110  ss << "null";
111  } else if(std::find(seen.begin(), seen.end(), callable_) == seen.end()) {
112  if(!verbose) {
113  seen.push_back(callable_);
114  }
115 
116  formula_input_vector v = callable_->inputs();
117  bool first = true;
118 
119  for(const auto& input : v) {
120  if(!first) {
121  ss << ", ";
122  }
123 
124  first = false;
125  ss << input.name << " ";
126 
127  if(input.access == formula_access::read_write) {
128  ss << "(read-write) ";
129  } else if(input.access == formula_access::write_only) {
130  ss << "(writeonly) ";
131  }
132 
133  ss << "-> " << callable_->query_value(input.name).to_debug_string(verbose, &seen);
134  }
135  } else {
136  ss << "...";
137  }
138 
139  ss << "}";
140 
141  return ss.str();
142 }
143 
145 {
146  variant_callable& other_ref = value_ref_cast<variant_callable>(other);
147  return callable_ ? callable_->equals(*other_ref.callable_) : callable_ == other_ref.callable_;
148 }
149 
151 {
152  variant_callable& other_ref = value_ref_cast<variant_callable>(other);
153  return callable_ ? callable_->less(*other_ref.callable_) : other_ref.callable_ != nullptr;
154 }
155 
156 boost::iterator_range<variant_iterator> variant_callable::make_iterator() const
157 {
158  if(!callable_) {
160  }
161 
162  if(inputs.empty()) {
163  callable_->get_inputs(inputs);
164  }
165 
166  return {variant_iterator(this, inputs.cbegin()), variant_iterator(this, inputs.cend())};
167 }
168 
169 variant variant_callable::deref_iterator(const utils::any& iter) const
170 {
171  if(!callable_) {
172  return variant();
173  }
174 
175  return callable_->query_value(utils::any_cast<const formula_input_vector::const_iterator&>(iter)->name);
176 }
177 
178 void variant_callable::iterator_inc(utils::any& iter) const
179 {
180  ++utils::any_cast<formula_input_vector::const_iterator&>(iter);
181 }
182 
183 void variant_callable::iterator_dec(utils::any& iter) const
184 {
185  --utils::any_cast<formula_input_vector::const_iterator&>(iter);
186 }
187 
189 {
190  std::ostringstream ss;
191  ss << "'";
192 
193  for(const auto& c : string_) {
194  switch(c) {
195  case '\'':
196  ss << "[']";
197  break;
198  case '[':
199  ss << "[(]";
200  break;
201  case ']':
202  ss << "[)]";
203  break;
204  default:
205  ss << c;
206  break;
207  }
208  }
209 
210  ss << "'";
211 
212  return ss.str();
213 }
214 
215 template<typename T>
216 std::string variant_container<T>::to_string_impl(bool annotate, bool annotate_empty, mod_func_t mod_func) const
217 {
218  std::ostringstream ss;
219 
220  if(annotate) {
221  ss << "[";
222  }
223 
224  bool first_time = true;
225 
226  for(const auto& member : container_) {
227  if(!first_time) {
228  ss << ", ";
229  }
230 
231  first_time = false;
232 
233  ss << to_string_detail(member, mod_func);
234  }
235 
236  // TODO: evaluate if this really needs to be separately conditional.
237  if(annotate_empty && container_.empty()) {
238  ss << "->";
239  }
240 
241  if(annotate) {
242  ss << "]";
243  }
244 
245  return ss.str();
246 }
247 
248 template<typename T>
250 {
251  return to_string_impl(false, false, [](const variant& v) { return v.string_cast(); });
252 }
253 
254 template<typename T>
256 {
257  return to_string_impl(true, true, [](const variant& v) { return v.serialize_to_string(); });
258 }
259 
260 template<typename T>
261 std::string variant_container<T>::get_debug_string(formula_seen_stack& seen, bool verbose) const
262 {
263  return to_string_impl(true, false, [&](const variant& v) { return v.to_debug_string(verbose, &seen); });
264 }
265 
266 template<typename T>
267 boost::iterator_range<variant_iterator> variant_container<T>::make_iterator() const
268 {
269  return {variant_iterator(this, get_container().cbegin()), variant_iterator(this, get_container().cend())};
270 }
271 
272 template<typename T>
273 void variant_container<T>::iterator_inc(utils::any& iter) const
274 {
275  ++utils::any_cast<typename T::const_iterator&>(iter);
276 }
277 
278 template<typename T>
279 void variant_container<T>::iterator_dec(utils::any& iter) const
280 {
281  --utils::any_cast<typename T::const_iterator&>(iter);
282 }
283 
284 template<typename T>
285 bool variant_container<T>::iterator_equals(const utils::any& first, const utils::any& second) const
286 {
287  return utils::any_cast<typename T::const_iterator>(first) == utils::any_cast<typename T::const_iterator>(second);
288 }
289 
290 // Force compilation of the following template instantiations
291 template class variant_container<variant_vector>;
293 
295 {
296  const auto& other_list = value_cast<variant_list>(second);
297 
298  if(num_elements() != other_list->num_elements()) {
299  throw type_error("List op requires two lists of the same length");
300  }
301 
302  std::vector<variant> res;
303  res.reserve(num_elements());
304 
305  for(std::size_t i = 0; i < num_elements(); ++i) {
306  res.push_back(op_func(get_container()[i], other_list->get_container()[i]));
307  }
308 
309  return variant(res);
310 }
311 
313 {
314  const auto& other_container = value_ref_cast<variant_list>(other).get_container();
315 
316  if(num_elements() != other.num_elements()) {
317  return false;
318  }
319 
320  for(std::size_t n = 0; n < num_elements(); ++n) {
321  if(get_container()[n] != other_container[n]) {
322  return false;
323  }
324  }
325 
326  return true;
327 }
328 
330 {
331  const auto& other_container = value_ref_cast<variant_list>(other).get_container();
332 
333  for(std::size_t n = 0; n != num_elements() && n != other.num_elements(); ++n) {
334  if(get_container()[n] < other_container[n]) {
335  return true;
336  } else if(get_container()[n] > other_container[n]) {
337  return false;
338  }
339  }
340 
341  return num_elements() < other.num_elements();
342 }
343 
344 variant variant_list::deref_iterator(const utils::any& iter) const
345 {
346  return *utils::any_cast<const variant_vector::const_iterator&>(iter);
347 }
348 
349 std::string variant_map::to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const
350 {
351  std::ostringstream ss;
352 
353  ss << mod_func(container_val.first);
354  ss << "->";
355  ss << mod_func(container_val.second);
356 
357  return ss.str();
358 }
359 
361 {
362  return get_container() == value_ref_cast<variant_map>(other).get_container();
363 }
364 
366 {
367  return get_container() < value_ref_cast<variant_map>(other).get_container();
368 }
369 
370 variant variant_map::deref_iterator(const utils::any& iter) const
371 {
372  const variant_map_raw::value_type& p = *utils::any_cast<const variant_map_raw::const_iterator&>(iter);
373  auto the_pair = std::make_shared<key_value_pair>(p.first, p.second);
374  return variant(the_pair);
375 }
376 
377 } // namespace wfl
virtual bool equals(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 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 void iterator_inc(utils::any &iter) const override
Implements the increment functionality of variant_iterator for a value of this type.
virtual boost::iterator_range< variant_iterator > make_iterator() const override
Creates an iterator pair that can be used for iteration.
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_
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
std::string to_string_impl(bool annotate, bool annotate_empty, mod_func_t mod_func) const
Implementation to handle string conversion for string_cast, get_serialized_string,...
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.
virtual std::size_t num_elements() const override
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) const override
Returns debug info for the variant value.
virtual boost::iterator_range< variant_iterator > make_iterator() const override
Creates an iterator pair that can be used for iteration.
std::function< std::string(const variant &)> mod_func_t
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.
std::string to_string_impl(const bool sign_value) const
variant build_range_variant(int limit) const
Iterator class for the variant.
Definition: variant.hpp:187
virtual variant deref_iterator(const utils::any &) const override
Implements the dereference functionality of variant_iterator for a value of this type.
variant list_op(value_base_ptr second, std::function< variant(variant &, variant &)> op_func)
Applies the provided function to the corresponding variants in this and another list.
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
virtual bool equals(variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
virtual std::string to_string_detail(const variant_map_raw::value_type &container_val, mod_func_t mod_func) const override
virtual variant deref_iterator(const utils::any &) const override
Implements the dereference functionality of variant_iterator for a value of this type.
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
virtual bool equals(variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
Base class for all variant types.
virtual boost::iterator_range< variant_iterator > make_iterator() const
Creates an iterator pair that can be used for iteration.
virtual variant deref_iterator(const utils::any &iter) const
Implements the dereference 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.
std::string serialize_to_string() const
Definition: variant.cpp:623
std::string string_cast() const
Definition: variant.cpp:638
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643
std::size_t i
Definition: function.cpp:968
Definition: contexts.hpp:43
std::shared_ptr< variant_value_base > value_base_ptr
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
mock_party p
static map_location::DIRECTION n