The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
variant_value.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #include "formula/variant.hpp"
16 
17 #include "formula/callable.hpp"
18 #include "formula/function.hpp"
19 
20 namespace wfl
21 {
22 
23 boost::iterator_range<variant_iterator> variant_value_base::make_iterator() const
24 {
25  return {variant_iterator(), variant_iterator()};
26 }
27 
28 variant variant_value_base::deref_iterator(const boost::any& /*iter*/) const
29 {
30  return variant();
31 }
32 
34 {
35  const int len = std::abs(limit - value_) + 1;
36 
37  std::vector<variant> res;
38  res.reserve(len);
39 
40  for(int i = value_; res.size() != res.capacity(); value_ < limit ? ++i : --i) {
41  res.emplace_back(i);
42  }
43 
44  return variant(res);
45 }
46 
47 std::string variant_decimal::to_string_impl(const bool sign_value) const
48 {
49  std::ostringstream ss;
50 
51  int fractional = value_ % 1000;
52  int integer = (value_ - fractional) / 1000;
53 
54  if(sign_value) {
55  // Make sure we get the sign on small negative values.
56  if(integer == 0 && value_ < 0) {
57  ss << '-';
58  }
59  }
60 
61  ss << integer << ".";
62 
63  fractional = std::abs(fractional);
64 
65  if(fractional < 100) {
66  if(fractional < 10) {
67  ss << "00";
68  } else {
69  ss << 0;
70  }
71  }
72 
73  ss << fractional;
74 
75  return ss.str();
76 }
77 
79  : callable_(callable)
80 {
81  if(callable_) {
82  callable_->subscribe_dtor(this);
83  }
84 }
85 
87  if(callable_) {
88  callable_->unsubscribe_dtor(this);
89  }
90 }
91 
93 {
94  // TODO: make serialize return a string.
95  std::string str;
96  if(callable_) {
97  callable_->serialize(str);
98  }
99 
100  return str;
101 }
102 
104 {
105  std::ostringstream ss;
106  ss << "{";
107 
108  if(!callable_) {
109  ss << "null";
110  } else if(std::find(seen.begin(), seen.end(), callable_) == seen.end()) {
111  if(!verbose) {
112  seen.push_back(callable_);
113  }
114 
115  formula_input_vector v = callable_->inputs();
116  bool first = true;
117 
118  for(const auto& input : v) {
119  if(!first) {
120  ss << ", ";
121  }
122 
123  first = false;
124  ss << input.name << " ";
125 
126  if(input.access == FORMULA_READ_WRITE) {
127  ss << "(read-write) ";
128  } else if(input.access == FORMULA_WRITE_ONLY) {
129  ss << "(writeonly) ";
130  }
131 
132  ss << "-> " << callable_->query_value(input.name).to_debug_string(verbose, &seen);
133  }
134  } else {
135  ss << "...";
136  }
137 
138  ss << "}";
139 
140  return ss.str();
141 }
142 
144 {
145  variant_callable& other_ref = value_ref_cast<variant_callable>(other);
146  return callable_ ? callable_->equals(*other_ref.callable_) : callable_ == other_ref.callable_;
147 }
148 
150 {
151  variant_callable& other_ref = value_ref_cast<variant_callable>(other);
152  return callable_ ? callable_->less(*other_ref.callable_) : other_ref.callable_ != nullptr;
153 }
154 
155 boost::iterator_range<variant_iterator> variant_callable::make_iterator() const
156 {
157  if(!callable_) {
159  }
160 
161  if(inputs.empty()) {
162  callable_->get_inputs(inputs);
163  }
164 
165  return {variant_iterator(this, inputs.cbegin()), variant_iterator(this, inputs.cend())};
166 }
167 
168 variant variant_callable::deref_iterator(const boost::any& iter) const
169 {
170  if(!callable_) {
171  return variant();
172  }
173 
174  return callable_->query_value(boost::any_cast<const formula_input_vector::const_iterator&>(iter)->name);
175 }
176 
177 void variant_callable::iterator_inc(boost::any& iter) const
178 {
179  ++boost::any_cast<formula_input_vector::const_iterator&>(iter);
180 }
181 
182 void variant_callable::iterator_dec(boost::any& iter) const
183 {
184  --boost::any_cast<formula_input_vector::const_iterator&>(iter);
185 }
186 
188 {
189  std::ostringstream ss;
190  ss << "'";
191 
192  for(const auto& c : string_) {
193  switch(c) {
194  case '\'':
195  ss << "[']";
196  break;
197  case '[':
198  ss << "[(]";
199  break;
200  case ']':
201  ss << "[)]";
202  break;
203  default:
204  ss << c;
205  break;
206  }
207  }
208 
209  ss << "'";
210 
211  return ss.str();
212 }
213 
214 template<typename T>
215 std::string variant_container<T>::to_string_impl(bool annotate, bool annotate_empty, mod_func_t mod_func) const
216 {
217  std::ostringstream ss;
218 
219  if(annotate) {
220  ss << "[";
221  }
222 
223  bool first_time = true;
224 
225  for(const auto& member : container_) {
226  if(!first_time) {
227  ss << ", ";
228  }
229 
230  first_time = false;
231 
232  ss << to_string_detail(member, mod_func);
233  }
234 
235  // TODO: evaluate if this really needs to be separately conditional.
236  if(annotate_empty && container_.empty()) {
237  ss << "->";
238  }
239 
240  if(annotate) {
241  ss << "]";
242  }
243 
244  return ss.str();
245 }
246 
247 template<typename T>
249 {
250  return to_string_impl(false, false, [](const variant& v) { return v.string_cast(); });
251 }
252 
253 template<typename T>
255 {
256  return to_string_impl(true, true, [](const variant& v) { return v.serialize_to_string(); });
257 }
258 
259 template<typename T>
261 {
262  return to_string_impl(true, false, [&](const variant& v) { return v.to_debug_string(verbose, &seen); });
263 }
264 
265 template<typename T>
266 boost::iterator_range<variant_iterator> variant_container<T>::make_iterator() const
267 {
268  return {variant_iterator(this, get_container().cbegin()), variant_iterator(this, get_container().cend())};
269 }
270 
271 template<typename T>
272 void variant_container<T>::iterator_inc(boost::any& iter) const
273 {
274  ++boost::any_cast<typename T::const_iterator&>(iter);
275 }
276 
277 template<typename T>
278 void variant_container<T>::iterator_dec(boost::any& iter) const
279 {
280  --boost::any_cast<typename T::const_iterator&>(iter);
281 }
282 
283 template<typename T>
284 bool variant_container<T>::iterator_equals(const boost::any& first, const boost::any& second) const
285 {
286  return boost::any_cast<typename T::const_iterator>(first) == boost::any_cast<typename T::const_iterator>(second);
287 }
288 
289 // Force compilation of the following template instantiations
290 template class variant_container<variant_vector>;
292 
294 {
295  const auto& other_list = value_cast<variant_list>(second);
296 
297  if(num_elements() != other_list->num_elements()) {
298  throw type_error("List op requires two lists of the same length");
299  }
300 
301  std::vector<variant> res;
302  res.reserve(num_elements());
303 
304  for(size_t i = 0; i < num_elements(); ++i) {
305  res.push_back(op_func(get_container()[i], other_list->get_container()[i]));
306  }
307 
308  return variant(res);
309 }
310 
312 {
313  const auto& other_container = value_ref_cast<variant_list>(other).get_container();
314 
315  if(num_elements() != other.num_elements()) {
316  return false;
317  }
318 
319  for(size_t n = 0; n < num_elements(); ++n) {
320  if(get_container()[n] != other_container[n]) {
321  return false;
322  }
323  }
324 
325  return true;
326 }
327 
329 {
330  const auto& other_container = value_ref_cast<variant_list>(other).get_container();
331 
332  for(size_t n = 0; n != num_elements() && n != other.num_elements(); ++n) {
333  if(get_container()[n] < other_container[n]) {
334  return true;
335  } else if(get_container()[n] > other_container[n]) {
336  return false;
337  }
338  }
339 
340  return num_elements() < other.num_elements();
341 }
342 
343 variant variant_list::deref_iterator(const boost::any& iter) const
344 {
345  return *boost::any_cast<const variant_vector::const_iterator&>(iter);
346 }
347 
348 std::string variant_map::to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const
349 {
350  std::ostringstream ss;
351 
352  ss << mod_func(container_val.first);
353  ss << "->";
354  ss << mod_func(container_val.second);
355 
356  return ss.str();
357 }
358 
360 {
361  return get_container() == value_ref_cast<variant_map>(other).get_container();
362 }
363 
365 {
366  return get_container() < value_ref_cast<variant_map>(other).get_container();
367 }
368 
369 variant variant_map::deref_iterator(const boost::any& iter) const
370 {
371  const variant_map_raw::value_type& p = *boost::any_cast<const variant_map_raw::const_iterator&>(iter);
372  auto the_pair = std::make_shared<key_value_pair>(p.first, p.second);
373  return variant(the_pair);
374 }
375 
376 } // namespace wfl
std::vector< char_t > string
virtual bool iterator_equals(const boost::any &first, const boost::any &second) const override
Implements the equality functionality of variant_iterator for a value of this type.
virtual void iterator_dec(boost::any &) const override
Implements the decrement functionality of variant_iterator for a value of this 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 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 to_string_detail(const variant_map_raw::value_type &container_val, mod_func_t mod_func) const override
virtual variant deref_iterator(const boost::any &) const override
Implements the dereference functionality of variant_iterator for a value of this type.
std::shared_ptr< variant_value_base > value_base_ptr
virtual variant deref_iterator(const boost::any &) const override
Implements the dereference 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.
std::vector< formula_input > formula_input_vector
virtual variant deref_iterator(const boost::any &iter) const
Implements the dereference functionality of variant_iterator for a value of this type.
static std::shared_ptr< T > value_cast(value_base_ptr ptr)
Casts a variant_value_base shared pointer to a new derived type.
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) 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 bool equals(variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
virtual size_t num_elements() const
Returns the number of elements in a type.
virtual void iterator_inc(boost::any &iter) const override
Implements the increment functionality of variant_iterator for a value of this type.
static T & value_ref_cast(variant_value_base &ptr)
Casts a variant_value_base reference to a new derived 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 boost::iterator_range< variant_iterator > make_iterator() const override
Creates an iterator pair that can be used for iteration.
std::string to_string_impl(const bool sign_value) const
virtual void iterator_dec(boost::any &iter) const override
Implements the decrement functionality of variant_iterator for a value of this type.
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) const override
Returns debug info for the variant value.
const_formula_callable_ptr callable_
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
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, and get_debug_string.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
std::string string_cast() const
Definition: variant.cpp:644
mock_party p
std::vector< const_formula_callable_ptr > formula_seen_stack
#define i
std::shared_ptr< const formula_callable > const_formula_callable_ptr
virtual bool equals(variant_value_base &other) const override
Called to determine if this variant is equal to another of the same type.
std::function< std::string(const variant &)> mod_func_t
Definition: contexts.hpp:42
virtual void iterator_inc(boost::any &) const override
Implements the increment functionality of variant_iterator for a value of this type.
bool find(E event, F functor)
Tests whether an event handler is available.
formula_input_vector inputs
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:649
virtual size_t num_elements() const override
Returns the number of elements in a type.
Base class for all variant types.
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
std::string serialize_to_string() const
Definition: variant.cpp:630
virtual boost::iterator_range< variant_iterator > make_iterator() const override
Creates an iterator pair that can be used for iteration.
variant_callable(const_formula_callable_ptr callable)
Iterator class for the variant.
Definition: variant.hpp:182
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
mock_char c
virtual variant deref_iterator(const boost::any &iter) const override
Implements the dereference functionality of variant_iterator for a value of this type.
static map_location::DIRECTION n
variant build_range_variant(int limit) const