Line data Source code
1 : #ifndef _USE_MATH_DEFINES
2 : #define _USE_MATH_DEFINES
3 : #endif
4 : #include <algorithm>
5 : #include <cmath>
6 : #include <sstream>
7 :
8 : #include "Tools/Algo/Bit_packer/Bit_packer.hpp"
9 : #include "Tools/Exception/exception.hpp"
10 :
11 : namespace spu
12 : {
13 : namespace tools
14 : {
15 : template<typename B, class AB, typename S, class AS>
16 : void
17 : Bit_packer::pack(const std::vector<B, AB>& vec_in,
18 : std::vector<S, AS>& vec_out,
19 : const int n_frames,
20 : const bool msb_to_lsb,
21 : const bool pack_per_byte,
22 : const int Nbps)
23 : {
24 : if (n_frames <= 0)
25 : {
26 : std::stringstream message;
27 : message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
28 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
29 : }
30 :
31 : if (vec_in.size() % n_frames)
32 : {
33 : std::stringstream message;
34 : message << "'vec_in.size()' has to be divisible by 'n_frames' ('vec_in.size()' = " << vec_in.size()
35 : << ", 'n_frames' = " << n_frames << ").";
36 : throw length_error(__FILE__, __LINE__, __func__, message.str());
37 : }
38 :
39 : if (pack_per_byte)
40 : {
41 :
42 : if ((vec_out.size() * sizeof(S) * Nbps) < vec_in.size())
43 : {
44 : std::stringstream message;
45 : message << "'vec_out.size()' has to be equal or greater than ('vec_in.size()' / 'sizeof(S)' / 'Nbps') "
46 : << "('vec_out.size()' = " << vec_out.size() << ", 'vec_in.size()' = " << vec_in.size()
47 : << ", 'sizeof(S)' = " << sizeof(S) << ", 'Nbps' = " << Nbps << ").";
48 : throw length_error(__FILE__, __LINE__, __func__, message.str());
49 : }
50 :
51 : Bit_packer::pack(
52 : vec_in.data(), (unsigned char*)vec_out.data(), (int)(vec_in.size() / n_frames), n_frames, msb_to_lsb, Nbps);
53 : }
54 : else
55 : {
56 : if ((vec_out.size() * Nbps) < vec_in.size())
57 : {
58 : std::stringstream message;
59 : message << "'vec_out.size()' has to be equal or greater than ('vec_in.size()' / 'Nbps') "
60 : << "('vec_out.size()' = " << vec_out.size() << ", 'vec_in.size()' = " << vec_in.size()
61 : << ", 'Nbps' = " << Nbps << ").";
62 : throw length_error(__FILE__, __LINE__, __func__, message.str());
63 : }
64 :
65 : Bit_packer::pack(vec_in.data(), vec_out.data(), (int)(vec_in.size() / n_frames), n_frames, msb_to_lsb, Nbps);
66 : }
67 : }
68 :
69 : template<typename B, typename S>
70 : void
71 11763 : Bit_packer::pack(const B* vec_in,
72 : S* vec_out,
73 : const int n_bits_per_frame,
74 : const int n_frames,
75 : const bool msb_to_lsb,
76 : const int Nbps)
77 : {
78 11763 : if (Nbps > (int)(sizeof(S) * CHAR_BIT) || Nbps <= 0)
79 : {
80 0 : std::stringstream message;
81 0 : message << "'Nbps' must be between 1 and (sizeof(S) * CHAR_BIT). ('Nbps' = " << Nbps
82 0 : << ", 'sizeof(S)' = " << sizeof(S) << ", 'CHAR_BIT' = " << CHAR_BIT << ").";
83 0 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
84 0 : }
85 :
86 11763 : const auto n_symbols_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
87 :
88 23526 : for (auto f = 0; f < n_frames; f++)
89 11763 : Bit_packer::_pack(
90 11763 : vec_in + f * n_bits_per_frame, vec_out + f * n_symbols_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
91 11763 : }
92 :
93 : template<typename B, class AB>
94 : void
95 : Bit_packer::pack(std::vector<B, AB>& vec, const int n_frames, const bool msb_to_lsb, const int Nbps)
96 : {
97 : if (n_frames <= 0)
98 : {
99 : std::stringstream message;
100 : message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
101 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
102 : }
103 :
104 : if (vec.size() % n_frames)
105 : {
106 : std::stringstream message;
107 : message << "'vec.size()' has to be divisible by 'n_frames' ('vec.size()' = " << vec.size()
108 : << ", 'n_frames' = " << n_frames << ").";
109 : throw length_error(__FILE__, __LINE__, __func__, message.str());
110 : }
111 :
112 : Bit_packer::pack(vec.data(), (int)(vec.size() / n_frames), n_frames, msb_to_lsb, Nbps);
113 : }
114 :
115 : template<typename B>
116 : void
117 : Bit_packer::pack(B* vec, const int n_bits_per_frame, const int n_frames, const bool msb_to_lsb, const int Nbps)
118 : {
119 : if (Nbps > (int)CHAR_BIT || Nbps <= 0)
120 : {
121 : std::stringstream message;
122 : message << "'Nbps' must be between 1 and CHAR_BIT. ('Nbps' = " << Nbps << ").";
123 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
124 : }
125 :
126 : const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
127 :
128 : unsigned char* symbs_out = (unsigned char*)vec;
129 :
130 : for (auto f = 0; f < n_frames; f++)
131 : Bit_packer::_pack(
132 : vec + f * n_bits_per_frame, symbs_out + f * n_symbs_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
133 : }
134 :
135 : template<typename B, class AB, typename S, class AS>
136 : void
137 : Bit_packer::unpack(const std::vector<S, AS>& vec_in,
138 : std::vector<B, AB>& vec_out,
139 : const int n_frames,
140 : const bool msb_to_lsb,
141 : const bool unpack_per_byte,
142 : const int Nbps)
143 : {
144 : if (n_frames <= 0)
145 : {
146 : std::stringstream message;
147 : message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
148 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
149 : }
150 :
151 : if (vec_out.size() % n_frames)
152 : {
153 : std::stringstream message;
154 : message << "'vec_out.size()' has to be divisible by 'n_frames' ('vec_out.size()' = " << vec_out.size()
155 : << ", 'n_frames' = " << n_frames << ").";
156 : throw length_error(__FILE__, __LINE__, __func__, message.str());
157 : }
158 :
159 : if (unpack_per_byte)
160 : {
161 : if ((vec_in.size() * sizeof(B) * Nbps) < vec_out.size())
162 : {
163 : std::stringstream message;
164 : message << "('vec_in.size()' * 'sizeof(B)' * 'Nbps') has to be equal or greater than 'vec_out.size()' "
165 : << "('vec_in.size()' = " << vec_in.size() << ", 'vec_out.size()' = " << vec_out.size()
166 : << ", 'sizeof(B)' = " << sizeof(B) << ", 'Nbps' = " << Nbps << ").";
167 : throw length_error(__FILE__, __LINE__, __func__, message.str());
168 : }
169 :
170 : Bit_packer::unpack(
171 : (unsigned char*)vec_in.data(), vec_out.data(), (int)(vec_out.size() / n_frames), n_frames, msb_to_lsb, Nbps);
172 : }
173 : else
174 : {
175 : if ((vec_in.size() * Nbps) < vec_out.size())
176 : {
177 : std::stringstream message;
178 : message << "('vec_in.size()' * 'Nbps') has to be equal or greater than 'vec_out.size()' "
179 : << "('vec_in.size()' = " << vec_in.size() << ", 'vec_out.size()' = " << vec_out.size()
180 : << ", 'Nbps' = " << Nbps << ").";
181 : throw length_error(__FILE__, __LINE__, __func__, message.str());
182 : }
183 :
184 : Bit_packer::unpack(vec_in.data(), vec_out.data(), (int)(vec_out.size() / n_frames), n_frames, msb_to_lsb, Nbps);
185 : }
186 : }
187 :
188 : template<typename B, typename S>
189 : void
190 11749 : Bit_packer::unpack(const S* vec_in,
191 : B* vec_out,
192 : const int n_bits_per_frame,
193 : const int n_frames,
194 : const bool msb_to_lsb,
195 : const int Nbps)
196 : {
197 11749 : if (Nbps > (int)(sizeof(S) * CHAR_BIT) || Nbps <= 0)
198 : {
199 0 : std::stringstream message;
200 0 : message << "'Nbps' must be between 1 and (sizeof(S) * CHAR_BIT). ('Nbps' = " << Nbps
201 0 : << ", 'sizeof(S)' = " << sizeof(S) << ", 'CHAR_BIT' = " << CHAR_BIT << ").";
202 0 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
203 0 : }
204 :
205 11749 : const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
206 :
207 23498 : for (auto f = 0; f < n_frames; f++)
208 11749 : Bit_packer::_unpack(
209 11749 : vec_in + f * n_symbs_per_frame, vec_out + f * n_bits_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
210 11749 : }
211 :
212 : template<typename B, class AB>
213 : void
214 : Bit_packer::unpack(std::vector<B, AB>& vec, const int n_frames, const bool msb_to_lsb, const int Nbps)
215 : {
216 : if (n_frames <= 0)
217 : {
218 : std::stringstream message;
219 : message << "'n_frames' has to be greater than 0 ('n_frames' = " << n_frames << ").";
220 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
221 : }
222 :
223 : if (vec.size() % n_frames)
224 : {
225 : std::stringstream message;
226 : message << "'vec.size()' has to be divisible by 'n_frames' ('vec.size()' = " << vec.size()
227 : << ", 'n_frames' = " << n_frames << ").";
228 : throw length_error(__FILE__, __LINE__, __func__, message.str());
229 : }
230 :
231 : Bit_packer::unpack(vec.data(), (int)(vec.size() / n_frames), n_frames, msb_to_lsb, Nbps);
232 : }
233 :
234 : template<typename B>
235 : void
236 : Bit_packer::unpack(B* vec, const int n_bits_per_frame, const int n_frames, const bool msb_to_lsb, const int Nbps)
237 : {
238 : if (Nbps > (int)CHAR_BIT || Nbps <= 0)
239 : {
240 : std::stringstream message;
241 : message << "'Nbps' must be between 1 and CHAR_BIT. ('Nbps' = " << Nbps << ").";
242 : throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
243 : }
244 :
245 : const auto n_symbs_per_frame = static_cast<int>(std::ceil((float)n_bits_per_frame / Nbps));
246 :
247 : unsigned char* bytes = (unsigned char*)vec;
248 : std::vector<unsigned char> bytes_cpy(n_symbs_per_frame); // TODO: find a way to avoid this allocation
249 :
250 : for (auto f = 0; f < n_frames; f++)
251 : {
252 : // TODO: find a way to avoid this copy
253 : std::copy(&bytes[f * n_symbs_per_frame], &bytes[(f + 1) * n_symbs_per_frame], bytes_cpy.begin());
254 :
255 : Bit_packer::_unpack(
256 : bytes_cpy.data() + f * n_symbs_per_frame, vec + f * n_bits_per_frame, n_bits_per_frame, msb_to_lsb, Nbps);
257 : }
258 : }
259 :
260 : template<typename B, typename S>
261 : void
262 11763 : Bit_packer::_pack(const B* vec_in, S* symbs_out, const int n_bits, const bool msb_to_lsb, const int Nbps)
263 : {
264 11763 : const auto n_symbs = n_bits / Nbps;
265 11763 : const auto rest = n_bits - n_symbs * Nbps;
266 :
267 11763 : if (!msb_to_lsb) // lsb_to_msb
268 : {
269 127380 : for (auto i = 0; i < n_symbs; i++, symbs_out++)
270 : {
271 115617 : S symb = 0;
272 1040553 : for (auto j = 0; j < Nbps; j++, vec_in++)
273 924936 : symb |= ((S)(*vec_in != 0)) << j;
274 115617 : *symbs_out = symb;
275 : }
276 :
277 11763 : if (rest != 0)
278 : {
279 0 : S symb = 0;
280 0 : for (auto j = 0; j < rest; j++, vec_in++)
281 0 : symb |= ((S)(*vec_in != 0)) << j;
282 0 : *symbs_out = symb;
283 : }
284 : }
285 : else // msb_to_lsb
286 : {
287 0 : for (auto i = 0; i < n_symbs; i++, symbs_out++)
288 : {
289 0 : S symb = 0;
290 0 : for (auto j = 0; j < Nbps; j++, vec_in++)
291 0 : symb = (symb << 1) | (*vec_in != 0);
292 0 : *symbs_out = symb << (sizeof(S) * CHAR_BIT - Nbps);
293 : }
294 :
295 0 : if (rest != 0)
296 : {
297 0 : S symb = 0;
298 0 : for (auto j = 0; j < rest; j++, vec_in++)
299 0 : symb = (symb << 1) | (*vec_in != 0);
300 0 : *symbs_out = symb << (sizeof(S) * CHAR_BIT - rest);
301 : }
302 : }
303 11763 : }
304 :
305 : template<typename B, typename S>
306 : void
307 11749 : Bit_packer::_unpack(const S* symbs_in, B* vec_out, const int n_bits, const bool msb_to_lsb, const int Nbps)
308 : {
309 11749 : const auto n_symbs = n_bits / Nbps;
310 11749 : const auto rest = n_bits - n_symbs * Nbps;
311 :
312 11749 : if (!msb_to_lsb) // lsb_to_msb
313 : {
314 127366 : for (auto i = 0; i < n_symbs; i++, symbs_in++)
315 1040553 : for (auto j = 0; j < Nbps; j++, vec_out++)
316 924936 : *vec_out = (*symbs_in >> j) & (S)1;
317 :
318 11749 : for (auto j = 0; j < rest; j++, vec_out++)
319 0 : *vec_out = (*symbs_in >> j) & (S)1;
320 : }
321 : else // msb_to_lsb
322 : {
323 0 : for (auto i = 0; i < n_symbs; i++, symbs_in++)
324 0 : for (auto j = 0; j < Nbps; j++, vec_out++)
325 0 : *vec_out = (*symbs_in >> (sizeof(S) * CHAR_BIT - 1 - j)) & (S)1;
326 :
327 0 : for (auto j = 0; j < rest; j++, vec_out++)
328 0 : *vec_out = (*symbs_in >> (sizeof(S) * CHAR_BIT - 1 - j)) & (S)1;
329 : }
330 11749 : }
331 : }
332 : }
333 :
334 : /* Test code :
335 : #include "Tools/Algo/Bit_packer.hpp"
336 : #include "Tools/Display/Frame_trace/Frame_trace.hpp"
337 : #include <random>
338 : #include <string>
339 : #include <vector>
340 :
341 : int main(int argc, char** argv)
342 : {
343 : using namespace spu;
344 : using B = int;
345 : using S = short;
346 :
347 : std::random_device rd;
348 :
349 : size_t size_in = (argc >= 2) ? std::stoi(argv[1]) : 16;
350 : int Nbps = (argc >= 3) ? std::stoi(argv[2]) : CHAR_BIT;
351 : int n_frames = (argc >= 4) ? std::stoi(argv[3]) : 1;
352 : int msb_to_lsb = (argc >= 5) ? std::stoi(argv[4]) : 0;
353 : int pack_per_byte = (argc >= 6) ? std::stoi(argv[5]) : 1;
354 : int seed = (argc >= 7) ? std::stoi(argv[6]) : rd();
355 :
356 : size_t size_out = std::ceil(1.f * size_in / Nbps);
357 :
358 : std::vector<B> vec_in (size_in * n_frames);
359 : std::vector<S> vec_packed (size_out * n_frames);
360 : std::vector<B> vec_unpacked(size_in * n_frames);
361 :
362 : std::mt19937 gen(seed);
363 : std::bernoulli_distribution d(0.5);
364 :
365 : for (auto& v : vec_in)
366 : v = d(gen);
367 :
368 : tools::Frame_trace<> ft;
369 :
370 : std::cout << "Vec in" << std::endl;
371 : ft.display_bit_vector(vec_in, Nbps);
372 :
373 : tools::Bit_packer::pack(vec_in, vec_packed, n_frames, msb_to_lsb, pack_per_byte, Nbps);
374 :
375 : std::cout << "Vec packed" << std::endl;
376 :
377 : if (pack_per_byte)
378 : {
379 : std::vector<char> vec_char(vec_packed.size() * sizeof(S));
380 : std::copy_n((char*)vec_packed.data(), vec_char.size(), vec_char.data());
381 : ft.display_hex_vector(vec_char, size_out * sizeof(S));
382 : }
383 : else
384 : ft.display_hex_vector(vec_packed, size_out);
385 :
386 : tools::Bit_packer::unpack(vec_packed, vec_unpacked, n_frames, msb_to_lsb, pack_per_byte, Nbps);
387 :
388 : std::cout << "Vec unpacked" << std::endl;
389 : ft.display_bit_vector(vec_unpacked, Nbps);
390 :
391 : bool same = true;
392 : for (unsigned i = 0; i < vec_unpacked.size(); i++)
393 : same &= vec_unpacked[i] == vec_in[i];
394 :
395 : std::cout << "Same in and unpacked = " << same << std::endl;
396 : }
397 : */
|