The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
config_filters.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 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 <algorithm>
16#include <set>
17#include <vector>
18
20
21#include "serialization/string_utils.hpp" // for utils::split
22#include "utils/general.hpp"
23#include "utils/math.hpp" // for in_ranges
24
25bool utils::config_filters::bool_matches_if_present(const config& filter, const config& cfg, const std::string& attribute, bool def)
26{
27 if(!filter.has_attribute(attribute)) {
28 return true;
29 }
30
31 return filter[attribute].to_bool() == cfg[attribute].to_bool(def);
32}
33
35 const config& filter, const config& cfg, const std::string& attribute, const std::string& def)
36{
37 if(!filter.has_attribute(attribute)) {
38 return true;
39 }
40
41 return utils::contains(utils::split(filter[attribute]), cfg[attribute].str(def));
42}
43
44bool utils::config_filters::set_includes_if_present(const config& filter, const config& cfg, const std::string& attribute)
45{
46 if(!filter.has_attribute(attribute)) {
47 return true;
48 }
49 //This function compares two sets in such a way that if
50 //no member of the ability set matches the filter element,
51 //it returns a false value but if the attribute is not present in ability
52 //then there is no point in wasting resources on building the set from the filter and the value is returned immediately.
53 if(!cfg.has_attribute(attribute)) {
54 return false;
55 }
56
57 const std::set<std::string> filter_attribute = utils::split_set(filter[attribute].str());
58 const std::set<std::string> cfg_attribute = utils::split_set(cfg[attribute].str());
59 for(const std::string& fil_at : filter_attribute) {
60 if (cfg_attribute.count(fil_at) == 0){
61 return false;
62 }
63 }
64 return true;
65}
66
67bool utils::config_filters::int_matches_if_present(const config& filter, const config& cfg, const std::string& attribute, utils::optional<int> def)
68{
69 if(!filter.has_attribute(attribute)) {
70 return true;
71 }
72 //This function can be called in cases where no default value is supposed to exist,
73 //if this is the case and the checked attribute does not exist then no value can match.
74 if(!cfg.has_attribute(attribute) && !def) {
75 return false;
76 }
77
78 //if filter attribute is "default" check if cfg attribute equals to def.
79 if(filter[attribute] == "default" && def){
80 return (cfg[attribute].to_int(*def) == *def);
81 }
82 int value_def = def ? (*def) : 0;
83 return in_ranges<int>(cfg[attribute].to_int(value_def), utils::parse_ranges_int(filter[attribute].str()));
84}
85
87 const config& filter, const config& cfg, const std::string& attribute, const std::string& opposite, utils::optional<int> def)
88{
89 if(int_matches_if_present(filter, cfg, attribute, def)) {
90 return true;
91 }
92
93 // Check if cfg[opposite].empty() and have optional def.
94 // If def don't exist return false.
95 if(!cfg.has_attribute(attribute)) {
96 if(!cfg.has_attribute(opposite) && !def) {
97 return false;
98 }
99 //if filter attribute is "default" check if cfg attribute equals to def.
100 if(filter[attribute] == "default" && def){
101 return (cfg[attribute].to_int(*def) == *def);
102 }
103 int value_def = def ? (*def) : 0;
104 return in_ranges<int>(-cfg[opposite].to_int(value_def), utils::parse_ranges_int(filter[attribute].str()));
105 }
106
107 return false;
108}
109
110bool utils::config_filters::double_matches_if_present(const config& filter, const config& cfg, const std::string& attribute, utils::optional<double> def)
111{
112 if(!filter.has_attribute(attribute)) {
113 return true;
114 }
115 //there is no attribute returning a decimal value using which has a default value but the variable exists in case this changes,
116 //otherwise in case the attribute is missing from the ability no value can match.
117 if(!cfg.has_attribute(attribute) && !def) {
118 return false;
119 }
120
121 //if filter attribute is "default" check if cfg attribute equals to def.
122 if(filter[attribute] == "default" && def){
123 return (cfg[attribute].to_int(*def) == *def);
124 }
125 double value_def = def ? (*def) : 1;
126 return in_ranges<double>(cfg[attribute].to_double(value_def), utils::parse_ranges_real(filter[attribute].str()));
127}
128
129bool utils::config_filters::bool_or_empty(const config& filter, const config& cfg, const std::string& attribute)
130{
131 //Here, no numeric value by default since it returns a Boolean value,
132 //except that this function is called in cases where a third value exists in addition to true/false.
133 //If the attribute is not present in the ability this induces a different behavior than if it takes a true or false value
134 //and this presence must be verified before checking its value.
135 if(!filter.has_attribute(attribute)) {
136 return true;
137 }
138
139 std::set<std::string> filter_attribute = utils::split_set(filter[attribute].str());
140 bool is_matches = false;
141 if(cfg.has_attribute(attribute)){
142 if(filter_attribute.count("yes") != 0 || filter_attribute.count("true") != 0){
143 is_matches = cfg[attribute].to_bool();
144 }
145 if(!is_matches && (filter_attribute.count("no") != 0 || filter_attribute.count("false") != 0)){
146 is_matches = !cfg[attribute].to_bool();
147 }
148 } else {
149 if(filter_attribute.count("none") != 0){
150 is_matches = true;
151 }
152 }
153 return is_matches;
154}
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
bool has_attribute(std::string_view key) const
Definition config.cpp:157
const config * cfg
General math utility functions.
bool int_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, utils::optional< int > def=utils::nullopt)
bool set_includes_if_present(const config &filter, const config &cfg, const std::string &attribute)
filter[attribute] and cfg[attribute] are assumed to be comma-separated lists.
bool double_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, utils::optional< double > def=utils::nullopt)
Checks whether the filter matches the value of cfg[attribute].
bool int_matches_if_present_or_negative(const config &filter, const config &cfg, const std::string &attribute, const std::string &opposite, utils::optional< int > def=utils::nullopt)
Supports filters using "add" and "sub" attributes, for example a filter add=1 matching a cfg containi...
bool string_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, const std::string &def)
bool bool_or_empty(const config &filter, const config &cfg, const std::string &attribute)
bool bool_matches_if_present(const config &filter, const config &cfg, const std::string &attribute, bool def)
Checks whether the filter matches the value of cfg[attribute].
std::set< std::string > split_set(std::string_view s, char sep, const int flags)
std::vector< std::pair< int, int > > parse_ranges_int(const std::string &str)
Handles a comma-separated list of inputs to parse_range.
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
std::vector< std::pair< double, double > > parse_ranges_real(const std::string &str)
std::vector< std::string > split(const config_attribute_value &val)