lzw-assignment/src/bitpack.cc

178 lines
5.7 KiB
C++
Raw Normal View History

#include "bitpack.hh"
2018-06-09 21:11:27 +00:00
#include "common.hh"
#include <algorithm>
2018-06-15 17:54:00 +00:00
#include <cmath>
using std::uint16_t;
using std::vector;
using uchar = unsigned char;
using vuint16 = vector<uint16_t>;
using vuchar = vector<uchar>;
using ustring = std::basic_string<unsigned char>;
2019-08-19 14:40:13 +00:00
[[nodiscard]] int max(const int t_n) { return ipow(2, t_n) - 1; }
2018-06-17 04:38:57 +00:00
2019-08-19 14:40:13 +00:00
[[nodiscard]] constexpr uint16_t mask_n(int t_nb_bits) {
2018-06-17 04:38:57 +00:00
if (t_nb_bits == 0) {
return 0;
}
uint16_t mask = mask_n(t_nb_bits - 1);
mask = static_cast<uint16_t>(mask << 1);
mask |= 0x1;
return mask;
2018-06-15 21:08:17 +00:00
}
2018-06-17 04:38:57 +00:00
constexpr uint16_t masks[17] = {
mask_n(0), mask_n(1), mask_n(2), mask_n(3), mask_n(4), mask_n(5),
mask_n(6), mask_n(7), mask_n(8), mask_n(9), mask_n(10), mask_n(11),
mask_n(12), mask_n(13), mask_n(14), mask_n(15), mask_n(16)};
2018-06-09 20:59:11 +00:00
///////////////////////////////////////////////////////////////////////////////
// packing //
///////////////////////////////////////////////////////////////////////////////
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuchar pack(const vuint16 &t_input) {
2018-06-21 15:38:51 +00:00
vuchar vec{};
return pack_n(t_input.begin(), t_input.end(), vec, 9);
2018-06-09 20:59:11 +00:00
}
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuchar pack_n(const vuint16::const_iterator t_input_begin,
const vuint16::const_iterator t_input_end,
vuchar &t_res, int t_n) {
if (t_n == 16) {
2018-06-21 15:38:51 +00:00
return pack_16(t_input_begin, t_input_end, t_res);
}
2018-06-15 21:08:17 +00:00
const int max_value = max(t_n); // max value held within t_n bits
2018-06-17 04:38:57 +00:00
int step = t_n % 8;
int left_shift = 0;
int right_shift = 0;
2018-06-15 17:54:00 +00:00
uchar current_char = 0;
bool char_touched = false;
2018-06-17 04:38:57 +00:00
// pour chaque élément
for (auto it = t_input_begin; it != t_input_end; ++it) {
2018-06-21 15:38:51 +00:00
// si on a atteint ou dépassé la valeur maximale, on change de nombre de
// bits
if (*it >= max_value) {
2018-06-21 15:38:51 +00:00
// écriture du masque pour notifier à la décompression du changement de
// bits
if ((left_shift += step) >= t_n) {
left_shift = (left_shift - t_n) + step;
}
const auto mask = masks[t_n] >> left_shift;
2018-06-21 15:38:51 +00:00
t_res.push_back(static_cast<uchar>(current_char | mask));
bool zero_rs = (right_shift == 0);
right_shift -= step;
2018-11-21 00:49:30 +00:00
if (right_shift < 0 && !zero_rs) {
// si right_shift est inférieur à zéro
// si right_shift était différent de zéro, alors extra octet
2018-11-21 00:49:30 +00:00
current_char = static_cast<uchar>(masks[t_n] >> (-right_shift) & 0xFFU);
t_res.push_back(current_char);
}
t_res.push_back(static_cast<uchar>(masks[t_n]));
return pack_n(it, t_input_end, t_res, t_n + 1);
}
2018-06-17 04:38:57 +00:00
// écriture normale
2018-06-15 17:54:00 +00:00
if ((left_shift += step) >= t_n) {
left_shift = (left_shift - t_n) + step;
}
2018-06-17 04:38:57 +00:00
t_res.push_back(
2018-11-21 00:49:30 +00:00
static_cast<uchar>(current_char | (*it >> left_shift & 0xFFU)));
2018-06-17 04:38:57 +00:00
bool zero_rs = (right_shift == 0);
right_shift -= step;
if (right_shift < 0) {
2018-06-17 04:38:57 +00:00
if (!zero_rs) {
2018-11-21 00:49:30 +00:00
current_char = static_cast<uchar>(*it >> (-right_shift) & 0xFFU);
2018-06-17 04:38:57 +00:00
t_res.push_back(current_char);
}
2018-06-17 04:38:57 +00:00
right_shift = 8 + right_shift;
}
if (right_shift == 0) {
2018-11-21 00:49:30 +00:00
current_char = static_cast<uchar>(*it & 0xFFU);
2018-06-17 04:38:57 +00:00
t_res.push_back(current_char);
current_char = 0;
2018-06-15 17:54:00 +00:00
char_touched = false;
} else {
2018-11-21 00:49:30 +00:00
current_char = static_cast<uchar>(*it << right_shift & 0xFFU);
2018-06-15 17:54:00 +00:00
char_touched = true;
}
}
2018-06-15 17:54:00 +00:00
if (char_touched) {
2018-06-17 04:38:57 +00:00
t_res.push_back(current_char);
}
2018-06-17 04:38:57 +00:00
return t_res;
}
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuchar pack_16(const vuint16::const_iterator t_input_begin,
const vuint16::const_iterator t_input_end,
vuchar &t_res) {
2018-11-21 00:49:30 +00:00
std::for_each(t_input_begin, t_input_end, [&t_res](const auto value) {
t_res.push_back(static_cast<uchar>(value >> 8 & 0xFFU));
t_res.push_back(static_cast<uchar>(value & 0xFFU));
});
2018-06-17 04:38:57 +00:00
return t_res;
}
///////////////////////////////////////////////////////////////////////////////
2018-06-10 22:58:01 +00:00
// unpacking //
///////////////////////////////////////////////////////////////////////////////
2018-06-09 20:59:11 +00:00
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuint16 unpack(ustring &&t_input) {
2018-06-21 15:38:51 +00:00
vuint16 vec{};
return unpack_n(t_input.begin(), t_input.end(), vec, 9);
2018-06-09 20:59:11 +00:00
}
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuint16 unpack_n(const ustring::const_iterator t_begin,
const ustring::const_iterator t_end,
vuint16 &t_res, int t_n) {
2018-06-15 17:54:00 +00:00
if (t_n == 16) {
2018-06-21 15:38:51 +00:00
return unpack_16(t_begin, t_end, t_res);
2018-06-15 17:54:00 +00:00
}
2018-06-17 04:38:57 +00:00
int step = t_n % 8;
2018-06-09 20:59:11 +00:00
int left_shift = 0;
int right_shift = 0;
2018-06-15 21:08:17 +00:00
const int max_value = max(t_n);
2018-06-11 14:34:35 +00:00
for (auto it = t_begin; it < t_end - 1; /* nope */) {
2018-06-09 20:59:11 +00:00
uint16_t current_char = 0;
// left bits
if ((left_shift += step) >= t_n) {
left_shift = (left_shift - t_n) + step;
}
2018-06-17 04:38:57 +00:00
current_char = static_cast<uint16_t>(*it << left_shift) & masks[t_n];
// right bits
2018-06-17 04:38:57 +00:00
bool zero_rs = (right_shift == 0);
2018-06-09 20:59:11 +00:00
right_shift -= step;
if (right_shift < 0) {
2018-06-17 04:38:57 +00:00
// if previous right shift was negative and not zero
if (!zero_rs) {
current_char |= *++it << (-right_shift) & masks[16 + right_shift];
2018-06-09 20:59:11 +00:00
}
2018-06-15 17:54:00 +00:00
right_shift = 8 + right_shift;
2018-06-09 20:59:11 +00:00
}
2018-06-17 04:38:57 +00:00
current_char |= *++it >> right_shift & masks[8 - right_shift];
// char made!
2018-06-17 04:38:57 +00:00
if (current_char >= max_value) { // if it is the mask
return unpack_n(it + 1, t_end, t_res, t_n + 1);
2018-06-09 20:59:11 +00:00
}
2018-11-21 00:49:30 +00:00
current_char &= masks[t_n];
t_res.push_back(current_char);
2018-06-15 17:54:00 +00:00
if (right_shift == 0) {
++it;
}
2018-06-09 20:59:11 +00:00
}
2018-06-17 04:38:57 +00:00
return t_res;
2018-06-09 20:59:11 +00:00
}
2019-08-19 14:40:13 +00:00
[[nodiscard]] vuint16 unpack_16(const ustring::const_iterator t_begin,
const ustring::const_iterator t_end,
vuint16 &t_res) {
2018-06-09 20:59:11 +00:00
for (auto it = t_begin; it < t_end; ++it) {
2018-06-17 04:38:57 +00:00
t_res.push_back(static_cast<uint16_t>(*it << 8 | *++it));
}
2018-06-17 04:38:57 +00:00
return t_res;
}