1 /*
2    Copyright (C) 2008 - 2018 by David White <dave@whitevine.net>
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/variant_value.hpp"
18 
19 #include <map>
20 #include <vector>
21 
22 namespace wfl
23 {
24 class formula_callable;
25 class variant_iterator;
26 
27 class variant
28 {
29 public:
30 	enum DECIMAL_VARIANT_TYPE { DECIMAL_VARIANT };
31 
32 	variant();
33 	explicit variant(int n);
34 	variant(int n, DECIMAL_VARIANT_TYPE /*type*/);
35 	variant(double n, DECIMAL_VARIANT_TYPE /*type*/);
36 	explicit variant(const std::vector<variant>& array);
37 	explicit variant(const std::string& str);
38 	explicit variant(const std::map<variant, variant>& map);
39 	variant(const variant& v) = default;
40 	variant(variant&& v) = default;
41 
42 	template<typename T>
variant(std::shared_ptr<T> callable)43 	variant(std::shared_ptr<T> callable)
44 		: value_(std::make_shared<variant_callable>(callable))
45 	{
46 		assert(value_.get());
47 	}
48 
49 	variant& operator=(const variant& v) = default;
50 	variant& operator=(variant&& v) = default;
51 
52 	variant operator[](size_t n) const;
53 	variant operator[](const variant& v) const;
54 
55 	size_t num_elements() const;
56 	bool is_empty() const;
57 
58 	variant get_member(const std::string& name) const;
59 
60 	/** Functions to test the type of the internal value. */
is_null() const61 	bool is_null()     const { return type() == VARIANT_TYPE::TYPE_NULL; }
is_int() const62 	bool is_int()      const { return type() == VARIANT_TYPE::TYPE_INT; }
is_decimal() const63 	bool is_decimal()  const { return type() == VARIANT_TYPE::TYPE_DECIMAL; }
is_callable() const64 	bool is_callable() const { return type() == VARIANT_TYPE::TYPE_CALLABLE; }
is_list() const65 	bool is_list()     const { return type() == VARIANT_TYPE::TYPE_LIST; }
is_string() const66 	bool is_string()   const { return type() == VARIANT_TYPE::TYPE_STRING; }
is_map() const67 	bool is_map()      const { return type() == VARIANT_TYPE::TYPE_MAP; }
68 
69 	int as_int() const;
70 
71 	/** Returns variant's internal representation of decimal number: ie, 1.234 is represented as 1234 */
72 	int as_decimal() const;
73 
74 	/** Returns a boolean state of the variant value. The implementation is type-dependent. */
75 	bool as_bool() const;
76 
77 	const std::vector<variant>& as_list() const;
78 	const std::map<variant, variant>& as_map() const;
79 
80 	const std::string& as_string() const;
81 
as_callable() const82 	const_formula_callable_ptr as_callable() const
83 	{
84 		must_be(VARIANT_TYPE::TYPE_CALLABLE);
85 		return value_cast<variant_callable>()->get_callable();
86 	}
87 
88 	template<typename T>
try_convert() const89 	std::shared_ptr<T> try_convert() const
90 	{
91 		if(!is_callable()) {
92 			return nullptr;
93 		}
94 
95 		return std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable()));
96 	}
97 
98 	template<typename T>
convert_to() const99 	std::shared_ptr<T> convert_to() const
100 	{
101 		std::shared_ptr<T> res = std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable()));
102 		if(!res) {
103 			throw type_error("could not convert type");
104 		}
105 
106 		return res;
107 	}
108 
109 	variant operator+(const variant&) const;
110 	variant operator-(const variant&) const;
111 	variant operator*(const variant&) const;
112 	variant operator/(const variant&) const;
113 	variant operator^(const variant&) const;
114 	variant operator%(const variant&) const;
115 	variant operator-() const;
116 
117 	bool operator==(const variant&) const;
118 	bool operator!=(const variant&) const;
119 	bool operator<(const variant&)  const;
120 	bool operator>(const variant&)  const;
121 	bool operator<=(const variant&) const;
122 	bool operator>=(const variant&) const;
123 
124 	variant list_elements_add(const variant& v) const;
125 	variant list_elements_sub(const variant& v) const;
126 	variant list_elements_mul(const variant& v) const;
127 	variant list_elements_div(const variant& v) const;
128 	variant concatenate(const variant& v) const;
129 	variant build_range(const variant& v) const;
130 
131 	bool contains(const variant& other) const;
132 
133 	variant get_keys() const;
134 	variant get_values() const;
135 
136 	variant_iterator begin() const;
137 	variant_iterator end() const;
138 
139 	std::string serialize_to_string() const;
140 	void serialize_from_string(const std::string& str);
141 
142 	std::string string_cast() const;
143 
144 	std::string to_debug_string(bool verbose = false, formula_seen_stack* seen = nullptr) const;
145 
146 	/** Gets string name of the current value type */
type_string() const147 	std::string type_string() const
148 	{
149 		return type().to_string();
150 	}
151 
152 	variant execute_variant(const variant& to_exec);
153 
154 private:
155 	template<typename T>
value_cast() const156 	std::shared_ptr<T> value_cast() const
157 	{
158 		return wfl::value_cast<T>(value_);
159 	}
160 
161 	void must_be(VARIANT_TYPE t) const;
162 
163 	void must_both_be(VARIANT_TYPE t, const variant& second) const;
164 
type() const165 	VARIANT_TYPE type() const
166 	{
167 		return value_->get_type();
168 	}
169 
170 	/**
171 	 * Variant value.
172 	 * Each of the constructors initialized this with the appropriate helper class.
173 	 */
174 	value_base_ptr value_;
175 };
176 
177 /**
178  * Iterator class for the variant.
179  *
180  * Depending on the @p type_ the @p list_iterator_ and the @p map_iterator_ are
181  * a valid iterator or singular. Since most actions on singular iterators
182  * result in Undefined Behavior care should be taken when copying the
183  * @p list_iterator_ and @p map_iterator_.
184  */
185 class variant_iterator
186 {
187 public:
188 	typedef variant value_type;
189 	typedef std::bidirectional_iterator_tag iterator_category;
190 	typedef variant& reference;
191 	typedef variant* pointer;
192 	typedef int difference_type;
193 
194 	/**
195 	 * Constructor for a no-op iterator.
196 	 */
197 	variant_iterator();
198 
199 	/**
200 	 * Constructor for a generic iterator.
201 	 *
202 	 * @pre @p iter is not singular.
203 	 *
204 	 * @param value   A pointer to a variant value representing the container.
205 	 * @param iter    An underlying iterator for the underlying container.
206 	 */
207 	variant_iterator(const variant_value_base* value, const boost::any& iter);
208 
209 	variant operator*() const;
210 	variant_iterator& operator++();
211 	variant_iterator operator++(int);
212 	variant_iterator& operator--();
213 	variant_iterator operator--(int);
214 	bool operator==(const variant_iterator& that) const;
215 	bool operator!=(const variant_iterator& that) const;
216 private:
217 	VARIANT_TYPE type_;
218 	const variant_value_base* container_;
219 	boost::any iter_;
220 };
221 
222 }
223