The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
variant_value.hpp
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 #pragma once
15 
16 #include "exceptions.hpp"
17 #include "formula/callable_fwd.hpp"
18 #include "utils/general.hpp"
19 #include "utils/make_enum.hpp"
20 
21 #include <functional>
22 #include <iostream>
23 #include <iterator>
24 #include <map>
25 #include <sstream>
26 #include <utility>
27 #include <vector>
28 #include <boost/range/iterator_range.hpp>
29 #include <boost/any.hpp>
30 
31 namespace wfl
32 {
33 class variant_value_base;
34 class variant_iterator;
35 class variant;
36 
37 /** The various types the variant class is designed to handle */
38 MAKE_ENUM(VARIANT_TYPE,
39  (TYPE_NULL, "null")
40  (TYPE_INT, "int")
41  (TYPE_DECIMAL, "decimal")
42  (TYPE_CALLABLE, "object")
43  (TYPE_LIST, "list")
44  (TYPE_STRING, "string")
45  (TYPE_MAP, "map")
46 );
47 
48 using variant_vector = std::vector<variant>;
49 using variant_map_raw = std::map<variant, variant>;
50 using value_base_ptr = std::shared_ptr<variant_value_base>;
51 
52 struct type_error : public game::error
53 {
54  explicit type_error(const std::string& str);
55 };
56 
57 /** Casts a @ref variant_value_base shared pointer to a new derived type. */
58 template<typename T>
59 static std::shared_ptr<T> value_cast(value_base_ptr ptr)
60 {
61  std::shared_ptr<T> res = std::dynamic_pointer_cast<T>(ptr);
62  if(!res) {
63  throw type_error("Could not cast type");
64  }
65 
66  return res;
67 }
68 
69 /** Casts a @ref variant_value_base reference to a new derived type. */
70 template<typename T>
72 {
73  try {
74  return dynamic_cast<T&>(ptr);
75  } catch(std::bad_cast&) {
76  throw type_error("Could not cast type");
77  }
78 }
79 
80 /**
81  * Base class for all variant types.
82  *
83  * This provides a common interface for all type classes to implement, as well as
84  * giving variant a base pointer type for its value member. It also serves as the
85  * implementation of the 'null' variant value.
86  *
87  * Do note this class should *not* implement any data members.
88  */
90 {
91 public:
92  /** Returns the number of elements in a type. Not relevant for every derivative. */
93  virtual size_t num_elements() const
94  {
95  return 0;
96  }
97 
98  /** Whether the stored value is considered empty or not. */
99  virtual bool is_empty() const
100  {
101  return true;
102  }
103 
104  /** Returns the stored variant value in plain string form. */
105  virtual std::string string_cast() const
106  {
107  return "0";
108  }
109 
110  /** Returns the stored variant value in formula syntax. */
112  {
113  return "null()";
114  }
115 
116  /** Returns debug info for the variant value. */
117  virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const
118  {
119  return get_serialized_string();
120  }
121 
122  /** Returns a bool expression of the variant value. */
123  virtual bool as_bool() const
124  {
125  return false;
126  }
127 
128  /**
129  * Called to determine if this variant is equal to another _of the same type_.
130  * This function is _only_ called if get_type() returns the same result for both arguments.
131  */
132  virtual bool equals(variant_value_base& /*other*/) const
133  {
134  return true; // null is equal to null
135  }
136 
137  /**
138  * Called to determine if this variant is less than another _of the same type_.
139  * This function is _only_ called if get_type() returns the same result for both arguments.
140  */
141  virtual bool less_than(variant_value_base& /*other*/) const
142  {
143  return false; // null is not less than null
144  }
145 
146  /** Returns the id of the variant type */
147  virtual const VARIANT_TYPE& get_type() const
148  {
149  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_NULL;
150  return type;
151  }
152 
153  /**
154  * Creates an iterator pair that can be used for iteration.
155  * For an iterable type, it should use the two-argument constructor of variant-iterator,
156  * passing the underlying iterator as the boost::any parameter.
157  *
158  * This creates both the begin and end iterator, but the variant implementation
159  * discards one of the two.
160  */
161  virtual boost::iterator_range<variant_iterator> make_iterator() const;
162 
163  /**
164  * Implements the dereference functionality of @ref variant_iterator
165  * for a value of this type.
166  *
167  * @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
168  */
169  virtual variant deref_iterator(const boost::any& iter) const;
170 
171  /**
172  * Implements the increment functionality of @ref variant_iterator
173  * for a value of this type.
174  *
175  * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
176  */
177  virtual void iterator_inc(boost::any&) const {}
178 
179  /**
180  * Implements the decrement functionality of @ref variant_iterator
181  * for a value of this type.
182  *
183  * The parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
184  */
185  virtual void iterator_dec(boost::any&) const {}
186 
187  /**
188  * Implements the equality functionality of @ref variant_iterator
189  * for a value of this type.
190  *
191  * Note that this is only called if the two iterators are already known to be of the same type.
192  *
193  * The first parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
194  * The second parameter is an opaque reference that was passed to the variant_iterator by @ref make_iterator.
195  */
196  virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const
197  {
198  return true;
199  }
200 
201  virtual ~variant_value_base() {}
202 };
203 
204 
205 /**
206  * Base class for numeric variant values. Currently only supports a value stored as an
207  * integer, but for now, that's all that's necessary.
208  */
210 {
211 public:
212  explicit variant_numeric(int value) : value_(value) {}
213 
214  virtual bool as_bool() const override
215  {
216  return value_ != 0;
217  }
218 
219  int get_numeric_value() const
220  {
221  return value_;
222  }
223 
224  virtual bool equals(variant_value_base& other) const override
225  {
226  return value_ == value_ref_cast<variant_numeric>(other).value_;
227  }
228 
229  virtual bool less_than(variant_value_base& other) const override
230  {
231  return value_ < value_ref_cast<variant_numeric>(other).value_;
232  }
233 
234 protected:
235  int value_;
236 };
237 
238 
240 {
241 public:
242  explicit variant_int(int value) : variant_numeric(value) {}
243 
244  variant build_range_variant(int limit) const;
245 
246  virtual std::string string_cast() const override
247  {
248  return std::to_string(value_);
249  }
250 
251  virtual std::string get_serialized_string() const override
252  {
253  return string_cast();
254  }
255 
256  virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
257  {
258  return string_cast();
259  }
260 
261  virtual const VARIANT_TYPE& get_type() const override
262  {
263  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_INT;
264  return type;
265  }
266 };
267 
268 
270 {
271 public:
272  explicit variant_decimal(int value) : variant_numeric(value) {}
273 
274  explicit variant_decimal(double value) : variant_numeric(0)
275  {
276  value *= 1000;
277  value_ = static_cast<int>(value);
278  value -= value_;
279 
280  if(value > 0.5) {
281  value_++;
282  } else if(value < -0.5) {
283  value_--;
284  }
285  }
286 
287  virtual std::string string_cast() const override
288  {
289  return to_string_impl(false);
290  }
291 
292  virtual std::string get_serialized_string() const override
293  {
294  return to_string_impl(false);
295  }
296 
297  virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
298  {
299  return to_string_impl(true);
300  }
301 
302  virtual const VARIANT_TYPE& get_type() const override
303  {
304  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_DECIMAL;
305  return type;
306  }
307 
308 private:
309  std::string to_string_impl(const bool sign_value) const;
310 };
311 
312 
314 {
315 public:
316  explicit variant_callable(const_formula_callable_ptr callable);
318 
319  virtual bool as_bool() const override
320  {
321  return callable_ != nullptr;
322  }
323 
324  virtual size_t num_elements() const override
325  {
326  return 1;
327  }
328 
330  {
331  return callable_;
332  }
333 
334  virtual std::string string_cast() const override
335  {
336  return "(object)";
337  }
338 
339  virtual std::string get_serialized_string() const override;
340 
341  virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
342 
343  virtual bool equals(variant_value_base& other) const override;
344  virtual bool less_than(variant_value_base& other) const override;
345 
346  virtual const VARIANT_TYPE& get_type() const override
347  {
348  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_CALLABLE;
349  return type;
350  }
351 
352  virtual boost::iterator_range<variant_iterator> make_iterator() const override;
353  virtual variant deref_iterator(const boost::any& iter) const override;
354 
355  virtual void iterator_inc(boost::any& iter) const override;
356  virtual void iterator_dec(boost::any& iter) const override;
357  virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const override
358  {
359  return true; // TODO: implement
360  }
361 
362 private:
363  void notify_dead() override {callable_.reset();}
364 
365  mutable formula_input_vector inputs; // for iteration
367 };
368 
369 
371 {
372 public:
373  explicit variant_string(const std::string& str) : string_(str) {}
374 
375  virtual bool is_empty() const override
376  {
377  return string_.empty();
378  }
379 
380  virtual bool as_bool() const override
381  {
382  return !is_empty();
383  }
384 
385  const std::string& get_string() const
386  {
387  return string_;
388  }
389 
390  virtual std::string string_cast() const override
391  {
392  return string_;
393  }
394 
395  virtual std::string get_serialized_string() const override;
396 
397  virtual std::string get_debug_string(formula_seen_stack& /*seen*/, bool /*verbose*/) const override
398  {
399  return string_;
400  }
401 
402  virtual bool equals(variant_value_base& other) const override
403  {
404  return string_ == value_ref_cast<variant_string>(other).string_;
405  }
406 
407  virtual bool less_than(variant_value_base& other) const override
408  {
409  return string_ < value_ref_cast<variant_string>(other).string_;
410  }
411 
412  virtual const VARIANT_TYPE& get_type() const override
413  {
414  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_STRING;
415  return type;
416  }
417 
418 private:
420 };
421 
422 /**
423  * Generalized implementation handling container variants.
424  *
425  * This class shouldn't usually be used directly. Instead, it's better to
426  * create a new derived class specialized to a specific container type.
427  */
428 template<typename T>
430 {
431 public:
432  explicit variant_container(const T& container)
433  : container_(container)
434  {
435  // NOTE: add more conditions if this changes.
436  static_assert((std::is_same<variant_vector, T>::value || std::is_same<variant_map_raw, T>::value),
437  "variant_container only accepts vector or map specifications.");
438  }
439 
440  virtual bool is_empty() const override
441  {
442  return container_.empty();
443  }
444 
445  virtual size_t num_elements() const override
446  {
447  return container_.size();
448  }
449 
450  virtual bool as_bool() const override
451  {
452  return !is_empty();
453  }
454 
456  {
457  return container_;
458  }
459 
460  const T& get_container() const
461  {
462  return container_;
463  }
464 
465  virtual std::string string_cast() const override;
466 
467  virtual std::string get_serialized_string() const override;
468 
469  virtual std::string get_debug_string(formula_seen_stack& seen, bool verbose) const override;
470 
471  bool contains(const variant& member) const
472  {
473  return utils::contains<T, variant>(container_, member);
474  }
475 
476  // We implement these here since the interface is the same for all
477  // specializations and leave the deref function to the derived classes.
478  virtual boost::iterator_range<variant_iterator> make_iterator() const override;
479 
480  virtual void iterator_inc(boost::any&) const override;
481  virtual void iterator_dec(boost::any&) const override;
482  virtual bool iterator_equals(const boost::any& first, const boost::any& second) const override;
483 
484 protected:
485  using mod_func_t = std::function<std::string(const variant&)>;
486 
487  virtual std::string to_string_detail(const typename T::value_type& value, mod_func_t mod_func) const = 0;
488 
489 private:
490  /**
491  * Implementation to handle string conversion for @ref string_cast, @ref get_serialized_string,
492  * and @ref get_debug_string.
493  *
494  * Derived classes should provide type-specific value handling by implementing @ref to_string_detail.
495  */
496  std::string to_string_impl(bool annotate, bool annotate_empty, mod_func_t mod_func) const;
497 
499 };
500 
501 
502 class variant_list : public variant_container<variant_vector>
503 {
504 public:
505  explicit variant_list(const variant_vector& vec)
507  {}
508 
509  /**
510  * Applies the provided function to the corresponding variants in this and another list.
511  */
512  variant list_op(value_base_ptr second, std::function<variant(variant&, variant&)> op_func);
513 
514  virtual bool equals(variant_value_base& other) const override;
515  virtual bool less_than(variant_value_base& other) const override;
516 
517  virtual const VARIANT_TYPE& get_type() const override
518  {
519  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_LIST;
520  return type;
521  }
522 
523  virtual variant deref_iterator(const boost::any&) const override;
524 
525 private:
526  virtual std::string to_string_detail(const variant_vector::value_type& container_val, mod_func_t mod_func) const override
527  {
528  return mod_func(container_val);
529  }
530 };
531 
532 
533 class variant_map : public variant_container<variant_map_raw>
534 {
535 public:
536  explicit variant_map(const variant_map_raw& map)
538  {}
539 
540  virtual bool equals(variant_value_base& other) const override;
541  virtual bool less_than(variant_value_base& other) const override;
542 
543  virtual const VARIANT_TYPE& get_type() const override
544  {
545  static VARIANT_TYPE type = VARIANT_TYPE::TYPE_MAP;
546  return type;
547  }
548 
549  virtual variant deref_iterator(const boost::any&) const override;
550 
551 private:
552  virtual std::string to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const override;
553 };
554 
555 } // namespace wfl
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.
variant_map(const variant_map_raw &map)
virtual bool as_bool() const override
Returns a bool expression of the variant value.
const T & get_container() const
virtual bool is_empty() const
Whether the stored value is considered empty or not.
virtual void iterator_dec(boost::any &) const
Implements the decrement functionality of variant_iterator for a value of this type.
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 bool is_empty() const override
Whether the stored value is considered empty or not.
MAKE_ENUM(VARIANT_TYPE,(TYPE_NULL,"null")(TYPE_INT,"int")(TYPE_DECIMAL,"decimal")(TYPE_CALLABLE,"object")(TYPE_LIST,"list")(TYPE_STRING,"string")(TYPE_MAP,"map"))
The various types the variant class is designed to handle.
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
std::map< variant, variant > variant_map_raw
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
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 bool as_bool() const override
Returns a bool expression of the variant value.
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 bool is_empty() const override
Whether the stored value is considered empty or not.
int get_numeric_value() const
const std::string & get_string() const
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
virtual void iterator_inc(boost::any &) const
Implements the increment functionality of variant_iterator for a value of this type.
virtual const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
variant_list(const variant_vector &vec)
virtual bool equals(variant_value_base &) const
Called to determine if this variant is equal to 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 const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
virtual size_t num_elements() const
Returns the number of elements in a type.
variant_string(const std::string &str)
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 bool as_bool() const
Returns a bool expression of the variant value.
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
virtual std::string get_debug_string(formula_seen_stack &seen, bool verbose) const override
Returns debug info for the variant value.
virtual size_t num_elements() const override
Returns the number of elements in a type.
virtual const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
const_formula_callable_ptr callable_
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
virtual bool iterator_equals(const boost::any &, const boost::any &) const override
Implements the equality functionality of variant_iterator for a value of this type.
Generalized implementation handling container variants.
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.
type_error(const std::string &str)
Definition: variant.cpp:58
virtual std::string get_debug_string(formula_seen_stack &, bool) const
Returns debug info for the variant value.
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.
virtual const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
variant_container(const T &container)
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
variant_int(int value)
virtual std::string to_string_detail(const typename T::value_type &value, mod_func_t mod_func) const =0
std::vector< const_formula_callable_ptr > formula_seen_stack
virtual std::string to_string_detail(const variant_vector::value_type &container_val, mod_func_t mod_func) const override
virtual std::string string_cast() const override
Returns the stored variant value in plain string form.
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
virtual bool iterator_equals(const boost::any &, const boost::any &) const
Implements the equality functionality of variant_iterator for a value of this type.
std::vector< variant > variant_vector
virtual std::string get_debug_string(formula_seen_stack &, bool) const override
Returns debug info for the variant value.
Base class for numeric variant values.
bool contains(const variant &member) const
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.
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
formula_input_vector inputs
virtual std::string string_cast() const
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 override
Returns the number of elements in a type.
Base class for all variant types.
void notify_dead() override
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 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)
virtual const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
virtual const VARIANT_TYPE & get_type() const override
Returns the id of the variant type.
virtual variant deref_iterator(const boost::any &iter) const override
Implements the dereference functionality of variant_iterator for a value of this type.
Defines the MAKE_ENUM macro.
virtual bool less_than(variant_value_base &) const
Called to determine if this variant is less than another of the same type.
virtual const VARIANT_TYPE & get_type() const
Returns the id of the variant type.
virtual bool as_bool() const override
Returns a bool expression of the variant value.
variant build_range_variant(int limit) const
const_formula_callable_ptr get_callable() const
virtual std::string get_serialized_string() const
Returns the stored variant value in formula syntax.
variant_decimal(double value)
virtual bool less_than(variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.