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