better, but still some bugs
This commit is contained in:
parent
bae6d01bc8
commit
8777183821
256
src/bitpack.cc
256
src/bitpack.cc
@ -10,108 +10,7 @@ using vuint16 = vector<uint16_t>;
|
|||||||
using vuchar = vector<uchar>;
|
using vuchar = vector<uchar>;
|
||||||
using ustring = std::basic_string<unsigned char>;
|
using ustring = std::basic_string<unsigned char>;
|
||||||
|
|
||||||
int max(const int t_n) {
|
int max(const int t_n) { return ipow(2, t_n) - 1; }
|
||||||
return ipow(2, t_n) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// packing //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
vuchar pack(const vuint16 &t_input) {
|
|
||||||
return pack_n(t_input.begin(), t_input.end(), 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packs \p t_input into unsigned char, assuming the max value of t_input
|
|
||||||
* only takes \p t_n bits
|
|
||||||
*
|
|
||||||
* \param t_input_begin pointer to the beginning of the vector of values to be packed
|
|
||||||
* \param t_input_end pointer to the end of the input vector
|
|
||||||
* \param t_n maximum size of an input value in bits
|
|
||||||
* \return Returns a vector of unsigned char containing the packed values from t_input
|
|
||||||
*/
|
|
||||||
vuchar pack_n(const vuint16::const_iterator t_input_begin,
|
|
||||||
const vuint16::const_iterator t_input_end, const int t_n) {
|
|
||||||
if (t_n == 16) {
|
|
||||||
return pack_16(t_input_begin, t_input_end);
|
|
||||||
}
|
|
||||||
const int max_value = max(t_n); // max value held within t_n bits
|
|
||||||
|
|
||||||
#ifdef Debug
|
|
||||||
std::printf("%d bits! %ld chars remaining\n", t_n,
|
|
||||||
std::distance(t_input_begin, t_input_end));
|
|
||||||
std::printf("max: %d\n", max_value);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int step = t_n / 8;
|
|
||||||
int left_shift = 0;
|
|
||||||
int middle_shift = 0;
|
|
||||||
int right_shift = 0;
|
|
||||||
uchar current_char = 0;
|
|
||||||
bool char_touched = false;
|
|
||||||
vuchar ret{};
|
|
||||||
|
|
||||||
for (auto it = t_input_begin; it != t_input_end; ++it) {
|
|
||||||
if ((left_shift += step) >= t_n) {
|
|
||||||
left_shift = (left_shift - t_n) + step;
|
|
||||||
}
|
|
||||||
ret.push_back((current_char | (*it >> left_shift)) & 0xFFu);
|
|
||||||
// current_char = 0;
|
|
||||||
|
|
||||||
bool zero_right_shift = (right_shift == 0);
|
|
||||||
right_shift -= step;
|
|
||||||
if (right_shift < 0) {
|
|
||||||
middle_shift = std::abs(right_shift);
|
|
||||||
right_shift = 8 - std::abs(right_shift);
|
|
||||||
if (!zero_right_shift) {
|
|
||||||
current_char = (*it >> middle_shift) & 0xFFu;
|
|
||||||
ret.push_back(current_char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (right_shift == 0) {
|
|
||||||
current_char = *it & 0xffu;
|
|
||||||
ret.push_back(current_char);
|
|
||||||
current_char = 0;
|
|
||||||
char_touched = false;
|
|
||||||
} else {
|
|
||||||
current_char = (*it << right_shift) & 0xFFu;
|
|
||||||
char_touched = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// il faut écrire la valeur pour la décompression
|
|
||||||
if (*it >= max_value) {
|
|
||||||
if (char_touched) {
|
|
||||||
ret.push_back(current_char);
|
|
||||||
}
|
|
||||||
const auto next_vec = pack_n(it, t_input_end, t_n + 1);
|
|
||||||
ret.insert(ret.end(), next_vec.begin(), next_vec.end());
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (char_touched) {
|
|
||||||
ret.push_back(current_char);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
vuchar pack_16(const vuint16::const_iterator t_input_begin,
|
|
||||||
const vuint16::const_iterator t_input_end) {
|
|
||||||
#ifdef Debug
|
|
||||||
std::printf("16 bits! %ld chars remaining\n",
|
|
||||||
std::distance(t_input_begin, t_input_end));
|
|
||||||
#endif
|
|
||||||
vuchar ret{};
|
|
||||||
std::for_each(t_input_begin, t_input_end, [&](const auto value) {
|
|
||||||
ret.push_back((value >> 8) & 0xFFu);
|
|
||||||
ret.push_back(value & 0xFFu);
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// unpacking //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
constexpr uint16_t mask_n(int t_nb_bits) {
|
constexpr uint16_t mask_n(int t_nb_bits) {
|
||||||
if (t_nb_bits == 0) {
|
if (t_nb_bits == 0) {
|
||||||
@ -128,60 +27,167 @@ constexpr uint16_t masks[17] = {
|
|||||||
mask_n(6), mask_n(7), mask_n(8), mask_n(9), mask_n(10), mask_n(11),
|
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)};
|
mask_n(12), mask_n(13), mask_n(14), mask_n(15), mask_n(16)};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// packing //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
vuchar pack(const vuint16 &t_input) {
|
||||||
|
return pack_n(t_input.begin(), t_input.end(), vuchar{}, 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packs \p t_input into unsigned char, assuming the max value of t_input
|
||||||
|
* only takes \p t_n bits
|
||||||
|
*
|
||||||
|
* \param t_input_begin pointer to the beginning of the vector of values to be
|
||||||
|
* packed \param t_input_end pointer to the end of the input vector \param t_n
|
||||||
|
* maximum size of an input value in bits \return Returns a vector of unsigned
|
||||||
|
* char containing the packed values from t_input
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
return pack_16(t_input_begin, t_input_end, vector<unsigned char>());
|
||||||
|
}
|
||||||
|
const int max_value = max(t_n); // max value held within t_n bits
|
||||||
|
|
||||||
|
#ifdef Debug
|
||||||
|
std::printf("%d bits! %ld chars remaining\n", t_n,
|
||||||
|
std::distance(t_input_begin, t_input_end));
|
||||||
|
std::printf("max: %d\n", max_value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int step = t_n % 8;
|
||||||
|
int left_shift = 0;
|
||||||
|
int right_shift = 0;
|
||||||
|
uchar current_char = 0;
|
||||||
|
bool char_touched = false;
|
||||||
|
|
||||||
|
// pour chaque élément
|
||||||
|
for (auto it = t_input_begin; it != t_input_end; ++it) {
|
||||||
|
|
||||||
|
// si on a atteint ou dépassé la valeur maximale, on change de nombre de bits
|
||||||
|
if (*it >= max_value) {
|
||||||
|
// é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;
|
||||||
|
t_res.push_back(
|
||||||
|
static_cast<uchar>(current_char | mask));
|
||||||
|
bool zero_rs = (right_shift == 0);
|
||||||
|
right_shift -= 0;
|
||||||
|
if(right_shift < 0) {
|
||||||
|
if(!zero_rs) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((left_shift += step) >= t_n) {
|
||||||
|
left_shift = (left_shift - t_n) + step;
|
||||||
|
}
|
||||||
|
t_res.push_back(
|
||||||
|
static_cast<uchar>(current_char | (*it >> left_shift & 0xFFu)));
|
||||||
|
// current_char = 0;
|
||||||
|
|
||||||
|
bool zero_rs = (right_shift == 0);
|
||||||
|
right_shift -= step;
|
||||||
|
if (right_shift < 0) {
|
||||||
|
if (!zero_rs) {
|
||||||
|
current_char = static_cast<uchar>(*it >> (-right_shift) & 0xFFu);
|
||||||
|
t_res.push_back(current_char);
|
||||||
|
}
|
||||||
|
right_shift = 8 + right_shift;
|
||||||
|
}
|
||||||
|
if (right_shift == 0) {
|
||||||
|
current_char = static_cast<uchar>(*it & 0xffu);
|
||||||
|
t_res.push_back(current_char);
|
||||||
|
current_char = 0;
|
||||||
|
char_touched = false;
|
||||||
|
} else {
|
||||||
|
current_char = static_cast<uchar>(*it << right_shift & 0xFFu);
|
||||||
|
char_touched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (char_touched) {
|
||||||
|
t_res.push_back(current_char);
|
||||||
|
}
|
||||||
|
return t_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
vuchar pack_16(const vuint16::const_iterator t_input_begin,
|
||||||
|
const vuint16::const_iterator t_input_end, vuchar t_res) {
|
||||||
|
#ifdef Debug
|
||||||
|
std::printf("16 bits! %ld chars remaining\n",
|
||||||
|
std::distance(t_input_begin, t_input_end));
|
||||||
|
#endif
|
||||||
|
std::for_each(t_input_begin, t_input_end, [&](const auto value) {
|
||||||
|
t_res.push_back((value >> 8) & 0xFFu);
|
||||||
|
t_res.push_back(value & 0xFFu);
|
||||||
|
});
|
||||||
|
return t_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// unpacking //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
vuint16 unpack(ustring &&t_input) {
|
vuint16 unpack(ustring &&t_input) {
|
||||||
return unpack_n(t_input.begin(), t_input.end(), 9);
|
return unpack_n(t_input.begin(), t_input.end(), vuint16{}, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
vuint16 unpack_n(const ustring::const_iterator t_begin,
|
vuint16 unpack_n(const ustring::const_iterator t_begin,
|
||||||
const ustring::const_iterator t_end, const int t_n) {
|
const ustring::const_iterator t_end, vuint16 t_res, int t_n) {
|
||||||
#ifdef Debug
|
#ifdef Debug
|
||||||
std::printf("Chunk! %d bits, %ld compressed chars\n", t_n,
|
std::printf("Chunk! %d bits, %ld compressed chars\n", t_n,
|
||||||
std::distance(t_begin, t_end));
|
std::distance(t_begin, t_end));
|
||||||
#endif
|
#endif
|
||||||
if (t_n == 16) {
|
if (t_n == 16) {
|
||||||
return unpack_16(t_begin, t_end);
|
return unpack_16(t_begin, t_end, vector<uint16_t>());
|
||||||
}
|
}
|
||||||
int step = t_n / 8;
|
int step = t_n % 8;
|
||||||
int left_shift = 0;
|
int left_shift = 0;
|
||||||
int right_shift = 0;
|
int right_shift = 0;
|
||||||
vuint16 ret{};
|
|
||||||
const int max_value = max(t_n);
|
const int max_value = max(t_n);
|
||||||
for (auto it = t_begin; it < t_end - 1; /* nope */) {
|
for (auto it = t_begin; it < t_end - 1; /* nope */) {
|
||||||
uint16_t current_char = 0;
|
uint16_t current_char = 0;
|
||||||
// left bits
|
// left bits
|
||||||
left_shift =
|
if ((left_shift += step) >= t_n) {
|
||||||
((left_shift += step) >= t_n) ? (left_shift - t_n) + step : left_shift;
|
left_shift = (left_shift - t_n) + step;
|
||||||
current_char = static_cast<uint16_t>(*it << left_shift);
|
}
|
||||||
|
current_char = static_cast<uint16_t>(*it << left_shift) & masks[t_n];
|
||||||
// right bits
|
// right bits
|
||||||
bool zero_rs = right_shift;
|
bool zero_rs = (right_shift == 0);
|
||||||
right_shift -= step;
|
right_shift -= step;
|
||||||
if (right_shift < 0) {
|
if (right_shift < 0) {
|
||||||
// optional middle bits before right bits
|
// if previous right shift was negative and not zero
|
||||||
if (zero_rs) {
|
if (!zero_rs) {
|
||||||
current_char |= *++it << (-right_shift);
|
current_char |= *++it << (-right_shift) & masks[16 + right_shift];
|
||||||
}
|
}
|
||||||
right_shift = 8 + right_shift;
|
right_shift = 8 + right_shift;
|
||||||
}
|
}
|
||||||
current_char |= *(++it) >> right_shift;
|
current_char |= *++it >> right_shift & masks[8 - right_shift];
|
||||||
// char made!
|
// char made!
|
||||||
ret.push_back(current_char &= masks[t_n]);
|
if (current_char >= max_value) { // if it is the mask
|
||||||
if (current_char >= max_value) {
|
return unpack_n(it + 1, t_end, t_res, t_n + 1);
|
||||||
const auto next_vec = unpack_n(it + 1, t_end, t_n + 1);
|
|
||||||
ret.insert(ret.end(), next_vec.begin(), next_vec.end());
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
t_res.push_back(current_char &= masks[t_n]);
|
||||||
if (right_shift == 0) {
|
if (right_shift == 0) {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return t_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
vuint16 unpack_16(const ustring::const_iterator t_begin,
|
vuint16 unpack_16(const ustring::const_iterator t_begin,
|
||||||
const ustring::const_iterator t_end) {
|
const ustring::const_iterator t_end, vuint16 t_res) {
|
||||||
vuint16 ret{};
|
|
||||||
for (auto it = t_begin; it < t_end; ++it) {
|
for (auto it = t_begin; it < t_end; ++it) {
|
||||||
ret.push_back(static_cast<uint16_t>((*it << 8) | *(++it)));
|
t_res.push_back(static_cast<uint16_t>(*it << 8 | *++it));
|
||||||
}
|
}
|
||||||
return ret;
|
return t_res;
|
||||||
}
|
}
|
||||||
|
@ -15,22 +15,24 @@ std::vector<unsigned char> pack(const std::vector<std::uint16_t> &);
|
|||||||
|
|
||||||
/// \brief Packs std::uint16_t of n bits into unsigned char
|
/// \brief Packs std::uint16_t of n bits into unsigned char
|
||||||
std::vector<unsigned char>
|
std::vector<unsigned char>
|
||||||
pack_n(const std::vector<std::uint16_t>::const_iterator,
|
pack_n(std::vector<std::uint16_t>::const_iterator , std::vector<std::uint16_t>::const_iterator ,
|
||||||
const std::vector<std::uint16_t>::const_iterator, const int);
|
std::vector<unsigned char> , int );
|
||||||
|
|
||||||
/// \brief Specialization of \ref pack_n for 16bits
|
/// \brief Specialization of \ref pack_n for 16bits
|
||||||
std::vector<unsigned char>
|
std::vector<unsigned char>
|
||||||
pack_16(const std::vector<std::uint16_t>::const_iterator,
|
pack_16(std::vector<std::uint16_t>::const_iterator , std::vector<std::uint16_t>::const_iterator ,
|
||||||
const std::vector<std::uint16_t>::const_iterator);
|
std::vector<unsigned char> );
|
||||||
|
|
||||||
std::vector<std::uint16_t> unpack(std::basic_string<unsigned char> &&);
|
std::vector<std::uint16_t> unpack(std::basic_string<unsigned char> &&);
|
||||||
|
|
||||||
std::vector<std::uint16_t>
|
std::vector<std::uint16_t>
|
||||||
unpack_n(const std::basic_string<unsigned char>::const_iterator,
|
unpack_n(std::basic_string<unsigned char>::const_iterator t_begin,
|
||||||
const std::basic_string<unsigned char>::const_iterator, const int t_n);
|
std::basic_string<unsigned char>::const_iterator t_end,
|
||||||
|
std::vector<std::uint16_t> t_res, int t_n);
|
||||||
|
|
||||||
std::vector<std::uint16_t>
|
std::vector<std::uint16_t>
|
||||||
unpack_16(const std::basic_string<unsigned char>::const_iterator,
|
unpack_16(std::basic_string<unsigned char>::const_iterator,
|
||||||
const std::basic_string<unsigned char>::const_iterator);
|
std::basic_string<unsigned char>::const_iterator,
|
||||||
|
std::vector<std::uint16_t>);
|
||||||
|
|
||||||
#endif /* LZW_SRC_BITPACK_H_ */
|
#endif /* LZW_SRC_BITPACK_H_ */
|
||||||
|
@ -24,6 +24,9 @@ ustring lzw_uncompress(vuint16 &&t_compressed) {
|
|||||||
for (auto it = t_compressed.begin() + 1; it != t_compressed.end(); ++it) {
|
for (auto it = t_compressed.begin() + 1; it != t_compressed.end(); ++it) {
|
||||||
v = *it;
|
v = *it;
|
||||||
const auto uncompressed{dico_uncompress(dict, v, old)};
|
const auto uncompressed{dico_uncompress(dict, v, old)};
|
||||||
|
#ifdef Debug
|
||||||
|
std::printf("%d = %s\n", v, uncompressed.c_str());
|
||||||
|
#endif
|
||||||
ret.insert(ret.end(), uncompressed.begin(), uncompressed.end());
|
ret.insert(ret.end(), uncompressed.begin(), uncompressed.end());
|
||||||
old = v;
|
old = v;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user