mCRL2
Loading...
Searching...
No Matches
aterm_io_binary.cpp
Go to the documentation of this file.
1// Author(s): Jan Friso Groote
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
12
13
14namespace atermpp
15{
16using namespace mcrl2::utilities;
17
21static constexpr std::uint16_t BAF_MAGIC = 0x8baf;
22
40static constexpr std::uint16_t BAF_VERSION = 0x8308;
41
44enum class packet_type
45{
47 aterm,
50};
51
53static constexpr unsigned int packet_bits = 2;
54
55binary_aterm_ostream::binary_aterm_ostream(std::shared_ptr<mcrl2::utilities::obitstream> stream)
56 : m_stream(stream)
57{
58 // The term with function symbol index 0 indicates the end of the stream, its actual value does not matter.
59 m_function_symbols.insert(function_symbol("end_of_stream", 0));
61
62 // Write the header of the binary aterm format.
63 m_stream->write_bits(0, 8);
64 m_stream->write_bits(BAF_MAGIC, 16);
65 m_stream->write_bits(BAF_VERSION, 16);
66}
67
69 : binary_aterm_ostream(std::make_shared<mcrl2::utilities::obitstream>(stream))
70{}
71
73{
74 // Write the end of the stream.
75 m_stream->write_bits(static_cast<std::size_t>(packet_type::aterm), packet_bits);
76 m_stream->write_bits(0, function_symbol_index_width());
77}
78
81{
83 bool write = false;
84
86 : term(term)
87 {}
88
89 void mark(std::stack<std::reference_wrapper<detail::_aterm>>& todo) const
90 {
91 term.mark(todo);
92 }
93};
94
96{
97 // Traverse the term bottom up and store the subterms (and function symbol) before the actual term.
99 stack.emplace(static_cast<const aterm&>(term));
100
101 do
102 {
103 write_todo& current = stack.top();
104 aterm transformed = m_transformer(static_cast<const aterm&>(static_cast<const aterm&>(current.term)));
105
106 // Indicates that this term is output and not a subterm, these should always be written.
107 bool is_output = stack.size() == 1;
108 if (m_terms.index(current.term) >= m_terms.size() || is_output)
109 {
110 if (current.write)
111 {
112 if (transformed.type_is_int())
113 {
114 if (is_output)
115 {
116 // If the integer is output, write the header and just an integer
117 m_stream->write_bits(static_cast<std::size_t>(packet_type::aterm_int_output), packet_bits);
118 m_stream->write_integer(static_cast<const aterm_int&>(static_cast<const aterm&>(current.term)).value());
119 }
120 else
121 {
122 std::size_t symbol_index = write_function_symbol(transformed.function());
123
124 // Write the packet identifier of an aterm_int followed by its value.
125 m_stream->write_bits(static_cast<std::size_t>(packet_type::aterm), packet_bits);
126 m_stream->write_bits(symbol_index, function_symbol_index_width());
127 m_stream->write_integer(static_cast<const aterm_int&>(static_cast<const aterm&>(current.term)).value());
128 }
129 }
130 else
131 {
132 std::size_t symbol_index = write_function_symbol(transformed.function());
133
134 // Write the packet identifier, followed by the indices of its function symbol and arguments.
135 m_stream->write_bits(static_cast<std::size_t>(is_output ? packet_type::aterm_output : packet_type::aterm), packet_bits);
136 m_stream->write_bits(symbol_index, function_symbol_index_width());
137
138 for (const aterm& argument : transformed)
139 {
140 std::size_t index = m_terms.index(argument);
141 assert(index < m_terms.size()); // Every argument must already be written.
142 m_stream->write_bits(index, term_index_width());
143 }
144 }
145
146 if (!is_output)
147 {
148 // Only regular terms (not output) are shared and as such need a unique index.
149 bool assigned = m_terms.insert(current.term).second;
150 assert(assigned); mcrl2_unused(assigned); // This term should have a new index assigned.
151 m_term_index_width = static_cast<std::uint8_t>(std::log2(m_terms.size()) + 1);
152 }
153
154 stack.pop();
155 }
156 else
157 {
158 // Add all the arguments to the stack; to be processed first.
159 for (const aterm& argument : transformed)
160 {
161 const aterm& term = static_cast<const aterm&>(argument);
162 if (m_terms.index(term) >= m_terms.size())
163 {
164 // Only add arguments that have not been written before.
165 stack.emplace(term);
166 }
167 }
168
169 current.write = true;
170 }
171 }
172 else
173 {
174 stack.pop(); // This term was already written and as such should be skipped. This can happen if
175 // one term has two equal subterms.
176 }
177 }
178 while (!stack.empty());
179}
180
182{
183 assert(m_term_index_width == static_cast<unsigned int>(std::log2(m_terms.size()) + 1));
184 return m_term_index_width;
185}
186
188{
189 assert(m_function_symbol_index_width == static_cast<unsigned int>(std::log2(m_function_symbols.size()) + 1));
191}
192
193binary_aterm_istream::binary_aterm_istream(std::shared_ptr<mcrl2::utilities::ibitstream> stream)
194 : m_stream(stream)
195{
196 // The term with function symbol index 0 indicates the end of the stream.
197 m_function_symbols.emplace_back();
199
200 // Read the binary aterm format header.
201 if (m_stream->read_bits(8) != 0 || m_stream->read_bits(16) != BAF_MAGIC)
202 {
203 throw mcrl2::runtime_error("Error while reading: missing the BAF_MAGIC control sequence.");
204 }
205
206 std::size_t version = m_stream->read_bits(16);
207 if (version != BAF_VERSION)
208 {
209 throw mcrl2::runtime_error("The BAF version (" + std::to_string(version) + ") of the input file is incompatible with the version (" + std::to_string(BAF_VERSION) +
210 ") of this tool. The input file must be regenerated. ");
211 }
212}
213
215 : binary_aterm_istream(std::make_shared<mcrl2::utilities::ibitstream>(is))
216{}
217
219{
220 std::size_t result = m_function_symbols.index(symbol);
221
222 if (result < m_function_symbols.size())
223 {
224 return result;
225 }
226 else
227 {
228 // The function symbol has not been written yet, write it now and return its index.
229 m_stream->write_bits(static_cast<std::size_t>(packet_type::function_symbol), packet_bits);
230 m_stream->write_string(symbol.name());
231 m_stream->write_integer(symbol.arity());
232
233 auto result = m_function_symbols.insert(symbol);
234 m_function_symbol_index_width = static_cast<unsigned int>(std::log2(m_function_symbols.size()) + 1);
235
236 return result.first;
237 }
238}
239
241{
242 while(true)
243 {
244 // Determine the type of the next packet.
245 std::size_t header = m_stream->read_bits(packet_bits);
246 packet_type packet = static_cast<packet_type>(header);
247
248 if (packet == packet_type::function_symbol)
249 {
250 // Read a single function symbol and insert it into the already read function symbols.
251 std::string name = m_stream->read_string();
252 std::size_t arity = m_stream->read_integer();
253 m_function_symbols.emplace_back(name, arity);
254 m_function_symbol_index_width = static_cast<unsigned int>(std::log2(m_function_symbols.size()) + 1);
255 }
256 else if (packet == packet_type::aterm_int_output)
257 {
258 // Read the integer from the stream and construct an aterm_int.
259 std::size_t value = m_stream->read_integer();
260 make_aterm_int(static_cast<aterm_int&>(t), value);
261 return;
262 }
263 else if (packet == packet_type::aterm || packet == packet_type::aterm_output)
264 {
265 // First read the function symbol of the following term.
267
268 if (!symbol.defined())
269 {
270 // The term with function symbol zero marks the end of the stream.
271 t=aterm();
272 return;
273 }
274 else if (symbol == detail::g_as_int)
275 {
276 // Read the integer from the stream and construct a shared aterm_int in the index.
277 std::size_t value = m_stream->read_integer();
278 m_terms.emplace_back(aterm_int(value));
279 m_term_index_width = static_cast<unsigned int>(std::log2(m_terms.size()) + 1);
280 }
281 else
282 {
283 // Read arity number of arguments from the stream and search them in the already defined set of terms.
284 std::vector<aterm> arguments(symbol.arity());
285 for (std::size_t argument = 0; argument < symbol.arity(); ++argument)
286 {
287 arguments[argument] = m_terms[m_stream->read_bits(term_index_width())];
288 }
289
290 // Transform the resulting term.
291 aterm transformed = m_transformer(aterm(symbol, arguments.begin(), arguments.end()));
292
293 if (packet == packet_type::aterm_output)
294 {
295 // This aterm was marked as output in the file so return it.
296 t=transformed;
297 return;
298 }
299 else
300 {
301 // Construct the term appl from the function symbol and the already read arguments and insert it.
302 m_terms.emplace_back(transformed);
303 m_term_index_width = static_cast<unsigned int>(std::log2(m_terms.size()) + 1);
304 }
305 }
306 }
307 }
308}
309
311{
312 assert(m_term_index_width == static_cast<unsigned int>(std::log2(m_terms.size()) + 1));
313 return m_term_index_width;
314}
315
317{
318 assert(m_function_symbol_index_width == static_cast<unsigned int>(std::log2(m_function_symbols.size()) + 1));
320}
321
322void write_term_to_binary_stream(const aterm& t, std::ostream& os)
323{
324 binary_aterm_ostream(os) << t;
325}
326
327void read_term_from_binary_stream(std::istream& is, aterm& t)
328{
330}
331
332} // namespace atermpp
An integer term stores a single std::size_t value. It carries no arguments.
Definition aterm_int.h:26
std::size_t value() const noexcept
Provide the value stored in an aterm.
Definition aterm_int.h:54
aterm_transformer * m_transformer
Definition aterm_io.h:42
const function_symbol & function() const
Returns the function symbol belonging to an aterm.
Definition aterm.h:144
Reads terms from a stream in the steamable binary aterm format.
std::shared_ptr< mcrl2::utilities::ibitstream > m_stream
unsigned int m_function_symbol_index_width
caches the result of function_symbol_index_width().
atermpp::deque< aterm > m_terms
An index of read terms.
binary_aterm_istream(std::istream &is)
Provide the input stream from which terms are read.
unsigned int m_term_index_width
caches the result of term_index_width().
void get(aterm &t) override
Reads an aterm from this stream.
std::deque< function_symbol > m_function_symbols
An index of read function symbols.
Writes terms in a streamable binary aterm format to an output stream.
unsigned int m_term_index_width
caches the result of term_index_width().
std::size_t write_function_symbol(const function_symbol &symbol)
Write a function symbol to the output stream.
binary_aterm_ostream(std::ostream &os)
Provide the output stream to which the terms are written.
std::shared_ptr< mcrl2::utilities::obitstream > m_stream
unsigned int m_function_symbol_index_width
caches the result of function_symbol_index_width().
atermpp::indexed_set< aterm > m_terms
An index of already written terms.
void put(const aterm &term) override
Writes an aterm in a compact binary format where subterms are shared. The term that is written itself...
mcrl2::utilities::indexed_set< function_symbol > m_function_symbols
An index of already written function symbols.
Base class that should not be used.
std::size_t arity() const
Return the arity (number of arguments) of the function symbol (function_symbol).
const std::string & name() const
Return the name of the function_symbol.
A deque class in which aterms can be stored.
Definition stack.h:34
bool empty() const
Definition stack.h:124
size_type size() const
Definition stack.h:129
void pop()
Definition stack.h:150
void emplace(Args &&... args)
Definition stack.h:145
reference top()
Definition stack.h:114
bool type_is_int() const noexcept
Dynamic check whether the term is an aterm_int.
Definition aterm_core.h:63
Standard exception class for reporting runtime errors.
Definition exception.h:27
The counterpart of obitstream, guarantees that the same data is read as has been written when calling...
Definition bitstream.h:72
A bitstream provides per bit writing of data to any stream (including stdout).
Definition bitstream.h:32
function_symbol g_as_int
These function symbols are used to indicate integer, list and empty list terms.
The main namespace for the aterm++ library.
Definition algorithm.h:21
void write_term_to_binary_stream(const aterm &t, std::ostream &os)
Writes term t to a stream in binary aterm format.
static constexpr std::uint16_t BAF_VERSION
The BAF_VERSION constant is the version number of the ATerms written in BAF format....
void read_term_from_binary_stream(std::istream &is, aterm &t)
Reads a term from a stream in binary aterm format.
packet_type
Each packet has a header consisting of a type.
void make_aterm_int(aterm_int &target, std::size_t value)
Constructs an integer term from a value.
Definition aterm_int.h:69
static constexpr unsigned int packet_bits
The number of bits needed to store an element of packet_type.
static constexpr std::uint16_t BAF_MAGIC
The magic value for a binary aterm format stream.
void mcrl2_unused(T &&...)
Function that can be used to silence unused parameter warnings.
Definition unused.h:20
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
STL namespace.
Keep track of whether the term can be written to the stream.
void mark(std::stack< std::reference_wrapper< detail::_aterm > > &todo) const
write_todo(const aterm &term)
detail::reference_aterm< aterm > term