LCOV - code coverage report
Current view: top level - data/include/mcrl2/data/detail - data_property_map.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 111 129 86.0 %
Date: 2024-03-08 02:52:28 Functions: 70 107 65.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14