From fa4d8aa4f99987fa10afc9d7ccd50951d38e4b7a Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Thu, 5 Apr 2018 18:47:07 +0200 Subject: [PATCH] from one file to several --- src/common.cc | 43 ++++++++++++ src/common.hh | 18 +++++ src/compress.cc | 52 +++++++++++++++ src/compress.hh | 18 +++++ src/main.cc | 171 +++--------------------------------------------- src/utf8.cc | 52 +++++++++++++++ src/utf8.hh | 26 ++++++++ 7 files changed, 219 insertions(+), 161 deletions(-) create mode 100644 src/common.cc create mode 100644 src/common.hh create mode 100644 src/compress.cc create mode 100644 src/compress.hh create mode 100644 src/utf8.cc create mode 100644 src/utf8.hh diff --git a/src/common.cc b/src/common.cc new file mode 100644 index 0000000..6def9a9 --- /dev/null +++ b/src/common.cc @@ -0,0 +1,43 @@ +/** + * \file common.cc + * \brief Implementation for functions in common + */ + +#include "common.hh" + +using uint8_t = std::uint8_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 + * dans le dictionnaire, ou bien l’ajout d’une nouvelle chaîne si celle-ci n’est + * pas déjà présente. Une chaine de caractères est représentée par un couple + * numéro de chaine / caractère, le numéro de chaine renvoyant au caractère + * précédent (soit son code ASCII, soit son indice dans le dictionnaire) et le + * 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 + * 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 + */ +std::pair +dico(std::map, uint32_t> &t_dictionary, + uint32_t t_nr_chaine, uint8_t t_c) { + if (t_nr_chaine == 0xFFFFFFFF) + return std::make_pair(true, t_c); + auto &e = t_dictionary[std::make_pair(t_nr_chaine, t_c)]; + return (e) ? std::make_pair(true, e) + : std::make_pair( + false, + (e = static_cast< + typename std::remove_reference::type>( + t_dictionary.size()) + + 255)); +} diff --git a/src/common.hh b/src/common.hh new file mode 100644 index 0000000..4fad40c --- /dev/null +++ b/src/common.hh @@ -0,0 +1,18 @@ +/** + * \file common.hh + * \brief Header for functions in common + */ + +#ifndef LZW_SRC_COMMON_H_ +#define LZW_SRC_COMMON_H_ + +#include +#include + +/// \brief Recherche ou ajout de chaine dans le dictionnaire +std::pair +dico(std::map, std::uint32_t> + &t_dictionary, + std::uint32_t t_nr_chaine, std::uint8_t t_c); + +#endif /* LZW_SRC_COMMON_H_ */ diff --git a/src/compress.cc b/src/compress.cc new file mode 100644 index 0000000..2e00dd1 --- /dev/null +++ b/src/compress.cc @@ -0,0 +1,52 @@ +/** + * \file compress.cc + * \brief Implementation of compression + */ + +#include "compress.hh" +#include + +using dict_t = std::map, uint32_t>; +using ustring = std::basic_string; // chaine non encodée +using uvec = std::vector; // chaine encodée + +/** + * La chaine de caractère \p 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. + * + * \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 + */ +const uvec compress(const ustring &t_text, dict_t &t_dictionary) { + std::puts("Compressing..."); + uvec res{}; + uint32_t w = 0xFFFFFFFF; + uint32_t len = 0; +#ifdef Debug + size_t progress = 0; +#endif + for (const auto &c : t_text) { + ++len; +#ifdef Debug + printf("\rprogress: %zu / %zu", progress++, t_text.size()); +#endif + if (len > 9) { + res.push_back(static_cast(w)); + w = c; + len = 0; + } else if (const auto &[exists, pos] = dico(t_dictionary, w, c); + exists) { + w = pos; + } else { + res.push_back(static_cast(w)); + w = c; + len = 0; + } + } + printf("\n"); + return res; +} diff --git a/src/compress.hh b/src/compress.hh new file mode 100644 index 0000000..e788eb2 --- /dev/null +++ b/src/compress.hh @@ -0,0 +1,18 @@ +/** + * \file compress.hh + * \brief Header for compression functions + */ + +#ifndef LZW_SRC_COMPRESS_H_ +#define LZW_SRC_COMPRESS_H_ + +#include "common.hh" +#include + +/// \brief Compression d'une chaine de caractères +const std::vector +compress(const std::basic_string &t_text, + std::map, std::uint32_t> + &t_dictionary); + +#endif /* LZW_SRC_COMPRESS_H_ */ diff --git a/src/main.cc b/src/main.cc index d79bba8..db65b13 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,20 +1,16 @@ -#include -#include -#include +/** + * \file main.cc + * \brief Main file + * + * + * + */ + +#include "utf8.hh" +#include "compress.hh" #include #include -#include #include -#include -#include - -#ifdef Debug -#define pdeb printf -#else -#define pdeb \ - if (0) \ - printf -#endif using std::printf; using std::puts; @@ -35,153 +31,6 @@ using dic_t = std::map, uint32_t>; using ustring = std::basic_string; // chaine non encodée using uvec = std::vector; // chaine encodée -size_t size_str(dic_t &dict, uint32_t nr_chaine) { - for(const auto &[key, value] : dict) { - if(value == nr_chaine) { - if(std::get<0>(key) == 0xFFFFFFFF) - return 1; - return 1 + size_str(dict, std::get<0>(key)); - } - } - return 0; -} - -/** - * \brief Recherche ou ajout de chaine dans le dictionnaire - * - * Cette fonction a pour double usage la recherche d’une chaine de caractères - * dans le dictionnaire, ou bien l’ajout d’une nouvelle chaîne si celle-ci n’est - * pas déjà présente. Une chaine de caractères est représentée par un couple - * numéro de chaine / caractère, le numéro de chaine renvoyant au caractère - * précédent (soit son code ASCII, soit son indice dans le dictionnaire) et le - * 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 - * 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 - */ -std::pair dico(dic_t &dictionary, uint32_t nr_chaine, uint8_t c) { - if (nr_chaine == 0xFFFFFFFF) - return std::make_pair(true, c); - auto &e = dictionary[std::make_pair(nr_chaine, c)]; - return (e) ? std::make_pair(true, e) - : std::make_pair( - false, - (e = static_cast< - typename std::remove_reference::type>( - dictionary.size()) + - 255)); - // auto &e = dictionary[std::make_tuple(nr_chaine, c, len)]; - // return (e) ? std::make_pair(true, e) - // : std::make_pair( - // false, - // (e = static_cast< - // typename std::remove_reference::type>( - // dictionary.size()) + - // 255)); -} - -/** - * \brief Compression d'une chaine de caractères - * - * La chaine de caractère \p 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. - * - * \param text Chaine de caractères uint8_t représentant le fichier d'entrée - * \param dictionary Dictionnaire de compression - * \return std::vector - */ -const uvec compress(const ustring &text, dic_t &dictionary) { - std::puts("Compressing..."); - uvec res{}; - uint32_t w = 0xFFFFFFFF; - uint32_t len = 0; -#ifdef Debug - size_t progress = 0; -#endif - for (const auto &c : text) { - ++len; -#ifdef Debug - printf("\rprogress: %zu / %zu", progress++, text.size()); -#endif - if (len > 9) { - res.push_back(static_cast(w)); - w = c; - len = 0; - } else if (const auto &[exists, pos] = dico(dictionary, w, c); - exists) { - w = pos; - } else { - res.push_back(static_cast(w)); - w = c; - len = 0; - } - } - printf("\n"); - return res; -} - -/* - L’encodage des caractères se fait en UTF-8 - char < 128 => "0xxxxxxx" 7bits - char < 2,048 => "110xxxxx 10xxxxxx" 11bits - char < 65,536 => "1110xxxx 10xxxxxx 10xxxxxx" 16bits - char < 2,097,152 => "11110xxx 10xxxxxx 10xxxxxx 10xxxxxx" 21bits - char < 67,108,864 => "111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx" 26bits - char < 2,147,483,648 => "1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx" 31bits -*/ - -/** - * \brief Écrit les caractères au format UTF-8 - * - * Les caractères \c passés en argument sont écrit dans le fichier de sortie au - * format UTF-8 - * - * \param out Fichier de sortie - * \param c Caractères à écrire dans \p out - */ -void write_utf8(FILE* out, uint32_t c) { - if(c < 128) { - fwrite(&c, sizeof(unsigned char), 1, out); - return; - } - size_t loops = 0; - unsigned char header = 0; - if (c < 2048) { - loops = 1; - header = 0xC0; - } else if (c < 65536) { - loops = 2; - header = 0xE0; - } else if (c < 2097152) { - loops = 3; - header = 0xF0; - } else if (c < 67108864) { - loops = 4; - header = 0xF8; - } else { - loops = 5; - header = 0xFC; - } - - ustring str(loops + 1, 0); - for (size_t i = 0; i <= loops; ++i) { - str[i] = static_cast( - ((c & (i == loops) ? 0x3F : 0xFF) >> ((loops - i) * 6)) + - ((i == 0) ? header : 0x80)); - } - fwrite(str.data(), sizeof(unsigned char), str.size(), out); -} - int main(int argc, char *argv[]) { if (argc < 2) { puts("Usage: lzw "); diff --git a/src/utf8.cc b/src/utf8.cc new file mode 100644 index 0000000..b509ef3 --- /dev/null +++ b/src/utf8.cc @@ -0,0 +1,52 @@ +/** + * \file utf8.cc + * \brief Implementation for UTF-8 related functions + */ + +#include "utf8.hh" +#include + +using FILE = std::FILE; +using uint8_t = std::uint8_t; +using uint32_t = std::uint32_t; +using ustring = std::basic_string; // chaine non encodée + +/** + * Les caractères \c passés en argument sont écrit dans le fichier de sortie au + * format UTF-8 + * + * \param out Fichier de sortie + * \param c Caractères à écrire dans \p out + */ +void write_utf8(FILE* t_out, uint32_t t_c) { + if(t_c < 128) { + fwrite(&t_c, sizeof(unsigned char), 1, t_out); + return; + } + size_t loops = 0; + unsigned char header = 0; + if (t_c < 2048) { + loops = 1; + header = 0xC0; + } else if (t_c < 65536) { + loops = 2; + header = 0xE0; + } else if (t_c < 2097152) { + loops = 3; + header = 0xF0; + } else if (t_c < 67108864) { + loops = 4; + header = 0xF8; + } else { + loops = 5; + header = 0xFC; + } + + ustring str(loops + 1, 0); + for (size_t i = 0; i <= loops; ++i) { + str[i] = static_cast( + ((t_c & (i == loops) ? 0x3F : 0xFF) >> ((loops - i) * 6)) + + ((i == 0) ? header : 0x80)); + } + fwrite(str.data(), sizeof(unsigned char), str.size(), t_out); +} diff --git a/src/utf8.hh b/src/utf8.hh new file mode 100644 index 0000000..4b51be2 --- /dev/null +++ b/src/utf8.hh @@ -0,0 +1,26 @@ +/** + * \file utf8.hh + * \brief Header for UTF-8 related functions + */ + +#ifndef LZW_SRC_UTF8_H_ +#define LZW_SRC_UTF8_H_ + +#include +#include + +/* + L’encodage des caractères se fait en UTF-8 + char < 128 => "0xxxxxxx" 7bits + char < 2,048 => "110xxxxx 10xxxxxx" 11bits + char < 65,536 => "1110xxxx 10xxxxxx 10xxxxxx" 16bits + char < 2,097,152 => "11110xxx 10xxxxxx 10xxxxxx 10xxxxxx" 21bits + char < 67,108,864 => "111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx" 26bits + char < 2,147,483,648 => "1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx" 31bits +*/ + + +/// \brief Écrit les caractères au format UTF-8 +void write_utf8(std::FILE* t_out, std::uint32_t t_c); + +#endif /* LZW_SRC_UTF8_H_ */