diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c81f5b..7d6d2be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(TGT "projet_lzw") set(${TGT}_VERSION_MAJOR 0) set(${TGT}_VERSION_MINOR 1) -set(CXX_COVERAGE_COMPILE_FLAGS "-pedantic -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -Wfloat-equal -Wwrite-strings -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion -Wsign-conversion -Wshadow -Weffc++ -Wredundant-decls -Wdouble-promotion -Winit-self -Wswitch-default -Wswitch-enum -Wundef -Winline -Wunused -Wnon-virtual-dtor -pthread") +set(CXX_COVERAGE_COMPILE_FLAGS "-pedantic -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -Wfloat-equal -Wwrite-strings -Wpointer-arith -Wcast-qual -Wcast-align -Wshadow -Weffc++ -Wredundant-decls -Wdouble-promotion -Winit-self -Wswitch-default -Wswitch-enum -Wundef -Winline -Wunused -Wnon-virtual-dtor -Wno-conversion -pthread") set(CMAKE_CXX_FLAGS_DEBUG "${CXX_COVERAGE_COMPILE_FLAGS} -DDebug -g -pg") set(CMAKE_CXX_FLAGS_RELEASE "${CXX_COVERAGE_COMPILE_FLAGS} -O3") diff --git a/src/bitpack.cc b/src/bitpack.cc index 2a508ce..0cbf556 100644 --- a/src/bitpack.cc +++ b/src/bitpack.cc @@ -10,103 +10,483 @@ using vuint16 = vector; using vuchar = vector; using ustring = std::basic_string; -int max(const int t_n) { - return ipow(2, t_n) - 1; -} +int max(const int t_n) { return ipow(2, t_n) - 1; } /////////////////////////////////////////////////////////////////////////////// // packing // /////////////////////////////////////////////////////////////////////////////// vuchar pack(const vuint16 &t_input) { - return pack_n(t_input.begin(), t_input.end(), 9); + return pack_9(t_input.begin(), t_input.end()); } -/** - * 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 - +vuchar pack_9(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end) { #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); + std::printf("9 bits\n"); #endif - - int step = t_n / 8; - int left_shift = 0; - int middle_shift = 0; - int right_shift = 0; + vuchar res{}; 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; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 8) { + case 0: { + res.push_back(static_cast(*it >> 1u & 0xffu)); + current_char = static_cast(*it << 7u & 0xffu); + break; } - 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); + case 1: { + res.push_back( + static_cast(current_char | (*it >> 2u & 0xffu))); + current_char = static_cast(*it << 6u & 0xffu); + break; + } + case 2: { + res.push_back( + static_cast(current_char | (*it >> 3u & 0xffu))); + current_char = static_cast(*it << 5u & 0xffu); + break; + } + case 3: { + res.push_back( + static_cast(current_char | (*it >> 4u & 0xffu))); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 4: { + res.push_back( + static_cast(current_char | (*it >> 5u & 0xffu))); + current_char = static_cast(*it << 3u & 0xffu); + break; + } + case 5: { + res.push_back( + static_cast(current_char | (*it >> 6u & 0xffu))); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 6: { + res.push_back( + static_cast(current_char | (*it >> 7u & 0xffu))); + current_char = static_cast(*it << 1u & 0xffu); + break; + } + case 7: { + res.push_back( + static_cast(current_char | (*it >> 8u & 0xffu))); + res.push_back(static_cast(*it & 0xffu)); + break; + } + default: + exit(2); + } + if (*it >= max(9)) { + if(round % 8 != 0) { + res.push_back(current_char); } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), res.size()); +#endif + return pack_10(++it, t_end, res); } - 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; - } + ++round; } - if (char_touched) { - ret.push_back(current_char); - } - return ret; + res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), res.size()); +#endif + return res; } -vuchar pack_16(const vuint16::const_iterator t_input_begin, - const vuint16::const_iterator t_input_end) { +vuchar pack_10(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { #ifdef Debug - std::printf("16 bits! %ld chars remaining\n", - std::distance(t_input_begin, t_input_end)); + std::printf("10 bits\n"); #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; + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 4) { + case 0: { + t_res.push_back(static_cast(*it >> 2u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 4u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 2: { + t_res.push_back(current_char | static_cast(*it >> 6u & 0xffu)); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 3: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + t_res.push_back(static_cast(*it & 0xffu)); + break; + } + default: + exit(2); + } + if (*it >= max(10)) { + if(round % 4 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_11(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_11(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { +#ifdef Debug + std::printf("11 bits\n"); +#endif + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 8) { + case 0: { + t_res.push_back(static_cast(*it >> 3u & 0xffu)); + current_char = static_cast(*it << 5u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 6u & 0xffu)); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 2: { + t_res.push_back(current_char | static_cast(*it >> 11u & 0xffu)); + t_res.push_back(static_cast(*it << 1 & 0xffu)); + current_char = static_cast(*it << 7u & 0xffu); + break; + } + case 3: { + t_res.push_back(current_char | static_cast(*it >> 12u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 4: { + t_res.push_back(current_char | static_cast(*it >> 7u & 0xffu)); + current_char = static_cast((*it << 1u) & 0xffu); + break; + } + case 5: { + t_res.push_back(current_char | static_cast(*it >> 10u & 0xffu)); + t_res.push_back(static_cast(*it >> 2u & 0xffu)); + current_char = static_cast(*it << 6u & 0xffu); + break; + } + case 6: { + t_res.push_back(current_char | static_cast(*it >> 5u & 0xffu)); + current_char = static_cast(*it << 3u & 0xffu); + break; + } + case 7: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + current_char = static_cast(*it & 0xffu); + break; + } + default: + exit(2); + } + if (*it >= max(11)) { + if(round % 8 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_12(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_12(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { +#ifdef Debug + std::printf("12 bits\n"); +#endif + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 2) { + case 0: { + t_res.push_back(static_cast(*it >> 4u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + current_char = static_cast(*it & 0xffu); + break; + } + default: + exit(2); + } + if (*it >= max(12)) { + if(round % 2 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_13(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_13(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { +#ifdef Debug + std::printf("13 bits\n"); +#endif + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 8) { + case 0: { + t_res.push_back(static_cast(*it >> 5u & 0xffu)); + current_char = static_cast(*it << 3u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 10u & 0xffu)); + t_res.push_back(static_cast(*it >> 2u & 0xffu)); + current_char = static_cast(*it << 6u & 0xffu); + break; + } + case 2: { + t_res.push_back(current_char | static_cast(*it >> 7u & 0xffu)); + current_char = static_cast(*it << 1u & 0xffu); + break; + } + case 3: { + t_res.push_back(current_char | static_cast(*it >> 12u & 0xffu)); + t_res.push_back(static_cast(*it >> 4u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 4: { + t_res.push_back(current_char | static_cast(*it >> 9u & 0xffu)); + t_res.push_back(static_cast(*it >> 1u & 0xffu)); + current_char = static_cast(*it << 7u & 0xffu); + break; + } + case 5: { + t_res.push_back(current_char | static_cast(*it >> 6u & 0xffu)); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 6: { + t_res.push_back(current_char | static_cast(*it >> 11u & 0xffu)); + t_res.push_back(static_cast(*it >> 3u & 0xffu)); + current_char = static_cast(*it << 5u & 0xffu); + break; + } + case 7: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + current_char = static_cast(*it & 0xffu); + break; + } + default: + exit(2); + } + if (*it >= max(13)) { + if(round % 8 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_14(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_14(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { +#ifdef Debug + std::printf("14 bits\n"); +#endif + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 4) { + case 0: { + t_res.push_back(current_char | static_cast(*it >> 6u & 0xffu)); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 12u & 0xffu)); + t_res.push_back(static_cast(*it >> 4u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 2: { + t_res.push_back(current_char | static_cast(*it >> 10u & 0xffu)); + t_res.push_back(static_cast(*it >> 2u & 0xffu)); + current_char = static_cast(*it << 6u & 0xffu); + break; + } + case 3: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + current_char = static_cast(*it & 0xffu); + break; + } + default: + exit(2); + } + if (*it >= max(14)) { + if(round % 4 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_15(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_15(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { +#ifdef Debug + std::printf("15 bits\n"); +#endif + uchar current_char = 0; + int round = 0; + for (auto it = t_input; it != t_end; ++it) { + switch (round % 8) { + case 0: { + t_res.push_back(current_char | static_cast(*it >> 7u & 0xffu)); + current_char = static_cast(*it << 1u & 0xffu); + break; + } + case 1: { + t_res.push_back(current_char | static_cast(*it >> 14u & 0xffu)); + t_res.push_back(static_cast(*it >> 6u & 0xffu)); + current_char = static_cast(*it << 2u & 0xffu); + break; + } + case 2: { + t_res.push_back(current_char | static_cast(*it >> 13u & 0xffu)); + t_res.push_back(static_cast(*it >> 5u & 0xffu)); + current_char = static_cast(*it << 3u & 0xffu); + break; + } + case 3: { + t_res.push_back(current_char | static_cast(*it >> 12u & 0xffu)); + t_res.push_back(static_cast(*it >> 4u & 0xffu)); + current_char = static_cast(*it << 4u & 0xffu); + break; + } + case 4: { + t_res.push_back(current_char | static_cast(*it >> 11u & 0xffu)); + t_res.push_back(static_cast(*it >> 3u & 0xffu)); + current_char = static_cast(*it << 5u & 0xffu); + break; + } + case 5: { + t_res.push_back(current_char | static_cast(*it >> 10u & 0xffu)); + t_res.push_back(static_cast(*it >> 2u & 0xffu)); + current_char = static_cast(*it << 6u & 0xffu); + break; + } + case 6: { + t_res.push_back(current_char | static_cast(*it >> 9u & 0xffu)); + t_res.push_back(static_cast(*it >> 1u & 0xffu)); + current_char = static_cast(*it << 7u & 0xffu); + break; + } + case 7: { + t_res.push_back(current_char | static_cast(*it >> 8u & 0xffu)); + current_char = static_cast(*it & 0xffu); + break; + } + default: + exit(2); + } + if (*it >= max(15)) { + if(round % 8 != 0) { + t_res.push_back(current_char); + } +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return pack_16(++it, t_end, t_res); + } + ++round; + } + t_res.push_back(current_char); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; +} + +vuchar pack_16(const vuint16::const_iterator t_input, + const vuint16::const_iterator t_end, vuchar &t_res) { + std::for_each(t_input, t_end, [&](const auto value) { + t_res.push_back(static_cast(value >> 8 & 0xFFu)); + t_res.push_back(static_cast(value & 0xFFu)); + }); +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, t_end), t_res.size()); +#endif + return t_res; } /////////////////////////////////////////////////////////////////////////////// @@ -129,59 +509,452 @@ constexpr uint16_t masks[17] = { mask_n(12), mask_n(13), mask_n(14), mask_n(15), mask_n(16)}; vuint16 unpack(ustring &&t_input) { - return unpack_n(t_input.begin(), t_input.end(), 9); + return unpack_9(t_input.begin(), t_input.end()); } -vuint16 unpack_n(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end, const int t_n) { +vuint16 unpack_9(const ustring::const_iterator t_input, + const ustring::const_iterator t_end) { #ifdef Debug - std::printf("Chunk! %d bits, %ld compressed chars\n", t_n, - std::distance(t_begin, t_end)); + std::printf("9 bits\n"); #endif - if (t_n == 16) { - return unpack_16(t_begin, t_end); - } - int step = t_n / 8; - int left_shift = 0; - int right_shift = 0; - vuint16 ret{}; - const int max_value = max(t_n); - for (auto it = t_begin; it < t_end - 1; /* nope */) { - uint16_t current_char = 0; - // left bits - left_shift = - ((left_shift += step) >= t_n) ? (left_shift - t_n) + step : left_shift; - current_char = static_cast(*it << left_shift); - // right bits - bool zero_rs = right_shift; - right_shift -= step; - if (right_shift < 0) { - // optional middle bits before right bits - if (zero_rs) { - current_char |= *++it << (-right_shift); - } - right_shift = 8 + right_shift; + const auto max_val = max(9); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + vuint16 res{}; + while (current_char < max_val && it < t_end - 1) { + switch (round % 8) { + case 0: { + current_char = static_cast(*it) << 1u; + current_char |= static_cast(*++it) >> 7u; + break; } - current_char |= *(++it) >> right_shift; - // char made! - ret.push_back(current_char &= masks[t_n]); - if (current_char >= max_value) { - 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; + case 1: { + current_char = static_cast(*it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; } - if (right_shift == 0) { + case 2: { + current_char = static_cast(*it) << 3u; + current_char |= static_cast(*++it) >> 5u; + break; + } + case 3: { + current_char = static_cast(*it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 4: { + current_char = static_cast(*it) << 5u; + current_char |= static_cast(*++it) >> 3u; + break; + } + case 5: { + current_char = static_cast(*it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 6: { + current_char = static_cast(*it) << 7u; + current_char |= static_cast(*++it) >> 1u; + break; + } + case 7: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); ++it; + break; } + default: + exit(2); + } + current_char &= masks[9]; + res.push_back(current_char); + ++round; } - return ret; + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), res.size()); +#endif + return unpack_10(it, t_end, res); + } + return res; +} + +vuint16 unpack_10(const ustring::const_iterator t_input, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("10 bits\n"); +#endif + const auto max_val = max(10); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + while (current_char < max_val && it < t_end - 1) { + switch (round % 4) { + case 0: { + current_char = static_cast(*it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; + } + case 1: { + current_char = static_cast(*it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 2: { + current_char = static_cast(*it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 3: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + ++it; + break; + } + default: + exit(2); + } + current_char &= masks[10]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return unpack_11(it, t_end, t_res); + } + return t_res; +} + +vuint16 unpack_11(const ustring::const_iterator t_input, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("11 bits\n"); +#endif + const auto max_val = max(11); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + while (current_char < max_val && it < t_end - 1) { + switch (round % 8) { + case 0: { + current_char = static_cast(*it) << 3u; + current_char |= static_cast(*++it) >> 5u; + break; + } + case 1: { + current_char = static_cast(*it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 2: { + current_char = static_cast(*it) << 9u; + current_char |= static_cast(*++it) << 1u; + current_char |= static_cast(*++it) >> 7u; + break; + } + case 3: { + current_char = static_cast(*it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 4: { + current_char = static_cast(*it) << 7u; + current_char |= static_cast(*++it) >> 1u; + break; + } + case 5: { + current_char = static_cast(*it) << 10u; + current_char |= static_cast(*++it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; + } + case 6: { + current_char = static_cast(*it) << 5u; + current_char |= static_cast(*++it) >> 3u; + break; + } + case 7: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + ++it; + break; + } + default: + exit(2); + } + current_char &= masks[11]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return unpack_12(it, t_end, t_res); + } + return t_res; +} + +vuint16 unpack_12(const ustring::const_iterator t_input, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("12 bits\n"); +#endif + const auto max_val = max(12); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + while (current_char < max_val && it < t_end - 1) { + switch (round % 2) { + case 0: { + current_char = static_cast(*it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 1: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + ++it; + break; + } + default: + exit(2); + } + current_char &= masks[12]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%d\n", current_char); +#endif + return unpack_13(it, t_end, t_res); + } + return t_res; +} + +vuint16 unpack_13(const ustring::const_iterator t_input, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("13 bits\n"); +#endif + const auto max_val = max(13); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + while (current_char < max_val && it < t_end - 1) { + switch (round % 8) { + case 0: { + current_char = static_cast(*it) << 5u; + current_char |= static_cast(*++it) >> 3u; + break; + } + case 1: { + current_char = static_cast(*it) << 10u; + current_char |= static_cast(*++it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; + } + case 2: { + current_char = static_cast(*it) << 7u; + current_char |= static_cast(*++it) >> 1u; + break; + } + case 3: { + current_char = static_cast(*it) << 12u; + current_char |= static_cast(*++it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 4: { + current_char = static_cast(*it) << 9u; + current_char |= static_cast(*++it) << 1u; + current_char |= static_cast(*++it) >> 7u; + break; + } + case 5: { + current_char = static_cast(*it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 6: { + current_char = static_cast(*it) << 11u; + current_char |= static_cast(*++it) << 3u; + current_char |= static_cast(*++it) >> 5u; + break; + } + case 7: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + break; + } + default: + exit(2); + } + current_char &= masks[13]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return unpack_14(it, t_end, t_res); + } + return t_res; +} + +vuint16 unpack_14(const ustring::const_iterator t_input, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("14 bits\n"); +#endif + const auto max_val = max(14); + int round = 0; + uint16_t current_char = 0; + auto it = t_input; + while (current_char < max_val && it < t_end - 1) { + switch (round % 4) { + case 0: { + current_char = static_cast(*it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 1: { + current_char = static_cast(*it) << 12u; + current_char |= static_cast(*++it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 2: { + current_char = static_cast(*it) << 10u; + current_char |= static_cast(*++it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; + } + case 3: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + break; + } + default: + exit(2); + } + current_char &= masks[14]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_input, it), t_res.size()); +#endif + return unpack_15(it, t_end, t_end, t_res); + } + return t_res; +} + +vuint16 unpack_15(const ustring::const_iterator t_begin, + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("15 bits\n"); +#endif + const auto max_val = max(15); + int round = 0; + uint16_t current_char = 0; + auto it = t_begin; + while (current_char < max_val && it < t_end - 1) { + switch (round % 8) { + case 0: { + current_char = static_cast(*it) << 7u; + current_char |= static_cast(*++it) >> 1u; + break; + } + case 1: { + current_char = static_cast(*it) << 14u; + current_char |= static_cast(*++it) << 6u; + current_char |= static_cast(*++it) >> 2u; + break; + } + case 2: { + current_char = static_cast(*it) << 13u; + current_char |= static_cast(*++it) << 5u; + current_char |= static_cast(*++it) >> 3u; + break; + } + case 3: { + current_char = static_cast(*it) << 12u; + current_char |= static_cast(*++it) << 4u; + current_char |= static_cast(*++it) >> 4u; + break; + } + case 4: { + current_char = static_cast(*it) << 11u; + current_char |= static_cast(*++it) << 3u; + current_char |= static_cast(*++it) >> 5u; + break; + } + case 5: { + current_char = static_cast(*it) << 10u; + current_char |= static_cast(*++it) << 2u; + current_char |= static_cast(*++it) >> 6u; + break; + } + case 6: { + current_char = static_cast(*it) << 9u; + current_char |= static_cast(*++it) << 1u; + current_char |= static_cast(*++it) >> 7u; + break; + } + case 7: { + current_char = static_cast(*it) << 8u; + current_char |= static_cast(*++it); + break; + } + default: + exit(2); + } + current_char &= masks[15]; + t_res.push_back(current_char); + ++round; + } + if (current_char >= max_val) { +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_begin, it), t_res.size()); +#endif + return unpack_16(it, t_end, t_res); + } + return t_res; } vuint16 unpack_16(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end) { - vuint16 ret{}; + const ustring::const_iterator t_end, + vuint16& t_res) { +#ifdef Debug + std::printf("16 bits\n"); +#endif for (auto it = t_begin; it < t_end; ++it) { - ret.push_back(static_cast((*it << 8) | *(++it))); + t_res.push_back(static_cast(*it << 8u) | + static_cast(*++it & 0xffu)); } - return ret; +#ifdef Debug + std::printf("%ld elements written\n%ld chars written so far\n", + std::distance(t_begin, t_end), t_res.size()); +#endif + return t_res; } diff --git a/src/bitpack.hh b/src/bitpack.hh index e3d37d2..81c26d4 100644 --- a/src/bitpack.hh +++ b/src/bitpack.hh @@ -10,27 +10,86 @@ #include #include -/// \brief Bat-packs the input dynamically +/////////////////////////////////////////////////////////////////////////////// +// packing // +/////////////////////////////////////////////////////////////////////////////// + std::vector pack(const std::vector &); -/// \brief Packs std::uint16_t of n bits into unsigned char -std::vector -pack_n(const std::vector::const_iterator, - const std::vector::const_iterator, const int); +std::vector pack_9(std::vector::const_iterator, + std::vector::const_iterator); -/// \brief Specialization of \ref pack_n for 16bits -std::vector -pack_16(const std::vector::const_iterator, - const std::vector::const_iterator); +std::vector pack_10(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_11(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_12(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_13(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_14(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_15(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +std::vector pack_16(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); + +/////////////////////////////////////////////////////////////////////////////// +// unpack // +/////////////////////////////////////////////////////////////////////////////// std::vector unpack(std::basic_string &&); std::vector -unpack_n(const std::basic_string::const_iterator, - const std::basic_string::const_iterator, const int t_n); +unpack_9(std::basic_string::const_iterator, + std::basic_string::const_iterator); std::vector -unpack_16(const std::basic_string::const_iterator, - const std::basic_string::const_iterator); +unpack_10(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_11(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_12(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_13(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_14(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_15(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); + +std::vector +unpack_16(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector &); #endif /* LZW_SRC_BITPACK_H_ */ diff --git a/src/common.hh b/src/common.hh index 8087188..3c8e7bf 100644 --- a/src/common.hh +++ b/src/common.hh @@ -15,10 +15,10 @@ int ipow(int, int); /// \brief Recherche ou ajout de chaine dans le dictionnaire std::pair dico(std::map, std::uint16_t> &, - const std::uint16_t, const std::uint8_t); + std::uint16_t, std::uint8_t); std::basic_string dico_uncompress(std::map> &, - const std::uint16_t, const std::uint16_t); + std::uint16_t, std::uint16_t); #endif /* LZW_SRC_COMMON_H_ */ diff --git a/src/compress.cc b/src/compress.cc index 334234d..f0d6788 100644 --- a/src/compress.cc +++ b/src/compress.cc @@ -74,12 +74,7 @@ void compress(const std::string &t_in_file, const char *t_out_file) { assert(input_file); FILE *const out = (t_out_file != nullptr) ? fopen(t_out_file, "wb") : fopen("output.lzw", "wb"); - if (out == nullptr) { - std::cerr << "Error at " << __FILE__ << ":" << __LINE__ - 4 - << ": could not open output file. Aborting...\n"; - std::fclose(input_file); - exit(1); - } + assert(out); std::fseek(input_file, 0L, SEEK_END); const auto file_size = static_cast(ftell(input_file)); diff --git a/src/compress.hh b/src/compress.hh index 4aa4c75..e0fa926 100644 --- a/src/compress.hh +++ b/src/compress.hh @@ -7,9 +7,9 @@ #define LZW_SRC_COMPRESS_H_ #include "common.hh" -#include #include #include +#include /// \brief Compression d'une chaine de caractères std::vector> diff --git a/src/io.hh b/src/io.hh index 9979add..82aa947 100644 --- a/src/io.hh +++ b/src/io.hh @@ -6,8 +6,8 @@ #ifndef LZW_SRC_IO_H_ #define LZW_SRC_IO_H_ -#include #include +#include #include #include @@ -19,17 +19,17 @@ * * Un chunk se compose ainsi : * nb_char_chunk : nombre de caractères du chunk (2B) - * text* : caractères de taille char_size (ceil((char_size * nb_char_chunk) / 8)) + * text* : caractères de taille char_size (ceil((char_size * nb_char_chunk) / + * 8)) * * Si le dernier caractère ne termine pas le dernier octet du chunk, les * derniers bits sont mit à zéro */ - /// \brief Écrit dans le fichier le texte compressé -void write_file(FILE *const, const std::vector> &); +void write_file(FILE *, const std::vector> &); /// \brief Écrit un chunk dans le fichier de sortie -void write_chunk(FILE *const, const std::vector &); +void write_chunk(FILE *, const std::vector &); #endif /* LZW_SRC_IO_H_ */ diff --git a/src/uncompress.hh b/src/uncompress.hh index ac6ae0c..5999845 100644 --- a/src/uncompress.hh +++ b/src/uncompress.hh @@ -5,9 +5,8 @@ #include #include -std::basic_string -lzw_uncompress(std::vector &&); +std::basic_string lzw_uncompress(std::vector &&); -void uncompress(const std::string &, const char*); +void uncompress(const std::string &, const char *); #endif /* LZW_SRC_UNCOMPRESS_H_ */