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