LCOV - code coverage report
Current view: top level - atermpp/include/mcrl2/atermpp - aterm.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 73 73 100.0 %
Date: 2020-09-16 00:45:56 Functions: 234 263 89.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Jan Friso Groote, Maurice Laveaux, 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             : 
      10             : #ifndef MCRL2_ATERMPP_ATERM_H
      11             : #define MCRL2_ATERMPP_ATERM_H
      12             : 
      13             : #include "mcrl2/atermpp/detail/aterm.h"
      14             : #include "mcrl2/atermpp/type_traits.h"
      15             : 
      16             : /// \brief The main namespace for the aterm++ library.
      17             : namespace atermpp
      18             : {
      19             : 
      20             : typedef void(*term_callback)(const aterm&);
      21             : 
      22             : extern void add_creation_hook(const function_symbol&, term_callback);
      23             : extern void add_deletion_hook(const function_symbol&, term_callback);
      24             : 
      25             : /// \brief An unprotected term does not change the reference count of the
      26             : ///        shared term when it is copied or moved.
      27             : class unprotected_aterm
      28             : {
      29             :   friend detail::_aterm* detail::address(const unprotected_aterm& t);
      30             : 
      31             : protected:
      32             :   const detail::_aterm* m_term;
      33             : 
      34             : public:
      35             : 
      36             :   /// \brief Default constuctor.
      37   201367397 :   unprotected_aterm() noexcept
      38   201367397 :    : m_term(nullptr)
      39   201367397 :   {}
      40             : 
      41             :   /// \brief Constructor.
      42             :   /// \param term The term from which the new term is constructed.
      43   637753825 :   unprotected_aterm(const detail::_aterm* term) noexcept
      44   637753825 :    : m_term(term)
      45   637753825 :   {}
      46             : 
      47             :   /// \brief Dynamic check whether the term is an aterm_appl.
      48             :   /// \return True iff this term is an term_appl.
      49             :   /// \details This function has constant complexity.
      50             :   ///          It is defined as !type_is_int() && !type_is_list().
      51  2347725119 :   bool type_is_appl() const noexcept
      52             :   {
      53  2347725119 :     return !type_is_int() && !type_is_list();
      54             :   }
      55             : 
      56             :   /// \brief Dynamic check whether the term is an aterm_int.
      57             :   /// \return True iff this term has internal structure of an aterm_int.
      58             :   /// \details This function has constant complexity.
      59  2546399389 :   bool type_is_int() const noexcept
      60             :   {
      61  2546399389 :     const function_symbol& f=m_term->function();
      62  2546399389 :     return f == detail::g_as_int;
      63             :   }
      64             : 
      65             :   /// \brief Dynamic check whether the term is an aterm_list.
      66             :   /// \returns True iff this term has the structure of an term_list
      67             :   /// \details This function has constant complexity.
      68  2556015110 :   bool type_is_list() const noexcept
      69             :   {
      70  2556015110 :     const function_symbol& f=m_term->function();
      71  2556015110 :     return f == detail::g_as_list || f == detail::g_as_empty_list;
      72             :   }
      73             : 
      74             :   /// \brief Comparison operator.
      75             :   /// \details Terms are stored in a maximally shared way. This
      76             :   ///         means that this equality operator can be calculated
      77             :   ///         in constant time.
      78             :   /// \return true iff t is equal to the current term.
      79  1112444153 :   bool operator ==(const unprotected_aterm& t) const
      80             :   {
      81  1112444153 :     return m_term == t.m_term;
      82             :   }
      83             : 
      84             :   /// \brief Inequality operator on two unprotected aterms.
      85             :   /// \details See note at the == operator. This operator requires constant time.
      86             :   /// \param t A term to which the current term is compared.
      87             :   /// \return false iff t is equal to the current term.
      88    43965579 :   bool operator !=(const unprotected_aterm& t) const
      89             :   {
      90    43965579 :     return m_term!=t.m_term;
      91             :   }
      92             : 
      93             :   /// \brief Comparison operator for two unprotected aterms.
      94             :   /// \details This operator requires constant time. It compares
      95             :   ///         the addresses where terms are stored. That means
      96             :   ///         that the outcome of this operator is only stable
      97             :   ///         as long as aterms are not garbage collected.
      98             :   /// \param t A term to which the current term is compared.
      99             :   /// \return True iff the current term is smaller than the argument.
     100   284830025 :   bool operator <(const unprotected_aterm& t) const
     101             :   {
     102   284830025 :     return m_term<t.m_term;
     103             :   }
     104             : 
     105             :   /// \brief Comparison operator for two unprotected aterms.
     106             :   /// \details This operator requires constant time. See note at the operator <.
     107             :   /// \param t A term to which the current term is compared.
     108             :   /// \return True iff the current term is larger than the argument.
     109         102 :   bool operator >(const unprotected_aterm& t) const
     110             :   {
     111         102 :     return m_term>t.m_term;
     112             :   }
     113             : 
     114             :   /// \brief Comparison operator for two unprotected aterms.
     115             :   /// \details This operator requires constant time. See note at the operator <.
     116             :   /// \param t A term to which the current term is compared.
     117             :   /// \return True iff the current term is smaller or equal than the argument.
     118           5 :   bool operator <=(const unprotected_aterm& t) const
     119             :   {
     120           5 :     return m_term<=t.m_term;
     121             :   }
     122             : 
     123             :   /// \brief Comparison operator for two unprotected aterms.
     124             :   /// \details This operator requires constant time. See note at the operator <.
     125             :   /// \param t A term to which the current term is compared.
     126             :   /// \return True iff the current term is larger or equalthan the argument.
     127             :   bool operator >=(const unprotected_aterm& t) const
     128             :   {
     129             :     return m_term>=t.m_term;
     130             :   }
     131             : 
     132             :   /// \brief Returns true if this term is not equal to the term assigned by
     133             :   ///        the default constructor of aterms, term_appl<T>'s and aterm_int.
     134             :   /// \details The default constructor of a term_list<T> is the empty list, on which
     135             :   ///          the operator defined yields true. This operation is more efficient
     136             :   ///          than comparing the current term with an aterm(), term_appl<T>() or an
     137             :   ///          aterm_int().
     138             :   /// \return A boolean indicating whether this term equals the default constructor.
     139  1498667911 :   bool defined() const
     140             :   {
     141  1498667911 :     return m_term != nullptr;
     142             :   }
     143             : 
     144             :   /// \brief Swaps this term with its argument.
     145             :   /// \details This operation is more efficient than exchanging terms by an assignment,
     146             :   ///          as swapping does not require to change the protection of terms.
     147             :   /// \param t The term with which this term is swapped.
     148        1675 :   void swap(unprotected_aterm& t) noexcept
     149             :   {
     150        1675 :     std::swap(m_term, t.m_term);
     151        1675 :   }
     152             : 
     153             :   /// \brief Yields the function symbol in an aterm.
     154             :   /// \returns The function symbol of the term, which can also be an AS_EMPTY_LIST,
     155             :   ///          AS_INT and AS_LIST.
     156             :   /// \details This is for internal use only.
     157      702846 :   const function_symbol& function() const
     158             :   {
     159      702846 :     return m_term->function();
     160             :   }
     161             : };
     162             : 
     163             : /// \brief The aterm base class that provides protection of the underlying shared terms.
     164             : class aterm : public unprotected_aterm
     165             : {
     166             : public:
     167             : 
     168             :   /// \brief Default constructor.
     169    11643202 :   aterm() noexcept = default;
     170             : 
     171             :   /// \brief Standard destructor.
     172   810839323 :   ~aterm()
     173   810839323 :   {
     174   810839323 :     decrement_reference_count();
     175   810839323 :   }
     176             : 
     177             :   /// \brief Constructor based on an internal term data structure. This is not for public use.
     178             :   /// \details Takes ownership of the passed underlying term.
     179             :   /// \param t A pointer to an internal aterm data structure.
     180             :   /// \todo Should be protected, but this cannot yet be done due to a problem
     181             :   ///       in the compiling rewriter.
     182   161481132 :   explicit aterm(const detail::_aterm *t) noexcept
     183   161481132 :   {
     184   161481132 :     t->increment_reference_count();
     185   161481132 :     m_term = t;
     186   161481132 :   }
     187             : 
     188             :   /// \brief Copy constructor.
     189             :   /// \param other The aterm that is copied.
     190             :   /// \details  This class has a non-trivial destructor so explicitly define the copy and move operators.
     191   460503727 :   aterm(const aterm& other) noexcept
     192   460503727 :    : unprotected_aterm(other.m_term)
     193             :   {
     194   460503727 :     increment_reference_count();
     195   460503727 :   }
     196             : 
     197             :   /// \brief Move constructor.
     198             :   /// \param other The aterm that is moved into the new term. This term may have changed after this operation.
     199             :   /// \details This operation does not employ increments and decrements of reference counts and is therefore more
     200             :   ///          efficient than the standard copy construct.
     201   177250096 :   aterm(aterm&& other) noexcept
     202   177250096 :    : unprotected_aterm(other.m_term)
     203             :   {
     204   177250096 :     other.m_term=nullptr;
     205   177250096 :   }
     206             : 
     207             :   /// \brief Assignment operator.
     208             :   /// \param other The aterm that will be assigned.
     209             :   /// \return A reference to the assigned term.
     210    84883903 :   aterm& operator=(const aterm& other) noexcept
     211             :   {
     212             :     // Increment first to prevent the same term from becoming reference zero temporarily.
     213    84883903 :     other.increment_reference_count();
     214             : 
     215             :     // Decrement the reference from the term that is currently referred to.
     216    84883903 :     decrement_reference_count();
     217             : 
     218    84883903 :     m_term = other.m_term;
     219    84883903 :     return *this;
     220             :   }
     221             : 
     222             :   /// \brief Move assignment operator.
     223             :   /// \brief This move assignment operator
     224             :   /// \param other The aterm that will be assigned.
     225             :   /// \return A reference to the assigned term.
     226    69796851 :   aterm& operator=(aterm&& other) noexcept
     227             :   {
     228    69796851 :     std::swap(m_term, other.m_term);
     229    69796851 :     return *this;
     230             :   }
     231             : 
     232             : protected:
     233             :   /// \brief Increment the reference count.
     234             :   /// \details This increments the reference count unless the term contains null.
     235             :   ///          Use with care as this destroys the reference count mechanism.
     236   545387630 :   void increment_reference_count() const
     237             :   {
     238   545387630 :     if (defined())
     239             :     {
     240   545383757 :       m_term->increment_reference_count();
     241             :     }
     242   545387630 :   }
     243             : 
     244             :   /// \brief Decrement the reference count.
     245             :   /// \details This decrements the reference count unless the term contains null.
     246             :   ///          Use with care as this destroys the reference count mechanism.
     247   895723226 :   void decrement_reference_count() const
     248             :   {
     249   895723226 :     if (defined())
     250             :     {
     251   706826055 :       m_term->decrement_reference_count();
     252             :     }
     253   895723226 :   }
     254             : };
     255             : 
     256             : template <class Term1, class Term2>
     257             : struct is_convertible : public
     258             :     std::conditional<std::is_base_of<aterm, Term1>::value &&
     259             :                      std::is_base_of<aterm, Term2>::value && (
     260             :                      std::is_convertible<Term1, Term2>::value ||
     261             :                      std::is_convertible<Term2, Term1>::value),
     262             :                      std::true_type, std::false_type>::type
     263             : { };
     264             : 
     265             : /// \brief A cheap cast from one aterm based type to another
     266             : ///        When casting one aterm based type into another, generally  a new aterm is constructed,
     267             : ///        and the old one is destroyed. This can cause undesired overhead, for instance due to
     268             : ///        increasing and decreasing of reference counts. This cast changes the type, without
     269             : ///        changing the aterm itself. It can only be used if Base and Derived inherit from aterm,
     270             : ///        and contain no additional information than a
     271             : ///          single aterm.
     272             : /// \param   t A term of a type inheriting from an aterm.
     273             : /// \return  A term of type Derived.
     274             : template <class Derived, class Base>
     275  3036173401 : const Derived& down_cast(const Base& t,
     276             :                          typename std::enable_if<is_convertible<Base, Derived>::value &&
     277             :                                                  !std::is_base_of<Derived, Base>::value>::type* = nullptr)
     278             : {
     279             :   static_assert(sizeof(Derived) == sizeof(aterm),
     280             :                 "aterm cast cannot be applied types derived from aterms where extra fields are added");
     281  3036173401 :   return reinterpret_cast<const Derived&>(t);
     282             : }
     283             : 
     284             : template < typename DerivedCont, typename Base, template <typename Elem> class Cont >
     285        5832 : const DerivedCont& container_cast(const Cont<Base>& t,
     286             :                               typename std::enable_if_t<
     287             :                                 is_container<DerivedCont, aterm>::value &&
     288             :                                 std::is_same_v<Cont<typename DerivedCont::value_type>, DerivedCont> &&
     289             :                                 !std::is_base_of_v<DerivedCont, Cont<Base> > &&
     290             :                                 is_convertible<Base, typename DerivedCont::value_type>::value
     291             :                               >* = nullptr)
     292             : {
     293             :   static_assert(sizeof(typename DerivedCont::value_type) == sizeof(aterm),
     294             :                 "aterm cast cannot be applied types derived from aterms where extra fields are added");
     295        5832 :   return reinterpret_cast<const DerivedCont&>(t);
     296             : }
     297             : 
     298             : /// \brief A cast form an aterm derived class to a class that inherits in possibly multiple steps from this class.
     299             : /// \details The derived class is not allowed to contain extra fields. This conversion does not require runtime computation
     300             : ///          effort. Also see down_cast.
     301             : /// \param t The term that is converted.
     302             : /// \return A term of type Derived.
     303             : template <class Derived, class Base>
     304     3734210 : const Derived& vertical_cast(const Base& t,
     305             :                           typename std::enable_if<is_convertible<Base, Derived>::value>::type* = nullptr)
     306             : {
     307             :   static_assert(sizeof(Derived) == sizeof(aterm),
     308             :                 "aterm cast cannot be applied types derived from aterms where extra fields are added");
     309     3734210 :   return reinterpret_cast<const Derived&>(t);
     310             : }
     311             : 
     312             : template < typename DerivedCont, typename Base, template <typename Elem> class Cont >
     313             : const DerivedCont& vertical_cast(const Cont<Base>& t,
     314             :                               typename std::enable_if_t<
     315             :                                 is_container<DerivedCont, aterm>::value &&
     316             :                                 std::is_same_v<Cont<typename DerivedCont::value_type>, DerivedCont> &&
     317             :                                 is_convertible<Base, typename DerivedCont::value_type>::value
     318             :                               >* = nullptr)
     319             : {
     320             :   static_assert(sizeof(typename DerivedCont::value_type) == sizeof(aterm),
     321             :                 "aterm cast cannot be applied types derived from aterms where extra fields are added");
     322             :   return reinterpret_cast<const DerivedCont&>(t);
     323             : }
     324             : 
     325             : namespace detail
     326             : {
     327             :   /// \returns A pointer to the underlying aterm.
     328  1583516357 :   inline _aterm* address(const unprotected_aterm& t)
     329             :   {
     330  1583516357 :     return const_cast<_aterm*>(t.m_term);
     331             :   }
     332             : }
     333             : 
     334             : } // namespace atermpp
     335             : 
     336             : namespace std
     337             : {
     338             : 
     339             : /// \brief Swaps two aterms.
     340             : /// \details This operation is more efficient than exchanging terms by an assignment,
     341             : ///          as swapping does not require to change the protection of terms.
     342             : ///          In order to be used in the standard containers, the declaration must
     343             : ///          be preceded by an empty template declaration. This swap function is
     344             : ///          not used for classes that derive from the aterm class. A specific
     345             : ///          swap function must be provided for derived classes.
     346             : /// \param t1 The first term
     347             : /// \param t2 The second term
     348             : template <>
     349             : inline void swap(atermpp::unprotected_aterm& t1, atermpp::unprotected_aterm& t2) noexcept
     350             : {
     351             :   t1.swap(t2);
     352             : }
     353             : 
     354             : } // namespace std
     355             : 
     356             : #endif // MCRL2_ATERMPP_ATERM_H

Generated by: LCOV version 1.13