mCRL2
Loading...
Searching...
No Matches
aterm.h
Go to the documentation of this file.
1// Author(s): 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/atermpp/aterm.h
10/// \brief The aterm class contains terms which essentially are function applications.
11
12#ifndef MCRL2_ATERMPP_ATERM_APPL_H
13#define MCRL2_ATERMPP_ATERM_APPL_H
14
15#include "mcrl2/atermpp/aterm_core.h"
16#include "mcrl2/atermpp/concepts.h"
17#include "mcrl2/atermpp/detail/aterm_appl_iterator.h"
18#include "mcrl2/atermpp/detail/aterm_core.h"
19#include "mcrl2/atermpp/detail/aterm_list.h"
20#include "mcrl2/atermpp/detail/global_aterm_pool.h"
21#include "mcrl2/utilities/type_traits.h"
22#include <type_traits>
23
24namespace atermpp
25{
26
27class aterm : public aterm_core
28{
29protected:
30 /// \brief Constructor.
31 /// \param t A pointer internal data structure from which the term is constructed.
32 /// \details This function is explicitly protected such that is not used in common code.
33 explicit aterm(detail::_term_appl* t)
34 : aterm_core(static_cast<detail::_aterm*>(t))
35 {}
36
37public:
38 /// An unsigned integral type.
40
41 /// A signed integral type.
42 using difference_type = ptrdiff_t;
43
44 /// Iterator used to iterate through an term_appl.
46
47 /// Const iterator used to iterate through an term_appl.
49
50 /// \brief Default constructor.
52 : aterm_core()
53 {}
54
55 /// This class has user-declared copy constructor so declare default copy and move operators.
56 aterm(const aterm& other) noexcept = default;
57 aterm& operator=(const aterm& other) noexcept = default;
58 aterm(aterm&& other) noexcept = default;
59 aterm& operator=(aterm&& other) noexcept = default;
60
61 /// \brief Constructor that provides an aterm based on a function symbol and forward iterator providing the arguments.
62 /// \details The iterator range is traversed more than once. If only one traversal is required
63 /// use term_appl with a TermConverter argument. But this function
64 /// is substantially less efficient.
65 /// The length of the iterator range must match the arity of the function symbol.
66 /// \param sym A function symbol.
67 /// \param begin The start of a range of elements.
68 /// \param end The end of a range of elements.
69 template <class ForwardIterator>
70 aterm(const function_symbol& sym, ForwardIterator begin, ForwardIterator end)
74 {
75 detail::g_thread_term_pool().create_appl_dynamic(*this, sym, begin, end);
76 }
77
78 /// \brief Constructor that provides an aterm based on a function symbol and an input iterator providing the
79 /// arguments. \details The given iterator is traversed only once. So it can be used with an input iterator.
80 /// This means that the TermConverter is applied exactly once to each element.
81 /// The length of the iterator range must be equal to the arity of the function symbol.
82 /// \param sym A function symbol.
83 /// \param begin The start of a range of elements.
84 /// \param end The end of a range of elements.
85 template <class InputIterator>
86 aterm(const function_symbol& sym, InputIterator begin, InputIterator end)
89 : aterm(sym, begin, end, [](const unprotected_aterm_core& term) -> const unprotected_aterm_core& { return term; })
90 {
92 "The InputIterator is missing the input iterator tag.");
93 }
94
95 /// \details The given iterator is traversed only once. So it can be used with an input iterator.
96 /// This means that the TermConverter is applied exactly once to each element.
97 /// The length of the iterator range must be equal to the arity of the function symbol.
98 /// \param sym A function symbol.
99 /// \param begin The start of a range of elements.
100 /// \param end The end of a range of elements.
101 /// \param converter An class or lambda term containing an operator Term operator()(const Term& t) which is
102 /// applied to each each element in the iterator range before it becomes an argument of this term.
103 template <class InputIterator, class TermConverter>
106 {
109 "The InputIterator has the output iterator tag.");
110 }
111
112 /// \brief Constructor.
113 /// \param sym A function symbol.
115
116 /// \brief Constructor for n-arity function application.
117 /// \param symbol A function symbol.
118 /// \param arguments The arguments of the function application.
119 template <typename... Terms>
121 {
123 }
124
125 /// \brief Returns the function symbol belonging to an aterm.
126 /// \return The function symbol of this term.
127 const function_symbol& function() const { return m_term->function(); }
128
129 /// \brief Returns the number of arguments of this term.
130 /// \return The number of arguments of this term.
131 size_type size() const { return m_term->function().arity(); }
132
133 /// \brief Returns true if the term has no arguments.
134 /// \return True if this term has no arguments.
135 bool empty() const { return size() == 0; }
136
137 /// \brief Returns an iterator pointing to the first argument.
138 /// \return An iterator pointing to the first argument.
140 {
141 return const_iterator(&static_cast<const aterm&>(reinterpret_cast<const detail::_term_appl*>(m_term)->arg(0)));
142 }
143
144 /// \brief Returns a const_iterator pointing past the last argument.
145 /// \return A const_iterator pointing past the last argument.
147 {
148 return const_iterator(&static_cast<const aterm&>(reinterpret_cast<const detail::_term_appl*>(m_term)->arg(size())));
149 }
150
151 /// \brief Returns the largest possible number of arguments.
152 /// \return The largest possible number of arguments.
153 constexpr size_type max_size() const { return std::numeric_limits<size_type>::max(); }
154
155 /// \brief Returns the i-th argument.
156 /// \param i A positive integer.
157 /// \return The argument with the given index.
158 const aterm& operator[](const size_type i) const
159 {
160 assert(i < size()); // Check the bounds.
161 return static_cast<const aterm&>(reinterpret_cast<const detail::_term_appl*>(m_term)->arg(i));
162 }
163};
164
165using term_callback = void (*)(const aterm&);
166
167extern void add_deletion_hook(const function_symbol&, term_callback);
168
169/// \brief Constructor an aterm in a variable based on a function symbol and an forward iterator providing the
170/// arguments. \details The iterator range is traversed more than once. If only one traversal is required
171/// use term_appl with a TermConverter argument. But this function
172/// is substantially less efficient.
173/// The length of the iterator range must match the arity of the function symbol.
174/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
175/// \param sym A function symbol.
176/// \param begin The start of a range of elements.
177/// \param end The end of a range of elements.
178template <class Term,
179 class ForwardIterator>
180void make_term_appl(Term& target, const function_symbol& sym, ForwardIterator begin, ForwardIterator end)
184{
185 detail::g_thread_term_pool().create_appl_dynamic(target, sym, begin, end);
186
187 static_assert((std::is_base_of_v<aterm, Term>), "Term must be derived from an aterm");
188 static_assert(sizeof(Term) == sizeof(std::size_t), "Term derived from an aterm must not have extra fields");
189}
190
191/// \brief Constructor an aterm in a variable based on a function symbol and an input iterator providing the arguments.
192/// \details The given iterator is traversed only once. So it can be used with an input iterator.
193/// This means that the TermConverter is applied exactly once to each element.
194/// The length of the iterator range must be equal to the arity of the function symbol.
195/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
196/// \param sym A function symbol.
197/// \param begin The start of a range of elements.
198/// \param end The end of a range of elements.
199template <class Term, class InputIterator>
200void make_term_appl(Term& target, const function_symbol& sym, InputIterator begin, InputIterator end)
203{
204 make_term_appl(target, sym, begin, end, [](const Term& term) -> const Term& { return term; });
205
206 static_assert((std::is_base_of_v<aterm, Term>), "Term must be derived from an aterm");
207 static_assert(sizeof(Term) == sizeof(std::size_t), "Term derived from an aterm must not have extra fields");
209 "The InputIterator is missing the input iterator tag.");
210}
211
212/// \brief Constructor an aterm in a variable based on a function symbol and an forward iterator providing the
213/// arguments. \details The given iterator is traversed only once. So it can be used with an input iterator.
214/// This means that the TermConverter is applied exactly once to each element.
215/// The length of the iterator range must be equal to the arity of the function symbol.
216/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
217/// \param sym A function symbol.
218/// \param begin The start of a range of elements.
219/// \param end The end of a range of elements.
220/// \param converter An class or lambda term containing an operator Term operator()(const Term& t) which is
221/// applied to each each element in the iterator range before it becomes an argument of this term.
222template <class Term, class InputIterator, class TermConverter>
224 const function_symbol& sym,
229{
231
232 static_assert(std::is_base_of_v<aterm, Term>, "Term must be derived from an aterm");
233 static_assert(sizeof(Term) == sizeof(std::size_t), "Term derived from an aterm must not have extra fields");
234}
235
236/// \brief Make an term_appl consisting of a single function symbol.
237/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
238/// \param sym A function symbol.
239template <class Term>
241{
243
244 static_assert(std::is_base_of_v<aterm, Term>, "Term must be derived from an aterm");
245 static_assert(sizeof(Term) == sizeof(std::size_t), "Term derived from an aterm must not have extra fields");
246}
247
248/// \brief Make an aterm application for n-arity function application.
249/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
250/// \param symbol A function symbol.
251/// \param arguments The arguments of the function application.
252template <class Term, typename... Terms>
254{
256}
257
258/// \brief Constructor for n-arity function application with an index.
259/// \param target The variable in which the result will be put. This variable may be used for scratch purposes.
260/// \param symbol A function symbol.
261/// \param arguments The arguments of the function application.
262template <class Term, class INDEX_TYPE, typename... Terms>
264{
266}
267
268/// \brief A universal cast from an aterm to another aterm that is convertible in either direction. Less strict than vertical_cast.
269/// \param t A term of a type inheriting from an aterm.
270/// \return A term of type const Derived&.
271template <IsATerm Derived, IsATerm Base>
276const Derived& down_cast(const Base& t)
277{
278 // Runtime check that the cast is valid.
279 assert(Derived(static_cast<const aterm&>(t)) != aterm());
280
281 // UB: Only allowed when we constructed an actual Derived type
282 return reinterpret_cast<const Derived&>(reinterpret_cast<const detail::_aterm&>(t));
283}
284
285/// \brief A universal cast from an aterm to another non const aterm that is convertible in either direction. The casted term is assignable.
286/// \param t A term of a type inheriting from an aterm.
287/// \return A term of type Derived&.
288template <IsATerm Derived, IsATerm Base>
294{
295 // Runtime check that the cast is valid.
296 // This check is unnecessary and even incorrect as the term assigned may contain an arbitrary term,
297 // that is not necessary of type Derived.
298 // assert(Derived(static_cast<const aterm&>(t)) != aterm());
299
300 // UB: Only allowed when we constructed an actual Derived type
301 return reinterpret_cast<Derived&>(reinterpret_cast<detail::_aterm&>(t));
302}
303
304/// \brief A cast form an aterm derived class to a class that inherits in (possibly multiple steps) from this class.
305/// \details The derived class is not allowed to contain extra fields. This conversion does not require runtime
306/// computation
307/// effort. Also see down_cast.
308/// \param t The term that is converted.
309/// \return A term of type Derived.
310template <IsATerm Derived, IsATerm Base>
313{
314 // Runtime check that the cast is valid.
315 assert(Derived(static_cast<const aterm&>(t)) != aterm());
316
317 return reinterpret_cast<const Derived&>(reinterpret_cast<const detail::_aterm&>(t));
318}
319
320/// \brief Send the term in textual form to the ostream.
321/// \param out The stream to which the term is sent.
322/// \param t The term that is printed to the stream.
323/// \return The stream to which the term is written.
325
326/// \brief Transform an aterm to an ascii string.
327/// \param t The input aterm.
328/// \return A string representation of the given term derived from an aterm.
329inline std::string pp(const atermpp::aterm& t)
330{
331 std::ostringstream oss;
332 oss << t;
333 return oss.str();
334}
335
336} // namespace atermpp
337
338namespace std
339{
340
341/// \brief Swaps two aterms.
342/// \details This operation is more efficient than exchanging terms by an assignment,
343/// as swapping does not require to change the protection of terms.
344/// In order to be used in the standard containers, the declaration must
345/// be preceded by an empty template declaration. This swap function is
346/// not used for classes that derive from the aterm class. A specific
347/// swap function must be provided for derived classes.
348/// \param t1 The first term
349/// \param t2 The second term
350template <>
351inline void swap(atermpp::unprotected_aterm_core& t1, atermpp::unprotected_aterm_core& t2) noexcept
352{
353 t1.swap(t2);
354}
355} // namespace std
356namespace std
357{
358
359/// \brief Swaps two term_applss.
360/// \details This operation is more efficient than exchanging terms by an assignment,
361/// as swapping does not require to change the protection of terms.
362/// \param t1 The first term.
363/// \param t2 The second term.
364inline void swap(atermpp::aterm& t1, atermpp::aterm& t2) noexcept
365{
366 t1.swap(t2);
367}
368
369/// \brief Standard hash function.
370template <>
371struct hash<atermpp::aterm>
372{
373 std::size_t operator()(const atermpp::aterm& t) const { return std::hash<atermpp::aterm_core>()(t); }
374};
375
376} // namespace std
377
378#endif // MCRL2_ATERMPP_ATERM_APPL_H
atermpp::aterm create_nested_function(const std::string &function_name, const std::string &leaf_name, std::size_t number_of_arguments, std::size_t depth)
Create a nested function application f_depth. Where f_0 = c and f_i = f(f_i-1,...,...
atermpp::aterm create_nested_function(const std::string &function_name, const std::string &leaf_name, std::size_t depth)
Create a nested function application f_depth. Where f_0 = c and f_i = f(f_i-1,...,...
void benchmark_threads(std::size_t number_of_threads, F f)
Run the given function f on number_of_threads threads (including the main thread) and report the elap...
aterm(aterm &&other) noexcept=default
aterm()
Default constructor.
Definition aterm.h:51
aterm & operator=(const aterm &other) noexcept=default
aterm(const aterm &other) noexcept=default
This class has user-declared copy constructor so declare default copy and move operators.
aterm(detail::_term_appl *t)
Constructor.
Definition aterm.h:33
aterm & operator=(aterm &&other) noexcept=default
aterm(const function_symbol &sym, ForwardIterator begin, ForwardIterator end)
Constructor that provides an aterm based on a function symbol and forward iterator providing the argu...
Definition aterm.h:70
void enable_garbage_collection(bool enable)
Enable garbage collection when passing true and disable otherwise.
Definition aterm_pool.h:133
A unordered_map class in which aterms can be stored.
Implements a simple stopwatch that starts on construction.
Definition stopwatch.h:17
The main namespace for the aterm++ library.
std::string pp(const atermpp::aterm &t)
Transform an aterm to an ascii string.
Definition aterm.h:329
void add_deletion_hook(const function_symbol &, term_callback)
Check for reasonably sized aterm (32 bits, 4 bytes) This check might break on perfectly valid archite...
void make_term_appl(Term &target, const function_symbol &sym, ForwardIterator begin, ForwardIterator end)
Constructor an aterm in a variable based on a function symbol and an forward iterator providing the a...
Definition aterm.h:180
void swap(atermpp::aterm &t1, atermpp::aterm &t2) noexcept
Swaps two term_applss.
Definition aterm.h:364
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Definition aterm.h:351
int main(int argc, char *argv[])
std::size_t operator()(const atermpp::aterm &t) const
Definition aterm.h:373