The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
variant_value.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 - 2025
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 "utils/ranges.hpp"
19#include <utility>
20
21#include "formula/callable.hpp"
22#include "formula/function.hpp"
24
25namespace wfl
26{
27namespace implementation
28{
29template<typename Range>
30auto make_iterator_range(const variant_value_base* val, const Range& range) -> boost::iterator_range<variant_iterator>
31{
32 return {
33 variant_iterator{val, std::cbegin(range)},
34 variant_iterator{val, std::cend(range)}
35 };
36}
37
38} // namespace implementation
39
40boost::iterator_range<variant_iterator> variant_value_base::make_iterator() const
41{
43}
44
45variant variant_value_base::deref_iterator(const utils::any& /*iter*/) const
46{
47 return variant();
48}
49
51{
52 const int len = std::abs(limit - value_) + 1;
53
54 std::vector<variant> res;
55 res.reserve(len);
56
57 for(int i = value_; res.size() != res.capacity(); value_ < limit ? ++i : --i) {
58 res.emplace_back(i);
59 }
60
61 return variant(std::move(res));
62}
63
64std::string variant_decimal::to_string_impl(const bool sign_value) const
65{
66 std::ostringstream ss;
67
68 int fractional = value_ % 1000;
69 int integer = (value_ - fractional) / 1000;
70
71 if(sign_value) {
72 // Make sure we get the sign on small negative values.
73 if(integer == 0 && value_ < 0) {
74 ss << '-';
75 }
76 }
77
78 ss << integer << ".";
79
80 fractional = std::abs(fractional);
81
82 if(fractional < 100) {
83 if(fractional < 10) {
84 ss << "00";
85 } else {
86 ss << 0;
87 }
88 }
89
90 ss << fractional;
91
92 return ss.str();
93}
94
96 : callable_(std::move(callable))
97{
98 if(callable_) {
99 callable_->subscribe_dtor(this);
100 }
101}
102
104{
105 if(callable_) {
106 callable_->unsubscribe_dtor(this);
107 }
108}
109
111{
112 if(callable_) {
113 return callable_->serialize();
114 }
115
116 return {};
117}
118
119std::string variant_callable::get_debug_string(formula_seen_stack& seen, bool verbose) const
120{
121 std::ostringstream ss;
122 ss << "{";
123
124 if(!callable_) {
125 ss << "null";
126 } else if(!utils::contains(seen, callable_)) {
127 if(!verbose) {
128 seen.push_back(callable_);
129 }
130
131 formula_input_vector v = callable_->inputs();
132 bool first = true;
133
134 for(const auto& input : v) {
135 if(!first) {
136 ss << ", ";
137 }
138
139 first = false;
140 ss << input.name << " ";
141
142 if(input.access == formula_access::read_write) {
143 ss << "(read-write) ";
144 } else if(input.access == formula_access::write_only) {
145 ss << "(writeonly) ";
146 }
147
148 ss << "-> " << callable_->query_value(input.name).to_debug_string(verbose, &seen);
149 }
150 } else {
151 ss << "...";
152 }
153
154 ss << "}";
155
156 return ss.str();
157}
158
160{
161 const variant_callable& other_ref = utils::cast_as(*this, other);
162 return callable_ ? callable_->equals(*other_ref.callable_) : callable_ == other_ref.callable_;
163}
164
166{
167 const variant_callable& other_ref = utils::cast_as(*this, other);
168 return callable_ ? callable_->less(*other_ref.callable_) : other_ref.callable_ != nullptr;
169}
170
171boost::iterator_range<variant_iterator> variant_callable::make_iterator() const
172{
173 if(!callable_) {
175 }
176
177 if(inputs.empty()) {
178 callable_->get_inputs(inputs);
179 }
180
182}
183
184variant variant_callable::deref_iterator(const utils::any& iter) const
185{
186 if(!callable_) {
187 return variant();
188 }
189
190 return callable_->query_value(utils::any_cast<const formula_input_vector::const_iterator&>(iter)->name);
191}
192
193void variant_callable::iterator_inc(utils::any& iter) const
194{
195 ++utils::any_cast<formula_input_vector::const_iterator&>(iter);
196}
197
198void variant_callable::iterator_dec(utils::any& iter) const
199{
200 --utils::any_cast<formula_input_vector::const_iterator&>(iter);
201}
202
204{
205 std::ostringstream ss;
206 ss << "'";
207
208 for(const auto& c : string_) {
209 switch(c) {
210 case '\'':
211 ss << "[']";
212 break;
213 case '[':
214 ss << "[(]";
215 break;
216 case ']':
217 ss << "[)]";
218 break;
219 default:
220 ss << c;
221 break;
222 }
223 }
224
225 ss << "'";
226
227 return ss.str();
228}
229
230namespace implementation
231{
232namespace detail
233{
234template<typename Func>
235std::string serialize_value(const Func& op, const variant& value)
236{
237 return std::invoke(op, value);
238}
239
240template<typename Func>
241std::string serialize_value(const Func& op, const std::pair<variant, variant>& value)
242{
243 std::ostringstream ss;
244
245 ss << std::invoke(op, value.first);
246 ss << "->";
247 ss << std::invoke(op, value.second);
248
249 return ss.str();
250}
251
252template<typename Range, typename Func>
253auto make_serialized_range(const Range& range, const Func& op)
254{
255 return range | utils::views::transform([&op](auto&& value) { return serialize_value(op, value); });
256}
257
258/** WFL empty list literal */
259static std::string serialize_empty(const std::vector<variant>&)
260{
261 return "[]";
262}
263
264/** WFL empty map literal */
265static std::string serialize_empty(const std::map<variant, variant>&)
266{
267 return "[->]";
268}
269
270} // namespace detail
271
272template<typename Range, typename Func>
273std::string to_string(const Range& range, const Func& op)
274{
275 return utils::join(detail::make_serialized_range(range, op), ", ");
276}
277
278template<typename Range, typename Func>
279std::string as_literal(const Range& range, const Func& op)
280{
281 if(range.empty()) {
282 return detail::serialize_empty(range);
283 }
284
285 std::ostringstream ss;
286 ss << "[" << to_string(range, op) << "]";
287 return ss.str();
288}
289
290} // namespace implementation
291
292template<typename T>
294{
296}
297
298template<typename T>
303
304template<typename T>
305std::string variant_container<T>::get_debug_string(formula_seen_stack& seen, bool verbose) const
306{
307 return implementation::as_literal(container_,
308 [&seen, verbose](const variant& v) { return v.to_debug_string(verbose, &seen); });
309}
310
311template<typename T>
312boost::iterator_range<variant_iterator> variant_container<T>::make_iterator() const
313{
314 return implementation::make_iterator_range(this, container_);
315}
316
317template<typename T>
318void variant_container<T>::iterator_inc(utils::any& iter) const
319{
320 ++as_container_iterator(iter);
321}
322
323template<typename T>
324void variant_container<T>::iterator_dec(utils::any& iter) const
325{
326 --as_container_iterator(iter);
327}
328
329template<typename T>
330bool variant_container<T>::iterator_equals(const utils::any& first, const utils::any& second) const
331{
332 return as_container_iterator(first) == as_container_iterator(second);
333}
334
335// Force compilation of the following template instantiations
338
339variant variant_list::deref_iterator(const utils::any& iter) const
340{
341 return *as_container_iterator(iter);
342}
343
344variant variant_map::deref_iterator(const utils::any& iter) const
345{
346 const auto& [key, value] = *as_container_iterator(iter);
347 return make_callable<key_value_pair>(key, value);
348}
349
350} // namespace wfl
virtual bool equals(const 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
Required by variant_value_base.
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(const variant_value_base &other) const override
Called to determine if this variant is less than another of the same type.
Generalized interface for container variants.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
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.
static const_iterator & as_container_iterator(utils::any &iter)
Casts opaque iter to a mutable const_iterator reference.
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.
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
Required by variant_value_base.
variant build_range_variant(int limit) const
Iterator class for the variant.
Definition variant.hpp:160
virtual variant deref_iterator(const utils::any &) const override
Required by variant_value_base.
virtual variant deref_iterator(const utils::any &) const override
Required by variant_value_base.
virtual std::string get_serialized_string() const override
Returns the stored variant value in formula syntax.
std::string string_
Required by variant_value_base.
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.
std::string serialize_to_string() const
Definition variant.cpp:666
std::string string_cast() const
Definition variant.cpp:681
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition variant.cpp:686
Contains the implementation details for lexical_cast and shouldn't be used directly.
STL namespace.
T cend(const std::pair< T, T > &p)
T cbegin(const std::pair< T, T > &p)
constexpr auto transform
Definition ranges.hpp:45
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
std::string join(const Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
To & cast_as(To &, From &value)
static std::string serialize_empty(const std::vector< variant > &)
WFL empty list literal.
auto make_serialized_range(const Range &range, const Func &op)
std::string serialize_value(const Func &op, const variant &value)
auto make_iterator_range(const variant_value_base *val, const Range &range) -> boost::iterator_range< variant_iterator >
std::string to_string(const Range &range, const Func &op)
std::string as_literal(const Range &range, const Func &op)
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
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
#define i
#define c