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

Generated by: LCOV version 1.13