From b7f96f0557e8e7d1e296d097ff74c3627247aecc Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Thu, 26 Apr 2018 13:49:39 +0200 Subject: [PATCH] Fixed empty chunk issue, still unexpected errors --- src/common.cc | 16 +++--- src/common.hh | 6 +-- src/compress.cc | 136 +++++++++++++++++++++--------------------------- src/compress.hh | 5 +- src/main.cc | 6 +-- 5 files changed, 76 insertions(+), 93 deletions(-) diff --git a/src/common.cc b/src/common.cc index d223f5f..19477e6 100644 --- a/src/common.cc +++ b/src/common.cc @@ -6,8 +6,8 @@ #include "common.hh" using uint8_t = std::uint8_t; -using uint16_t = std::uint16_t; -using dic_t = std::map, uint16_t>; +using uint32_t = std::uint32_t; +using dic_t = std::map, uint32_t>; /** * Cette fonction a pour double usage la recherche d’une chaine de caractères @@ -18,18 +18,18 @@ using dic_t = std::map, uint16_t>; * caractère se référant au dernier caractère de la chaine courante. Si le * numéro de chaine est -1, alors il s’agit du premier caractère de la chaine, * et la valeur renvoyée sera la valeur ASCII du caractère. La fonction renvoie - * une paire bool/uint16_t, la valeur booléene indiquant si une nouvelle fut - * ajoutée dans le dictionnaire ou non, et le uint16_t indiquant la valeur + * une paire bool/uint32_t, la valeur booléene indiquant si une nouvelle fut + * ajoutée dans le dictionnaire ou non, et le uint32_t indiquant la valeur * numérique de la chaîne dans le dictionnaire. * * \param dictionary Dictionnaire * \param nr_chaine Numéro de la chaine précédant le caractères \p c dans \p dictionary * \param c Caractère suivant la chaine de caractères \p nr_chaine - * \return std::pair + * \return std::pair */ -const std::pair -dico(std::map, uint16_t> &t_dictionary, - uint16_t t_nr_chaine, uint8_t t_c) { +const std::pair +dico(std::map, uint32_t> &t_dictionary, + uint32_t t_nr_chaine, uint8_t t_c) { if (t_nr_chaine == 0xFFFF) return std::make_pair(true, t_c); auto &e = t_dictionary[std::make_pair(t_nr_chaine, t_c)]; diff --git a/src/common.hh b/src/common.hh index cc1b367..1406ab8 100644 --- a/src/common.hh +++ b/src/common.hh @@ -10,8 +10,8 @@ #include /// \brief Recherche ou ajout de chaine dans le dictionnaire -const std::pair -dico(std::map, std::uint16_t> &, - uint16_t, uint8_t); +const std::pair +dico(std::map, std::uint32_t> &, + uint32_t, uint8_t); #endif /* LZW_SRC_COMMON_H_ */ diff --git a/src/compress.cc b/src/compress.cc index 0278200..b5406fb 100644 --- a/src/compress.cc +++ b/src/compress.cc @@ -16,56 +16,55 @@ constexpr bool debug_mode = false; #include #include -using dict_t = std::map, uint16_t>; -using ustring = std::basic_string; // chaine non encodée -using uvec = std::vector; // chaine encodée +using dict_t = std::map, uint32_t>; +using ustring = std::basic_string; // chaîne non encodée +using uvec = std::vector; // chaîne encodée using std::printf; +void join_and_write( + std::vector, uvec>> &t_threads, + FILE *t_out) { + for (auto &elem : t_threads) { + (*elem.first).join(); + } + for (auto &elem : t_threads) { + for (const auto c : elem.second) { + write_utf8(t_out, c); + } + } + t_threads.clear(); +} + /** - * La chaine de caractère \p text est lue caractère par caractère, et est et + * La chaîne de caractère \p t_text est lue caractère par caractère, et est et * selon la valeur de retour de la fonction \ref dico (permettant dans le même * temps la création du dictionnaire), on rajoute un mot ou pas dans le vecteur * de caractères UTF-8 représentant des mots de chars compressés. La fonction - * renvoie ledit vecteur de uint32_t. + * renvoie ledit vecteur de uint32_t via le paramètre \p t_res. * - * \param t_text Chaine de caractères uint8_t représentant le fichier d'entrée - * \param t_dictionary Dictionnaire de compression - * \return std::vector + * \param[in] t_text Chaîne de caractères uint8_t représentant le fichier + * d'entrée \param[out] t_res Chaîne de caractères de sortie */ void lzw_compress(const std::vector &t_text, uvec &t_res) { dict_t dictionary{}; std::puts("Compressing..."); - // uvec res{}; - uint16_t w = 0xFFFF; - uint16_t len = 0; + uint32_t w = 0xFFFF; constexpr size_t DICT_MAX = 7936; /* 12 bits */ - size_t progress = 0; - for (const auto &c : t_text) { - ++len; - - if constexpr (debug_mode) { - printf("\rprogress: %zu / %zu", ++progress, t_text.size()); - } - - if (/* len > LENGTH_MAX || */ dictionary.size() >= DICT_MAX) { - t_res.push_back(static_cast(w)); - w = static_cast(c); - len = 0; + if (dictionary.size() >= DICT_MAX) { + t_res.push_back(static_cast(w)); + w = static_cast(c); } else if (const auto &[exists, pos] = dico(dictionary, w, static_cast(c)); exists) { w = pos; } else { - t_res.push_back(static_cast(w)); + t_res.push_back(static_cast(w)); w = static_cast(c); - len = 0; } } - printf("\n"); - // return res; } /** @@ -82,81 +81,66 @@ void lzw_compress(const std::vector &t_text, uvec &t_res) { void compress(const std::string &t_in_file, const char *t_out_file) { // Fichier d’entrée std::ifstream input_file{t_in_file}; - if(!input_file.is_open()) { + if (!input_file.is_open()) { std::cerr << "Error at " << __FILE__ << ":" << __LINE__ - 2 - << ": could not open output file \"" << t_in_file << "\". Aborting...\n"; + << ": could not open output file \"" << t_in_file + << "\". Aborting...\n"; exit(1); } // Fichier de sortie - const char *filename = - (t_out_file) ? t_out_file : "output.lzw"; + const char *filename = (t_out_file) ? t_out_file : "output.lzw"; FILE *out = fopen(filename, "wb"); - if(!out) { + if (!out) { std::cerr << "Error at " << __FILE__ << ":" << __LINE__ - 4 - << ": could not open output file \"" << filename << "\". Aborting...\n"; + << ": could not open output file \"" << filename + << "\". Aborting...\n"; input_file.close(); exit(1); } - // input_file.seekg(0, std::ios::end); - // // string contenant le fichier d’entrée - // ustring str(static_cast(input_file.tellg()), - // static_cast(0)); - // input_file.seekg(0, std::ios::beg); - - // // assignation du contenu du fichier à str - // str.assign((std::istreambuf_iterator(input_file)), - // std::istreambuf_iterator()); - - // printf("Size of input file: %zu\n", str.size()); - - // dict_t dictionary{}; - - // const auto comp_str{lzw_compress(str, dictionary)}; - // thread pool std::vector, uvec>> threads{}; // char chunk[32768]; - std::vector chunk{}; - chunk.reserve(32768); - while (input_file.read(chunk.data(), 32768)) { - threads.push_back(std::make_pair(nullptr, uvec{})); + std::vector chunk(32768, 0); + while (input_file.read(chunk.data(), + static_cast(chunk.size()))) { + printf("\n"); + threads.emplace_back(nullptr, uvec{}); threads.back().first = std::make_unique( std::thread{lzw_compress, chunk, ref(threads.back().second)}); if (threads.size() >= 8) { - for (auto &elem : threads) { - (*elem.first).join(); - } - for (auto &elem : threads) { - for (const auto c : elem.second) { - write_utf8(out, c); - } - } - threads.clear(); + join_and_write(threads, out); } } - if(threads.size() != 0) { - for (auto &elem : threads) { - (*elem.first).join(); + if (!threads.empty()) { + join_and_write(threads, out); + } + + if (input_file.tellg() != std::ios::end) { + std::puts("Leftovers, compressing..."); + { + const auto prev_pos = input_file.tellg(); + input_file.seekg(0, std::ios::end); + chunk.reserve(static_cast(input_file.tellg() - prev_pos)); + input_file.seekg(prev_pos, std::ios::beg); + std::istreambuf_iterator itr(input_file); + for (std::streamoff i = 0; i < prev_pos; ++i, ++itr) + ; + chunk.assign((itr), std::istreambuf_iterator()); } - for (auto &elem : threads) { - for (const auto c : elem.second) { - write_utf8(out, c); + uvec ret{}; + lzw_compress(chunk, ret); + for (const auto c : ret) { + if constexpr (debug_mode) { + printf("%c\t", c); } + write_utf8(out, c); } - threads.clear(); } - if(input_file.tellg() != std::ios::end) { - std::puts("Leftovers..."); - } - - // for (const auto c : comp_str) - // write_utf8(out, c); - fclose(out); input_file.close(); } diff --git a/src/compress.hh b/src/compress.hh index 30de860..8c3ddcb 100644 --- a/src/compress.hh +++ b/src/compress.hh @@ -11,10 +11,9 @@ #include /// \brief Compression d'une chaine de caractères -void lzw_compress(const std::vector &t_text, - std::vector &t_rec); +void lzw_compress(const std::vector &, std::vector &); /// \brief Wrapper de \ref lzw_compress -void compress(const std::string &t_in_file, const char *t_out_file); +void compress(const std::string &, const char *); #endif /* LZW_SRC_COMPRESS_H_ */ diff --git a/src/main.cc b/src/main.cc index c9641e6..9afc659 100644 --- a/src/main.cc +++ b/src/main.cc @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) { std::string output_path{}; bool compressing = true; - while (1) { + while (true) { int option_index = 0; static struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { {"output", required_argument, nullptr, 'o'}, {"compress", no_argument, nullptr, 'c'}, {"uncompress", no_argument, nullptr, 'u'}, - {0, 0, 0, 0}}; + {nullptr, 0, nullptr, 0}}; int c = getopt_long(argc, argv, "hi:o:cu", long_options, &option_index); if (c == -1) break; @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) { } } - if (input_path == "") { + if (input_path.empty()) { puts("Error: no input file specified"); return 2; }