mCRL2
Loading...
Searching...
No Matches
data_property_map.h
Go to the documentation of this file.
1// Author(s): Jeroen van der Wulp and Wieger Wesselink
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9/// \file mcrl2/data/detail/data_property_map.h
10/// \brief A property map containing properties of an LPS specification.
11
12#ifndef MCRL2_DATA_DETAIL_DATA_PROPERTY_MAP_H
13#define MCRL2_DATA_DETAIL_DATA_PROPERTY_MAP_H
14
15#include "mcrl2/data/variable.h"
16
17namespace mcrl2::data::detail
18{
19
20/// \brief Base class for storing properties of mCRL2 types.
21/// Properties are (key, value) pairs stored as strings in <tt>KEY = VALUE</tt>
22/// format. The data_property_map has some predefined functions for
23/// types in the Data Library.
24/// The optional type argument is used by derived classes. The type
25/// represents the name of a derived class as per CRTP.
26template < typename Derived = void >
28{
29 protected:
30
31 /// \brief Add start/end separators for non-set container types
32 template <typename Container>
33 requires(atermpp::is_set<Container>::value)
35 {
36 return "[" + c + "]";
37 }
38
39 /// \brief Add start/end separators for set container types
40 template <typename Container>
41 requires(!atermpp::is_set<Container>::value)
43 {
44 return "{" + c + "}";
45 }
46
47 /// \brief Contains a normalized string representation of the properties.
49
50 //--------------------------------------------//
51 // print functions
52 //--------------------------------------------//
54 {
55 std::ostringstream out;
56 out << n;
57 return out.str();
58 }
59
61 {
62 return s;
63 }
64
66 {
67 return s;
68 }
69
70 std::string print(const data::variable& v) const
71 {
72 return data::pp(v) + ":" + data::pp(v.sort());
73 }
74
75 template < typename Container >
76 std::string print(const Container& v, typename atermpp::enable_if_container< Container >::type* = nullptr) const
77 {
78 std::set<std::string> elements;
79
80 for (auto i = v.begin(); i != v.end(); ++i)
81 {
82 elements.insert(static_cast< Derived const& >(*this).print(*i));
83 }
84
85 return utilities::string_join(elements, ", ");
86 }
87
88 template < typename Container >
89 std::string print(const Container& v, bool print_separators, typename atermpp::enable_if_container< Container >::type* = nullptr) const
90 {
91 return (print_separators) ? add_separators< Container >(print(v)) : print(v);
92 }
93
94 //--------------------------------------------//
95 // parse functions
96 //--------------------------------------------//
97 unsigned int parse_unsigned_int(std::string const& text) const
98 {
99 return std::stoul(utilities::remove_whitespace(text)); // Transform string to an unsigned integer.
100 }
101
103 {
104 std::vector<std::string> v = utilities::split(text, ",");
105 std::for_each(v.begin(), v.end(), utilities::trim);
106 return std::set<std::string>(v.begin(), v.end());
107 }
108
110 {
113 for (const std::string& ms: multisets)
114 {
115 std::string s = utilities::regex_replace("[{}]", "", ms);
116 std::vector<std::string> v = utilities::split(s, ",");
119 }
120 return result;
121 }
122
123 //--------------------------------------------//
124 // compare functions
125 //--------------------------------------------//
126 /// \brief Compares two integers, and returns a message if they are different.
127 /// If if they are equal the empty string is returned.
128 std::string compare(const std::string& property, unsigned int x, unsigned int y) const
129 {
130 if (x != y)
131 {
133 out << "Difference in property " << property << " detected: " << x << " versus " << y << "\n";
134 return out.str();
135 }
136 return "";
137 }
138
139 /// \brief Compares two sets and returns a string with the differences encountered.
140 /// Elements present in the first one but not in the second are printed with a '+'
141 /// in front of it, elements present in the seconde but not in the first one with a '-'
142 /// in front of it. A value x of the type T is printed using print(x), so this
143 /// operation must be defined.
144 /// If no differences are found the empty string is returned.
145 template <typename T>
146 std::string compare(const std::string& property, const std::set<T>& x, const std::set<T>& y) const
147 {
149
150 // compute elements in x but not in y
151 std::set<T> plus;
153
154 // compute elements in y but not in x
155 std::set<T> minus;
157
158 if (!plus.empty() || !minus.empty())
159 {
160 out << "Difference in property " << property << " detected:";
161 for (auto i = plus.begin(); i != plus.end(); ++i)
162 {
163 out << " +" << print(*i);
164 }
165 for (auto i = minus.begin(); i != minus.end(); ++i)
166 {
167 out << " -" << print(*i);
168 }
169 out << "\n";
170 return out.str();
171 }
172 return "";
173 }
174
175 /// \brief Compares two values x and y of a given property. This function should
176 /// be redefined in derived classes.
177 /// \return An empty string if the two values are equal, otherwise a string indicating
178 /// the differences between the two.
179 std::string compare_property(const std::string& property, const std::string& /* x */, const std::string& /* y */) const
180 {
181 return "ERROR: unknown property " + property + " encountered!";
182 }
183
184 //--------------------------------------------//
185 // miscellaneous functions
186 //--------------------------------------------//
187 /// \brief Returns the maximum length of the property names
188 unsigned int max_key_length() const
189 {
190 unsigned int result = 0;
191 for (const std::pair<const std::basic_string<char>, std::basic_string<char>>& i: m_data)
192 {
193 result = (std::max)(static_cast< std::size_t >(result), i.first.size());
194 }
195 return result;
196 }
197
198 std::string align(const std::string& s, unsigned int n) const
199 {
200 if (s.size() >= n)
201 {
202 return s;
203 }
204 return s + std::string(n - s.size(), ' ');
205 }
206
207 /// \brief Collects the names of the elements of the container.
208 /// The name of element x is retrieved by x.name().
209 template <typename Container>
211 {
213 for (auto i = v.begin(); i != v.end(); ++i)
214 {
215 result.insert(i->name());
216 }
217 return result;
218 }
219
220 /// \brief Default constructor for derived types
221 data_property_map() = default;
222
223 /// \brief Initializes the property map with text containing lines in
224 /// <tt>KEY = VALUE</tt> format.
225 void parse_text(const std::string& text)
226 {
227 for (const std::string& line: utilities::split(text, "\n"))
228 {
229 std::vector<std::string> words = utilities::split(line, "=");
230 if (words.size() == 2)
231 {
232 utilities::trim(words[0]);
233 utilities::trim(words[1]);
234 m_data[words[0]] = words[1];
235 }
236 }
237 }
238
239 public:
240 /// The strings may appear in a random order, and not all of them need to be present
241 data_property_map(const std::string& text)
242 {
243 parse_text(text);
244 }
245
246 /// \brief Returns a string representation of the properties
248 {
249 unsigned int n = max_key_length();
250 std::vector<std::string> lines;
251 for (const auto & i : m_data)
252 {
253 lines.push_back(align(i.first, n) + " = " + i.second);
254 }
255 return utilities::string_join(lines, "\n");
256 }
257
258 /// \brief Returns the stored properties
259 const std::map<std::string, std::string>& data() const
260 {
261 return m_data;
262 }
263
264 /// \brief Returns the value corresponding to key.
265 /// Throws an exception if the key is not found.
266 std::string operator[](const std::string& key) const
267 {
268 auto i = m_data.find(key);
269 if (i == m_data.end())
270 {
271 throw mcrl2::runtime_error("property_map: could not find key " + key);
272 }
273 return i->second;
274 }
275
276 /// \brief Compares this property map with another property map.
277 /// The function compare_property must be defined properly for all
278 /// available properties.
279 /// \return A string describing the differences found.
281 {
282 std::ostringstream out;
283 for (const auto & i : m_data)
284 {
285 auto j = other.data().find(i.first);
286 if (j != other.data().end())
287 {
288 out << static_cast< Derived const& >(*this).compare_property(i.first, i.second, j->second);
289 }
290 }
291 return out.str();
292 }
293};
294
295template <typename PropertyMap>
296bool compare_property_maps(const std::string& message, const PropertyMap& map1, const std::string& expected_result)
297{
298 PropertyMap map2(expected_result);
299 std::string result = map1.compare(map2);
300 if (!result.empty())
301 {
302 std::cerr << "------------------------------" << std::endl;
303 std::cerr << " Failed test " << std::endl;
304 std::cerr << "------------------------------" << std::endl;
305 std::cerr << message << std::endl;
306 std::cerr << "--- expected result ---" << std::endl;
307 std::cerr << expected_result << std::endl;
308 std::cerr << "--- found result ---" << std::endl;
309 std::cerr << map1.to_string() << std::endl;
310 std::cerr << "--- differences ---" << std::endl;
311 std::cerr << result << std::endl;
312 }
313 return result.empty();
314}
315
316} // namespace mcrl2::data::detail
317
318#endif // MCRL2_DATA_DETAIL_DATA_PROPERTY_MAP_H
Base class for storing properties of mCRL2 types. Properties are (key, value) pairs stored as strings...
data_property_map(const std::string &text)
The strings may appear in a random order, and not all of them need to be present.
unsigned int parse_unsigned_int(std::string const &text) const
const std::map< std::string, std::string > & data() const
Returns the stored properties.
std::string print(const core::identifier_string &s) const
void parse_text(const std::string &text)
Initializes the property map with text containing lines in KEY = VALUE format.
std::string print(const data::variable &v) const
std::string compare(const data_property_map &other) const
Compares this property map with another property map. The function compare_property must be defined p...
std::string operator[](const std::string &key) const
Returns the value corresponding to key. Throws an exception if the key is not found.
std::string print(std::size_t n) const
std::set< std::string > parse_set_string(std::string const &text) const
std::string to_string() const
Returns a string representation of the properties.
std::string print(const Container &v, typename atermpp::enable_if_container< Container >::type *=nullptr) const
std::string print(const Container &v, bool print_separators, typename atermpp::enable_if_container< Container >::type *=nullptr) const
bool compare_property_maps(const std::string &message, const PropertyMap &map1, const std::string &expected_result)