LCOV - code coverage report
Current view: top level - atermpp/source - function_symbol_pool.cpp (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 53 57 93.0 %
Date: 2019-06-19 00:50:04 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Maurice Laveaux
       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             : 
      10             : #include "mcrl2/atermpp/detail/function_symbol_pool.h"
      11             : 
      12             : #include "mcrl2/utilities/logger.h"
      13             : #include "mcrl2/utilities/unused.h"
      14             : 
      15             : #include <algorithm>
      16             : 
      17             : using namespace atermpp;
      18             : using namespace atermpp::detail;
      19             : using namespace mcrl2::utilities;
      20             : 
      21         140 : function_symbol_pool::function_symbol_pool()
      22             : {
      23             :   // Initialize the default function symbols.
      24         140 :   m_as_int = create("<aterm_int>", 0);
      25         140 :   m_as_list = create("<list_constructor>", 2);
      26         140 :   m_as_empty_list = create("<empty_list>", 0);
      27             : 
      28             :   // Initialize the global copies of these default function symbols.
      29         140 :   g_as_int = m_as_int;
      30         140 :   g_as_list = m_as_list;
      31         140 :   g_as_empty_list = m_as_empty_list;
      32         140 : }
      33             : 
      34           0 : function_symbol_pool::~function_symbol_pool()
      35             : {
      36           0 :   print_performance_stats();
      37           0 : }
      38             : 
      39     1352317 : function_symbol function_symbol_pool::create(const std::string& name, const std::size_t arity, const bool check_for_registered_functions)
      40             : {
      41             : 
      42     1352317 :   auto it = m_symbol_set.find(name, arity);
      43     1352317 :   if (it != m_symbol_set.end())
      44             :   {
      45             :     if (EnableFunctionSymbolMetrics) { m_function_symbol_metrics.hit(); }
      46             : 
      47             :     // The element already exists so return it.
      48     1312198 :     return function_symbol(_function_symbol::ref(&(*it)));
      49             :   }
      50             :   else
      51             :   {
      52             :     if (EnableFunctionSymbolMetrics) { m_function_symbol_metrics.miss(); }
      53             : 
      54       40119 :     _function_symbol& symbol = *m_symbol_set.emplace(name, arity).first;
      55       40119 :     if (check_for_registered_functions)
      56             :     {
      57             :       // Check whether there is a registered prefix p such that name equal pn where n is a number.
      58             :       // In that case prevent that pn will be generated as a fresh function name.
      59       37509 :       std::size_t start_of_index = name.find_last_not_of("0123456789") + 1;
      60             : 
      61       37509 :       if (start_of_index < name.size()) // Otherwise there is no trailing number.
      62             :       {
      63        8932 :         std::string potential_number = name.substr(start_of_index); // Get the trailing string after prefix_ of function_name.
      64        8932 :         std::string prefix = name.substr(0, start_of_index);
      65        4466 :         auto prefix_it = m_prefix_to_register_function_map.find(prefix);
      66        4466 :         if (prefix_it != m_prefix_to_register_function_map.end())  // points to the prefix.
      67             :         {
      68             :           try
      69             :           {
      70           1 :             std::size_t number = std::stoul(potential_number);
      71           1 :             *prefix_it->second = std::max(*prefix_it->second, number + 1); // Set the index belonging to the found prefix to at least a safe number+1.
      72             :           }
      73           0 :           catch (std::exception&)
      74             :           {
      75             :             // Can be std::invalid_argument or an out_of_range exception.
      76             :             // In both cases nothing needs to be done, and the exception can be ignored.
      77             :           }
      78             :         }
      79             :       }
      80             :     }
      81             : 
      82       40119 :     return function_symbol(_function_symbol::ref(&symbol));
      83             :   }
      84             : }
      85             : 
      86         341 : void function_symbol_pool::destroy(_function_symbol* f)
      87             : {
      88         341 :   assert(f != nullptr);
      89         341 :   assert(f->reference_count() == 0);
      90             : 
      91             :   // Remove it from the function symbol pool.
      92         341 :   m_symbol_set.erase(*f);
      93         341 : }
      94             : 
      95        2243 : void function_symbol_pool::deregister(const std::string& prefix)
      96             : {
      97        2243 :   m_prefix_to_register_function_map.erase(prefix);
      98        2243 : }
      99             : 
     100        2243 : std::shared_ptr<std::size_t> function_symbol_pool::register_prefix(const std::string& prefix)
     101             : {
     102        2243 :   auto it = m_prefix_to_register_function_map.find(prefix);
     103        2243 :   if (it != m_prefix_to_register_function_map.end())
     104             :   {
     105         546 :     return it->second;
     106             :   }
     107             :   else
     108             :   {
     109        1697 :     std::size_t index = get_sufficiently_large_postfix_index(prefix);
     110        3394 :     std::shared_ptr<std::size_t> shared_index = std::make_shared<std::size_t>(index);
     111        1697 :     m_prefix_to_register_function_map[prefix] = shared_index;
     112        1697 :     return shared_index;
     113             :   }
     114             : }
     115             : 
     116        1697 : std::size_t function_symbol_pool::get_sufficiently_large_postfix_index(const std::string& prefix) const
     117             : {
     118        1697 :   std::size_t index = 0;
     119      720544 :   for (const auto& f : m_symbol_set)
     120             :   {
     121      718847 :     const std::string& function_name = f.name();
     122             : 
     123      718847 :     if (function_name.compare(0, prefix.size(), prefix) == 0)   // The function name starts with the prefix
     124             :     {
     125      124214 :       std::string potential_number = function_name.substr(prefix.size()); // Get the trailing string after prefix_ of function_name.
     126             :       std::size_t end_of_number;
     127             :       try
     128             :       {
     129       62107 :         std::size_t number = std::stoul(potential_number, &end_of_number);
     130       60071 :         if (end_of_number == potential_number.size()) // A proper number was read.
     131             :         {
     132       60071 :           if (number >= index)
     133             :           {
     134        2112 :             index = number + 1;
     135             :           }
     136             :         }
     137             :       }
     138        2036 :       catch (std::exception&)
     139             :       {
     140             :         // Can be std::invalid_argument or an out_of_range exception.
     141             :         // In both cases nothing needs to be done, and the exception can be ignored.
     142             :       }
     143             :     }
     144             :   }
     145             : 
     146        1697 :   return index;
     147             : }
     148             : 
     149           2 : void function_symbol_pool::print_performance_stats() const noexcept
     150             : {
     151             :   if (EnableFunctionSymbolHashtableMetrics)
     152             :   {
     153             :     m_symbol_set.print_performance_statistics();
     154             :   }
     155             : 
     156             :   if (EnableFunctionSymbolMetrics)
     157             :   {
     158             :     mCRL2log(mcrl2::log::info, "Performance") << "g_function_symbol_pool: Stores " << size() << " function symbols. create() " << m_function_symbol_metrics.message() << ".\n";
     159             :   }
     160             : 
     161             :   if (EnableReferenceCountMetrics)
     162             :   {
     163             :     mCRL2log(mcrl2::log::info, "Performance") << "g_function_symbol_pool: all reference counts changed " << _function_symbol::reference_count_changes() << " times.\n";
     164             :   }
     165         422 : }

Generated by: LCOV version 1.12