mCRL2
Loading...
Searching...
No Matches
bitstream.cpp
Go to the documentation of this file.
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
11
17
18#ifdef MCRL2_PLATFORM_WINDOWS
19#include <io.h>
20#include <fcntl.h>
21#endif
22
23using namespace mcrl2::utilities;
24
31template<typename int_t = std::size_t>
32static size_t encode_variablesize_int(int_t value, uint8_t* output)
33{
34 size_t outputSize = 0;
35
36 // While more than 7 bits of data are left, occupy the last output byte
37 // and set the next byte flag.
38 while (value > 127)
39 {
40 // | 128: Sets the next byte flag.
41 output[outputSize] = (static_cast<uint8_t>(value & 127)) | 128;
42
43 // Remove the seven bits we just wrote from value.
44 value >>= 7;
45 outputSize++;
46 }
47
48 output[outputSize] = (static_cast<uint8_t>(value));
49 return outputSize + 1;
50}
51
56template<typename int_t = std::size_t>
58{
59 int_t value = 0;
60 for (size_t i = 0; i < integer_encoding_size<int_t>(); i++)
61 {
62 // Read the next byte from the stream.
63 std::size_t byte = stream.read_bits(8);
64
65 // Take 7 bits (mask 0x01111111) from byte and shift it before the bits already written to value.
66 value |= (static_cast<int_t>(byte) & 127) << (7 * i);
67
68 if (!(byte & 128))
69 {
70 // If the next-byte flag is not set then we are finished.
71 break;
72 }
73 else if (i >= integer_encoding_size<int_t>() - 1)
74 {
75 // The next-byte flag was set, but we cannot represent it using int_t.
76 throw std::runtime_error("Fail to read an int from the input");
77 }
78 }
79
80 return value;
81}
82
84static void set_stream_binary(const std::string& name, FILE* handle)
85{
87#ifdef MCRL2_PLATFORM_WINDOWS
88 if (_setmode(_fileno(handle), _O_BINARY) == -1)
89 {
90 mCRL2log(mcrl2::log::warning) << "Cannot set " << name << " to binary mode.\n";
91 }
92 else
93 {
94 mCRL2log(mcrl2::log::debug) << "Converted " << name << " to binary mode.\n";
95 }
96
97 fflush(stderr);
98#endif // MCRL2_PLATFORM_WINDOWS
99}
100
101obitstream::obitstream(std::ostream& stream)
102 : stream(stream)
103{
104 // Ensures that the given stream is changed to binary mode.
105 if (stream.rdbuf() == std::cout.rdbuf())
106 {
107 set_stream_binary("cout", stdout);
108 }
109 else if (stream.rdbuf() == std::cerr.rdbuf())
110 {
111 set_stream_binary("cerr", stderr);
112 }
113}
114
115void obitstream::write_bits(std::size_t value, unsigned int number_of_bits)
116{
117 // Add val to the buffer by masking out additional bits and put them at left-most position free in the buffer.
118 assert(number_of_bits <= std::numeric_limits<std::size_t>::digits);
119 if (number_of_bits < std::numeric_limits<std::size_t>::digits) // the check is needed to avoid undefined behavior
120 {
121 value &= (static_cast<std::size_t>(1) << number_of_bits) - 1;
122 }
123
124 write_buffer |= std::bitset<128>(value) << ((128 - bits_in_buffer) - number_of_bits);
125 bits_in_buffer += number_of_bits;
126
127 // Write 8 bytes if available
128 if (bits_in_buffer >= 64)
129 {
130 unsigned long long write_value = (write_buffer >> 64).to_ullong();
131 write_buffer <<= 64;
132 bits_in_buffer -= 64;
133
134 for (int32_t i = 7; i >= 0; --i)
135 {
136 // Write the 8 * i most significant bits and mask out the other values.
137 stream.put(static_cast<char>((write_value >> (8 * i)) & 255));
138
139 if (stream.fail())
140 {
141 throw mcrl2::runtime_error("Failed to write bytes to the output file/stream.");
142 }
143 }
144 }
145}
146
147void obitstream::write_string(const std::string& string)
148{
149 // Write length.
150 write_integer(string.size());
151
152 // Write actual string.
153 write(reinterpret_cast<const std::uint8_t*>(string.c_str()), string.size());
154}
155
156void obitstream::write_integer(std::size_t val)
157{
158 std::size_t nr_bytes = encode_variablesize_int(val, integer_buffer);
159
160 write(integer_buffer, nr_bytes);
161}
162
163ibitstream::ibitstream(std::istream& stream)
164 : stream(stream)
165{
166 // Ensures that the given stream is changed to binary mode.
167 if (stream.rdbuf() == std::cin.rdbuf())
168 {
169 set_stream_binary("cin", stdin);
170 }
171}
172
174{
175 std::size_t length;
176
177 // Get length of string.
178 length = read_integer();
179
180 // Assure buffer can hold the string.
181 if (m_text_buffer.size() < (length + 1))
182 {
183 m_text_buffer.resize(round_up_to_power_of_two(length + 1));
184 }
185
186 // Read the actual string.
187 read(length, reinterpret_cast<std::uint8_t*>(m_text_buffer.data()));
188 m_text_buffer[length] = '\0';
189
190 return m_text_buffer.data();
191}
192
193std::size_t ibitstream::read_bits(unsigned int number_of_bits)
194{
195 // Read at most the number of bits of a std::size_t.
196 assert(number_of_bits <= std::numeric_limits<std::size_t>::digits);
197
198 while (bits_in_buffer < number_of_bits)
199 {
200 // Read bytes until the buffer is sufficiently full.
201 int byte = stream.get();
202
203 if (stream.eof())
204 {
205 throw mcrl2::runtime_error("Unexpected end-of-file reached in the input file/stream.");
206 }
207 else if (stream.fail())
208 {
209 throw mcrl2::runtime_error("Failed to read bytes from the input file/stream.");
210 }
211
212 // Shift the 8 bits to the first free (120 - bits_in_buffer) position in the buffer.
213 read_buffer |= std::bitset<128>(static_cast<std::size_t>(byte)) << (56 + 64 - bits_in_buffer);
214 bits_in_buffer += 8;
215 }
216
217 // Read nr_bits from the buffer by shifting them to the least significant bits and masking out the remaining bits.
218 std::size_t value = (read_buffer >> (128 - number_of_bits)).to_ullong();
219
220 // Shift the first bit to the first position in the buffer.
221 read_buffer <<= number_of_bits;
222 bits_in_buffer -= number_of_bits;
223
224 return value;
225}
226
228{
229 return decode_variablesize_int(*this);
230}
231
232// Private functions
233
235{
236 // Writing the buffer full to 64 bits should flush it internally, this also guarantees that the unnecessary bits are zeroed out.
237 write_bits(0, 64 - bits_in_buffer);
238 assert(bits_in_buffer == 0);
239
240 stream.flush();
241 if (stream.fail())
242 {
243 throw mcrl2::runtime_error("Failed to write the last byte to the output file/stream.");
244 }
245}
246
247void obitstream::write(const uint8_t* buffer, std::size_t size)
248{
249 for (std::size_t index = 0; index < size; ++index)
250 {
251 // Write a single byte for every entry in the buffer that was filled (size).
252 write_bits(buffer[index], 8);
253 }
254}
255
256void ibitstream::read(std::size_t size, std::uint8_t* buffer)
257{
258 for (std::size_t index = 0; index < size; ++index)
259 {
260 // Read a single byte for every entry into the buffer that was filled (size).
261 std::size_t value = read_bits(8);
262 buffer[index] = static_cast<std::uint8_t>(value);
263 }
264}
static void set_stream_binary(const std::string &name, FILE *handle)
Change the current stream to binary mode (no handle of newline characters),.
Definition bitstream.cpp:84
static size_t encode_variablesize_int(int_t value, uint8_t *output)
Encodes an unsigned variable-length integer using the most significant bit (MSB) algorithm....
Definition bitstream.cpp:32
int_t decode_variablesize_int(ibitstream &stream)
Decodes an unsigned variable-length integer using the MSB algorithm.
Definition bitstream.cpp:57
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
unsigned int bits_in_buffer
how many bits in the buffer are used.
Definition bitstream.h:97
std::size_t read_bits(unsigned int num_of_bits)
Reads an num_of_bits bits from the input stream and stores them in the least significant part (in des...
void read(std::size_t size, std::uint8_t *buffer)
Read size bytes into the provided buffer.
std::vector< char > m_text_buffer
A temporary buffer to store char array strings.
Definition bitstream.h:99
std::bitset< 128 > read_buffer
Buffer that is filled starting from bit 127 when reading.
Definition bitstream.h:95
ibitstream(std::istream &stream)
Provides the stream on which the read function operate.
void flush()
Flush the remaining bits in the buffer to the output stream.
std::bitset< 128 > write_buffer
Buffer that is filled starting from bit 127 when writing.
Definition bitstream.h:62
unsigned int bits_in_buffer
how many bits in are used in the buffer.
Definition bitstream.h:64
std::uint8_t integer_buffer[integer_encoding_size< std::size_t >()]
Reserved space to store an n byte integer.
Definition bitstream.h:66
void write_bits(std::size_t value, unsigned int num_of_bits)
Write the num_of_bits least significant bits in descending order from value.
void write(const std::uint8_t *buffer, std::size_t size)
Writes size bytes from the given buffer.
void write_string(const std::string &string)
Write the given string to the output stream.
void write_integer(std::size_t value)
Write the given value to the output stream.
obitstream(std::ostream &stream)
Provides the stream on which the write function operate.
Exception classes for use in libraries and tools.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
@ warning
Definition logger.h:34
static T round_up_to_power_of_two(T value)
void mcrl2_unused(T &&...)
Function that can be used to silence unused parameter warnings.
Definition unused.h:20
add your file description here.