Opened 4 years ago
Last modified 4 years ago
#927 assigned ожидаются исправления
HW #3
Reported by: | Surkov Petr | Owned by: | Surkov Petr |
---|---|---|---|
Component: | HW #3 (Huffman) | Version: | 2.0 |
Keywords: | Cc: |
Description
Change History (5)
comment:1 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
comment:3 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 1.0 → 2.0 |
Что-то исправил.
В момент переписывания архитектуры понял, что больше не хочу заниматься этой домашкой. Она осталась прежней.
comment:4 Changed 4 years ago by
Owner: | changed from Egor Suvorov to Surkov Petr |
---|---|
Type: | ожидается проверка → ожидаются исправления |
Проверялась ревизия 3997.
Третья попытка разблокирована.
Корректность 8.5/9
- В
Huffman.hpp
не хватает#include <string>
(хотяstd::string
используется), из-за этого не компилируется подlibc++
:[ 31%] Building CXX object CMakeFiles/hw_03.dir/src/Huffman.cpp.o In file included from /home/yeputons/cpp19/surkov.petr/hw_03/src/Huffman.cpp:1: In file included from /home/yeputons/cpp19/surkov.petr/hw_03/include/Huffman.hpp:3: In file included from /usr/lib/llvm-10/bin/../include/c++/v1/unordered_map:409: In file included from /usr/lib/llvm-10/bin/../include/c++/v1/__hash_table:15: In file included from /usr/lib/llvm-10/bin/../include/c++/v1/memory:657: /usr/lib/llvm-10/bin/../include/c++/v1/utility:306:9: error: implicit instantiation of undefined template 'std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >' _T2 second; ^ /home/yeputons/cpp19/surkov.petr/hw_03/src/Huffman.cpp:7:17: note: in instantiation of template class 'std::__1::pair<const unsigned char, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >' requested here return {{*c, ""}};
- На баллы не влияет: принимаются флаги
-?file
/-Xfile
вместо--file
почём зря.
Тесты 7.8/8
- Нет большого теста на какую-нибудь оптимальность кодов или что-то такое.
Архитектура 4/5
- Актуальны старые замечания про:
- Битовые "строчки" в
std::string
- Необходимость руками считать статистику.
- Непонятную зону ответственность
HuffmanIO
. Было бы лучше выделить: побитовую запись/чтение, потоки байт со статистикой, функции чтения-записи чисел, функции чтения-записи таблицы кодирования.
- Битовые "строчки" в
CLI
- Не очень плюсовый стиль: отдельно массив, отдельно количество аргументов.
span<string_view>
/vector<string_view>
/vector<string>
подошли бы больше.
- Не очень плюсовый стиль: отдельно массив, отдельно количество аргументов.
EncodingIO
- Лучше в деструкторе не
flush
, аassert
, что буфер сброшен.
- Лучше в деструкторе не
HuffmanTree
- Неясно, зачем пустое дерево и публичный конструктор по умолчанию. Если для фабричных функций, то лучше его сделать приватным, а функции - друзьями. Или можно воспользоваться type_tags (смотри nullopt/in_place_t у std::optional, можно ещё у меня поинтересоваться).
- Плохо понимаю разницу между
HuffmanTree
иHuffmanNode
: конструкторы одинаковые, методы почти одинаковые... Кажется, что лучше вbuildFromFreqTable
манипулироватьHuffmanNode
и возвращать одно дерево. Тогда потребуется только конструктор от корня (возможно, отnullptr
).
Huffman
calculateFrequencies
лучше отдельной свободной функцией и протестировать.
Стиль 6.5/8
- Не стоит хардкодить компилятор в
CMakeLists.txt
. Это надо делать при вызове:cmake . -DCMAKE_CXX_COMPILER=clang++-6.0
. ВCMakeLists.txt
должно быть только что-то проектоспецифичное. - НЕ ОБЪЯВЛЯЙТЕ ПЕРЕМЕННЫЕ ВНЕ ЦИКЛОВ (смотрю на
TEST_CASE("Get bit") {
) - Все файлы должны завершаться
\n
(не incomplete line). CLI
input = args["f"][0], output = args["o"][0];
- тут лучше;
и на разных строчках.std::string arg = std::string(argv[i]).substr(1 + static_cast<size_t>(len != 2));
- лучше убрать и называть везде аргументы как-a
,-f
,--file
...1 + static_cast<size_t>(len != 2)
- это жесть какая-то. Я несколько минут понимал, что это и зачем. Только потом понял, что это для длинных опций. Но вы тут тогда ещё и приняли-?file
вместо--file
, что нехорошо.
- Вместо
valPos
лучше просто поi
итерироваться. - В тестах вместо константы 6 лучше
std::size(argv)
- В тестах лишние фигурные скобки (
Incompatible args
и дальше).
HuffmanIO
- Никогда не надо делать
flush
/endl
внутриoperator<<
. - Странно, что
writeEncodingTable
сбрасывает статистику по дополнительным символам. - Тесты
- Вместо
(1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 2) + 1
лучше0b1110'0101
- Вместо
string s = s1 + s2
лучшеstring s = "11110101" "10011001"
(подряд идущие строковые литералы препроцессор соединяет). Ну или хотя бы без промежуточных переменных:string s = string("foo") + "bar"
);
- Вместо
- Вместо
- Никогда не надо делать
Huffman
HuffmanTree::HuffmanNode::getCharsEncodingTable
- можно упростить: сразу создайте возвращаемое значение, а потом range-based-for сразу по результату функции без промежуточной переменной. Так можно: https://stackoverflow.com/a/9657748/767632- Тесты
- В одном месте не заиспользовали свой
FreqTable
- В одном месте не заиспользовали свой
HuffmanArchiver
- Тесты
- Лишние пустые строчки в начале
TEST_SUITE
uniform_int_distribution<>dis
- не хватает пробела передdis
info1
/info2
- не очень понятные имена. Равно как иss1/2/3
, лучше описать, что именно в них лежит.
- Лишние пустые строчки в начале
- Тесты
main
- Многовато инклудов
comment:5 Changed 4 years ago by
Кстати, решение прям классное. Серьёзное по архитектуре - я путаюсь с EncodingIO
/DecodingIO
плюс std::string
. Это исправить, будет 4.8/5 по архитектуре.
Note: See
TracTickets for help on using
tickets.
Корректность 8/9
Тесты 7/8
CLI
TEST_CASE
, аSUBCASE
. Куски-то всё-таки независимые, надо уметь их независимо проверять.IOProcessing
put
вstringstream
руками, создайте его от нужногоstring{....}
.bool b;
, простоCHECK(es.getByte())
0b00000111 == (1 << 2) | (1 << 1) | (1 << 0)
.Huffman
using
дляunordered_map<....>
, можно даже внутриHuffmanTree
.==
с точным кодированием.Архитектура 3.75/5
CLI
CLIException
—final
и лучше отruntime_error
/logic_error
, конструкторы проще станут заодно.const
-поле — на самом деле как минимум статическое, а лучше — деталь реализации (потому чтоprivate static
), должна быть в.cpp
. А ещё это явное дублирование кода, надо избавиться.std::string
. Заодно ассёрты исчезнут.HuffmanIOProcessing
:Stream
(это обычно один однонаправленный поток), аIO
:EncodingIO
,DecodingIO
.readLen()
/writeLen()
, когда на самом деле естьreadUInt32_t()
/writeUInt32_t()
.SizeInfo
. Лучше это инкапсулировать в базовомAbstractIO
. И сделать какие-то методы записи (возможно, побитовой, как общий знаменатель), всю запись пустить через них, а дальше считать статистику.readDecoding()
/writeEncoding
— кажется, это отдельные методы для работы с объектом "кодировка Хаффмана", а не часть общего ввода-вывода.Huffman
HuffmanTree
почему-то в конструкторе требует, чтобы деревья хранились в куче вunique_ptr
. Это лишнее ограничение, нам это неважно. Тут требуется лишь забрать владение их корнями (что наглядно видно из реализации). Хватит rvalue-ссылки.HuffmanArchiver
main
. Тогда весь ввод-вывод будет сосредоточен в нём. Сейчас вы, например, не можете протестировать корректность статистики.Стиль 6/8
snake_case
илиCamelCase
, неcamelCase
.namespace foo::bar
: стандартный gcc не умеет.-MMD -MP
(при компиляции рядом с.o
положится.d
, который можно-include
из Makefile;-
нужен для отсутст)""
, а не<>
CLI
last_arg
ыыкинуть, лучшеi
руками менять.args
в отдельную функцию.find() == end()
-->count
f
иfile
лучше склеивать прямо при парсинге, а не в конце проверять дублирование.args[].size()
проверять незачем: и так уже бывает исключениеArg duplicated
. И это, опять же, лучше проверять в общем случае, а не для каждого отдельно.HuffmanIOProcessing
HuffmanIO
operator<<
не должен сбрасывать буфер при помощиendl
никогда.decoding
/encoding
— не очень хорошие названия для таблицы кодирования.reset()
? Непонятно, что делает.rewindInput()
?isInputEmpty()
и методы возвращают true/false. Лучше выбрать ровно один каноничный способ работы с потоком.flush()
, а проверить, что пользователь сделалflush()
, имхо. Иначе у деструктора есть какие-то нетривиальные побочные эффекты.Huffman
HuffmanTree::getCharsEncoding
можно выкинуть одинif
new
в чистом виде никогда!assert
не на непустоту очереди, а на её размер.explicit
. Да и конструктор от частот тоже (но его уже заменили на функцию).HuffmanArchiver
getFrequencies
— тут оно прямо пробегается и считает. Лучшеcalculate
.encode
: незачем кодировать дважды и писать закодированную длину. Можно записать кое-что другое, будет так же красиво, но проще.compress()
/extract()
— непонятно, зачемif
в начале. Всегда кодируем, кроме каких-то случаев? Не понял. Заглушение ошибок? Хочу комментарий как минимум.assert
'ы, что мы стоим в начале файла. Или [мыть тарелки перед едой](http://blog.algoprog.ru/init-not-clear/).decode
объявляйте переменные только там, где они реально нужны (bit
), ни строчкой раньше.