LCOV - code coverage report
Current view: top level - atermpp/include/mcrl2/atermpp/detail - aterm_pool_storage_implementation.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 141 143 98.6 %
Date: 2024-04-26 03:18:02 Functions: 3263 11724 27.8 %
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             : #ifndef MCRL2_ATERMPP_ATERM_POOL_STORAGE_IMPLEMENTION_H
      11             : #define MCRL2_ATERMPP_ATERM_POOL_STORAGE_IMPLEMENTION_H
      12             : #pragma once
      13             : 
      14             : #include <type_traits>
      15             : #include <cstring>
      16             : #include "mcrl2/utilities/stack_array.h"
      17             : #include "mcrl2/atermpp/detail/aterm_pool.h"
      18             : 
      19             : 
      20             : 
      21             : namespace atermpp
      22             : {
      23             : namespace detail
      24             : {
      25             : 
      26             : /// \brief Construct the proxy where its arguments are given by applying the converter
      27             : ///        to each element in the iterator.
      28             : template<std::size_t N,
      29             :          typename InputIterator,
      30             :          typename TermConverter,
      31             :          typename std::enable_if<mcrl2::utilities::is_iterator<InputIterator>::value, void>::type* = nullptr,
      32             :          typename std::enable_if<std::is_convertible<
      33             :                                     typename std::invoke_result<TermConverter, typename InputIterator::value_type>::type,
      34             :                                     aterm>::value, void>::type* = nullptr>
      35      791082 : inline std::array<unprotected_aterm, N> construct_arguments(InputIterator it, InputIterator end, TermConverter converter)
      36             : {
      37             :   // The end is only used for debugging to ensure that the arity and std::distance(it, end) match.
      38      791082 :   mcrl2::utilities::mcrl2_unused(end);
      39             :  
      40             :   // Copy the arguments into this array.
      41      791082 :   std::array<unprotected_aterm, N> arguments;
      42     3070116 :   for (size_t i = 0; i < N; ++i)
      43             :   {
      44     2279034 :     assert(it != end);
      45     2279034 :     arguments[i] = converter(*it);
      46             :  
      47     2279034 :     ++it;
      48             :   }
      49      791082 :   assert(it == end);
      50             :  
      51      791082 :   return arguments;
      52             : }
      53             : 
      54             : /// \brief Construct the proxy where its arguments are given by applying the converter
      55             : ///        to each element in the iterator.
      56             : template<std::size_t N,
      57             :          typename InputIterator,
      58             :          typename TermConverter,
      59             :          typename std::enable_if<mcrl2::utilities::is_iterator<InputIterator>::value, void>::type* = nullptr,
      60             :          typename std::enable_if<std::is_same<
      61             :                                     typename std::invoke_result<TermConverter,
      62             :                                                                 typename InputIterator::value_type&,
      63             :                                                                 typename InputIterator::value_type>::type,
      64             :                                     void>::value, void>::type* = nullptr>
      65     9273255 : inline std::array<unprotected_aterm, N> construct_arguments(InputIterator it, InputIterator end, TermConverter converter)
      66             : {
      67             :   // The end is only used for debugging to ensure that the arity and std::distance(it, end) match.
      68     9273255 :   mcrl2::utilities::mcrl2_unused(end);
      69             :  
      70             :   // Copy the arguments into this array. Doesn't change any reference count, because they are unprotected terms.
      71     9273255 :   std::array<unprotected_aterm, N> arguments;
      72    34837074 :   for (size_t i = 0; i < N; ++i)
      73             :   {
      74    25563819 :     assert(it != end);
      75    25563819 :     typename InputIterator::value_type& t= *reinterpret_cast<typename InputIterator::value_type*>(&arguments[i]);
      76    25563819 :     converter(t, *it);
      77    25563819 :     ++it;
      78             :   }
      79     9273255 :   assert(it == end);
      80             :  
      81     9273255 :   return arguments;
      82             : }
      83             : 
      84     6273533 : void mark_term(const _aterm& root, std::stack<std::reference_wrapper<_aterm>>& todo)
      85             : {
      86     6273533 :   if (!root.is_marked())
      87             :   {
      88             :     // Do not use the stack, because this might run out of stack memory for large lists.
      89       10587 :     todo.push(const_cast<_aterm&>(root));
      90             : 
      91             :     // Mark the term depth-first to reduce the maximum todo size required.
      92       40005 :     while (!todo.empty())
      93             :     {
      94       29418 :       _aterm& term = todo.top();
      95       29418 :       todo.pop();
      96             : 
      97             :       // Each term should be marked.
      98       29418 :       term.mark();
      99             :       // Determine the arity of the function application.
     100       29418 :       const std::size_t arity = term.function().arity();
     101       29418 :       _term_appl& term_appl = static_cast<_term_appl&>(term);
     102             : 
     103       91937 :       for (std::size_t i = 0; i < arity; ++i)
     104             :       {
     105             :         // Marks all arguments that are not already (marked as) reachable, because the current
     106             :         // term is reachable and as such its arguments are reachable as well.
     107       62519 :         _aterm& argument = *detail::address(term_appl.arg(i));
     108       62519 :         if (!argument.is_marked())
     109             :         {
     110       18831 :           argument.mark();
     111             : 
     112             :           // Add the argument to be explored as well.
     113       18831 :           todo.push(argument);
     114             :         }
     115             :       }
     116             : 
     117             :     }
     118             :   }
     119     6273533 : }
     120             : 
     121             : #define ATERM_POOL_STORAGE_TEMPLATES template<typename Element, typename Hash, typename Equals, std::size_t N>
     122             : #define ATERM_POOL_STORAGE aterm_pool_storage<Element, Hash, Equals, N>
     123             : 
     124             : ATERM_POOL_STORAGE_TEMPLATES
     125        1430 : ATERM_POOL_STORAGE::aterm_pool_storage(aterm_pool& pool) :
     126        1430 :   m_pool(pool),
     127        1430 :   m_term_set(1 << 14)
     128        1430 : {}
     129             : 
     130             : ATERM_POOL_STORAGE_TEMPLATES
     131           1 : void ATERM_POOL_STORAGE::add_deletion_hook(function_symbol sym, term_callback callback)
     132             : {
     133           1 :   for (const auto& hook : m_deletion_hooks)
     134             :   {
     135           0 :     mcrl2::utilities::mcrl2_unused(hook);
     136           0 :     assert(hook.first != sym);
     137             :   }
     138           1 :   m_deletion_hooks.emplace_back(sym, callback);
     139           1 : }
     140             : 
     141             : ATERM_POOL_STORAGE_TEMPLATES
     142    19731852 : bool ATERM_POOL_STORAGE::create_int(aterm& term, std::size_t value)
     143             : {
     144    19731852 :   return emplace(term, value);
     145             : }
     146             : 
     147             : ATERM_POOL_STORAGE_TEMPLATES
     148     1188023 : bool ATERM_POOL_STORAGE::create_term(aterm& term, const function_symbol& symbol)
     149             : {
     150     1188023 :   assert(symbol.arity() == 0);
     151     1188023 :   return emplace(term, symbol);
     152             : }
     153             : 
     154             : template <std::size_t N>
     155    46562858 : void store_in_argument_array_(std::size_t , std::array<unprotected_aterm, N>& )
     156    46562858 : {}
     157             : 
     158             : template <std::size_t N, class FUNCTION_OR_TERM_TYPE, typename... Args>
     159    98625555 : void store_in_argument_array_(std::size_t i, 
     160             :                               std::array<unprotected_aterm, N>& argument_array, 
     161             :                               FUNCTION_OR_TERM_TYPE& function_or_term, 
     162             :                               const Args&... args)
     163             : {
     164             :   if constexpr (std::is_convertible<FUNCTION_OR_TERM_TYPE,atermpp::aterm>::value)
     165             :   {
     166    39337060 :     argument_array[i]=function_or_term;
     167             :   }
     168             :   // check whether the function_or_term invoked on an empty argument yields an aterm.
     169             :   else if constexpr (mcrl2::utilities::is_applicable< FUNCTION_OR_TERM_TYPE, void>::value)
     170             :   {
     171             :     argument_array[i]=function_or_term();
     172             :   }
     173             :   // Otherwise function_or_term is supposed to  have type void(term& result), putting the term in result. 
     174             :   else
     175             :   {
     176             :     // function_or_term(static_cast<Term&>(argument_array[i]));
     177             : 
     178             :     typedef mcrl2::utilities::function_traits<decltype(&FUNCTION_OR_TERM_TYPE::operator())> traits;
     179    59288495 :     function_or_term(static_cast<typename traits::template arg<0>::type&>(argument_array[i]));
     180             :   }
     181    98625553 :   store_in_argument_array_(i+1, argument_array, args...);
     182    98625551 : }
     183             : 
     184             : template <std::size_t N, typename... Args>
     185    46562860 : void store_in_argument_array(std::array<unprotected_aterm, N>& argument_array,
     186             :                              const Args&... args)
     187             : {
     188    46562860 :   store_in_argument_array_(0, argument_array, args...);
     189    46562858 : }
     190             : 
     191             : 
     192             : 
     193             : ATERM_POOL_STORAGE_TEMPLATES
     194             : template<class ...Terms>
     195   147845387 : bool ATERM_POOL_STORAGE::create_appl(aterm& term, const function_symbol& symbol, const Terms&... arguments)
     196             : {
     197   147845387 :   assert(symbol.arity() == sizeof...(arguments));
     198             :   if constexpr (detail::are_terms<Terms...>::value)
     199             :   {
     200   121003566 :     return emplace(term, symbol, arguments...);
     201             :   }
     202             :   else 
     203             :   {
     204    26841821 :     std::array<unprotected_aterm, N> argument_array;
     205             :     
     206             :     // Evaluate the functions or terms and put the result in "argument_array".
     207    26841821 :     store_in_argument_array(argument_array, arguments...);
     208             : 
     209    26841819 :     return emplace(term, symbol, argument_array.begin(), argument_array.end());
     210             :   }
     211             : }
     212             : 
     213             : ATERM_POOL_STORAGE_TEMPLATES
     214             : template<typename ForwardIterator>
     215     1011056 : bool ATERM_POOL_STORAGE::create_appl_iterator(aterm& term,
     216             :                                         const function_symbol& symbol,
     217             :                                         ForwardIterator begin,
     218             :                                         ForwardIterator end)
     219             : {
     220     1011056 :   return emplace(term, symbol, begin, end);
     221             : }
     222             : 
     223             : ATERM_POOL_STORAGE_TEMPLATES
     224             : template<typename InputIterator, typename TermConverter>
     225    10064337 : bool ATERM_POOL_STORAGE::create_appl_iterator(aterm& term,
     226             :                                         const function_symbol& symbol,
     227             :                                         TermConverter converter,
     228             :                                         InputIterator begin,
     229             :                                         InputIterator end)
     230             : {
     231    10064337 :   std::array<unprotected_aterm, N> arguments = construct_arguments<N>(begin, end, converter);
     232    20128674 :   return emplace(term, symbol, arguments);
     233             : }
     234             : 
     235             : ATERM_POOL_STORAGE_TEMPLATES
     236             : template<typename ForwardIterator>
     237         484 : bool ATERM_POOL_STORAGE::create_appl_dynamic(aterm& term,
     238             :                                         const function_symbol& symbol,
     239             :                                         ForwardIterator begin,
     240             :                                         ForwardIterator end)
     241             : {
     242         484 :   return emplace(term, symbol, begin, end);
     243             : }
     244             : 
     245             : ATERM_POOL_STORAGE_TEMPLATES
     246             : template<typename InputIterator,
     247             :          typename TermConverter,
     248             :          typename std::enable_if<std::is_convertible<
     249             :                                     typename std::invoke_result<TermConverter, typename InputIterator::value_type>::type,
     250             :                                     aterm>::value, void>::type*>
     251          29 : bool ATERM_POOL_STORAGE::create_appl_dynamic(aterm& term,
     252             :                                         const function_symbol& symbol,
     253             :                                         TermConverter converter,
     254             :                                         InputIterator it,
     255             :                                         InputIterator end)
     256             : {
     257             :   // The end is only used for debugging to ensure that the arity and std::distance(it, end) match.
     258          29 :   mcrl2::utilities::mcrl2_unused(end);
     259             :  
     260          29 :   MCRL2_DECLARE_STACK_ARRAY(arguments, unprotected_aterm, symbol.arity());
     261         493 :   for (std::size_t i = 0; i < symbol.arity(); ++i)
     262             :   {
     263         464 :     assert(it != end);
     264         464 :     arguments[i] = converter(*it);
     265         464 :     ++it;
     266             :   }
     267          29 :   assert(it == end);
     268             :  
     269             :   // Find or create a new term and return it.
     270          58 :   return emplace(term, symbol, arguments.begin(), arguments.end());
     271          29 : }
     272             :  
     273             : ATERM_POOL_STORAGE_TEMPLATES
     274             : template<typename InputIterator,
     275             :          typename TermConverter,
     276             :          typename std::enable_if<std::is_same<
     277             :                                     typename std::invoke_result<TermConverter,
     278             :                                                                 typename InputIterator::value_type&,
     279             :                                                                 typename InputIterator::value_type>::type,
     280             :                                     void>::value, void>::type*>
     281        1138 : bool ATERM_POOL_STORAGE::create_appl_dynamic(aterm& term,
     282             :                                              const function_symbol& symbol,
     283             :                                              TermConverter converter,
     284             :                                              InputIterator it,
     285             :                                              InputIterator end)
     286             : {
     287             :   // The end is only used for debugging to ensure that the arity and std::distance(it, end) match.
     288        1138 :   mcrl2::utilities::mcrl2_unused(end);
     289             :  
     290        1138 :   MCRL2_DECLARE_STACK_ARRAY(arguments, unprotected_aterm, symbol.arity());
     291       16486 :   for (std::size_t i = 0; i < symbol.arity(); ++i)
     292             :   {
     293       15348 :     assert(it != end);
     294             :     // The construction below is possible as with protection sets the new term simply
     295             :     // overwrites the object at arguments[i].
     296       15348 :     converter(reinterpret_cast<typename InputIterator::value_type&>(arguments[i]), *it);
     297       15348 :     ++it;
     298             :   }
     299        1138 :   assert(it == end);
     300             :  
     301             :   // Find or create a new term and return it.
     302        2276 :   return emplace(term, symbol, arguments.begin(), arguments.end());
     303        1138 : }
     304             :  
     305             : 
     306             : ATERM_POOL_STORAGE_TEMPLATES
     307       10150 : void ATERM_POOL_STORAGE::print_performance_stats(const char* identifier) const
     308             : {
     309             :   if (EnableHashtableMetrics)
     310             :   {
     311             :     mCRL2log(mcrl2::log::info) << "g_term_pool(" << identifier << ") hashtable:\n";
     312             :     print_performance_statistics(m_term_set);
     313             :   }
     314             : 
     315             :   if (EnableGarbageCollectionMetrics && m_erasedBlocks > 0)
     316             :   {
     317             :     mCRL2log(mcrl2::log::info) << "g_term_pool(" << identifier << "): Consolidate removed " << m_erasedBlocks << " blocks.\n";
     318             :   }
     319             : 
     320             :   if (EnableCreationMetrics)
     321             :   {
     322             :     mCRL2log(mcrl2::log::info) << "g_term_pool(" << identifier << "): emplace() " << m_term_metric.message() << ".\n";
     323             :   }
     324       10150 : }
     325             : 
     326             : ATERM_POOL_STORAGE_TEMPLATES
     327       10150 : void ATERM_POOL_STORAGE::sweep()
     328             : {
     329             :   // Iterate over all terms and removes the ones that are marked.
     330      256700 :   for (auto it = m_term_set.begin(); it != m_term_set.end(); )
     331             :   {
     332      246550 :     const Element& term = *it;
     333             : 
     334      246550 :     if (!term.is_marked())
     335             :     {
     336             :       // For constants, i.e., arity zero and integer terms we do not mark, but use their reachability directly. 
     337      217132 :       it = destroy(it);
     338             :     }
     339             :     else
     340             :     {
     341             :       // Reset terms that have been marked.
     342       29418 :       term.unmark();
     343       29418 :       ++it;
     344             :     }
     345             :   }
     346             : 
     347             :   if constexpr (EnableBlockAllocator)
     348             :   {
     349             :     // Clean up unnecessary blocks.
     350       10150 :     m_erasedBlocks = m_term_set.get_allocator().consolidate();
     351             :   }
     352       10150 : }
     353             : 
     354             : ATERM_POOL_STORAGE_TEMPLATES
     355         380 : void ATERM_POOL_STORAGE::resize_if_needed()
     356             : {
     357         380 :   m_term_set.rehash_if_needed();
     358         380 : }
     359             : 
     360             : /// PRIVATE FUNCTIONS
     361             : 
     362             : ATERM_POOL_STORAGE_TEMPLATES
     363      217132 : void ATERM_POOL_STORAGE::call_deletion_hook(unprotected_aterm term)
     364             : {
     365      217133 :   for (const auto& [symbol, callback] : m_deletion_hooks)
     366             :   {
     367           1 :     if (symbol == term.function())
     368             :     {
     369           1 :       assert(verify_term(*detail::address(term)));
     370           1 :       callback(static_cast<const aterm&>(term));
     371             :     }
     372             :   }
     373      217132 : }
     374             : 
     375             : 
     376             : ATERM_POOL_STORAGE_TEMPLATES
     377        9135 : bool ATERM_POOL_STORAGE::verify_mark()
     378             : {
     379             :   // Check for consistency that if a term is marked then its arguments are as well.
     380      261962 :   for (const Element& term : m_term_set)
     381             :   {
     382      243692 :     if (term.is_marked() && term.function().arity() > 0)
     383             :     {
     384       23083 :        const _term_appl& ta = static_cast<_term_appl&>(const_cast<Element&>(term));
     385       85602 :        for (std::size_t i = 0; i < ta.function().arity(); ++i)
     386             :        {
     387       62519 :          assert(detail::address(ta.arg(i))->is_marked());
     388             :        }
     389             :     }
     390             :   }
     391        9135 :   return true;
     392             : }
     393             : 
     394             : ATERM_POOL_STORAGE_TEMPLATES
     395       10150 : bool ATERM_POOL_STORAGE::verify_sweep()
     396             : {
     397             :   // Check that no argument was removed from a reachable term.
     398       49718 :   for (const Element& term : m_term_set)
     399             :   {
     400             :     (void)term;
     401       29418 :     assert(verify_term(term));
     402             :   }
     403       10150 :   return true;
     404             : }
     405             : 
     406             : /// Private definitions
     407             : 
     408             : ATERM_POOL_STORAGE_TEMPLATES
     409      217132 : typename ATERM_POOL_STORAGE::iterator ATERM_POOL_STORAGE::destroy(iterator it)
     410             : {
     411             :   // Store the term temporarily to be able to deallocate it after removing it from the set.
     412      217132 :   const Element& term = *it;
     413             : 
     414             :   // Trigger the deletion hook before the term is actually destroyed.
     415      217132 :   call_deletion_hook(&term);
     416             : 
     417             :   // Remove them from the hash table, will also destroy terms with fixed arity.
     418      217132 :   return m_term_set.erase(it);
     419             : }
     420             : 
     421             : ATERM_POOL_STORAGE_TEMPLATES
     422             : template<typename ...Args>
     423   179842304 : bool ATERM_POOL_STORAGE::emplace(aterm& term, Args&&... args)
     424             : {
     425   179842304 :   auto [it, added] = m_term_set.emplace(std::forward<Args>(args)...);
     426   179842304 :   new (&term) atermpp::unprotected_aterm(&*it); 
     427             : 
     428   179842304 :   if (added)
     429             :   {
     430             :     if (EnableCreationMetrics) { m_term_metric.miss(); }
     431             :   }
     432             :   else if (EnableCreationMetrics)
     433             :   {
     434             :     // A term was already found in the set.
     435             :     m_term_metric.hit();
     436             :   }
     437             : 
     438   179842304 :   return added;
     439             : }
     440             : 
     441             : ATERM_POOL_STORAGE_TEMPLATES
     442             : constexpr bool ATERM_POOL_STORAGE::is_dynamic_storage() const
     443             : {
     444             :   return N == DynamicNumberOfArguments;
     445             : }
     446             : 
     447             : ATERM_POOL_STORAGE_TEMPLATES
     448             : template<std::size_t Arity>
     449     1486466 : bool ATERM_POOL_STORAGE::verify_term(const _aterm& term)
     450             : {
     451             :   // Check that a valid function symbol was used and that its arity belongs to this storage.
     452     1486466 :   assert(term.function().defined());
     453       29419 :   assert(Arity == DynamicNumberOfArguments ? true : term.function().arity() == N);
     454             : 
     455             :   // Check that all of its arguments are defined.
     456     1486466 :   if (term.function().arity() > 0)
     457             :   {
     458      803595 :     const _term_appl& ta = static_cast<const _term_appl&>(term);
     459      803595 :     assert(ta.function().defined());
     460     2260642 :     for (std::size_t i = 0; i < ta.function().arity(); ++i)
     461             :     {
     462     1457047 :       assert(ta.arg(i).defined());
     463     1457047 :       assert(&ta!=detail::address(ta.arg(i)));
     464     1457047 :       verify_term<DynamicNumberOfArguments>(*detail::address(ta.arg(i)));
     465             :     }
     466             :   }
     467     1486466 :   return true;
     468             : }
     469             : 
     470             : #undef ATERM_POOL_STORAGE_TEMPLATES
     471             : #undef ATERM_POOL_STORAGE
     472             : 
     473             : } // namespace detail
     474             : } // namespace atermpp
     475             : 
     476             : #endif

Generated by: LCOV version 1.14