Opened 4 years ago
Last modified 4 years ago
#936 assigned ожидается проверка
HW #3
Reported by: | Brilliantov Kirill | Owned by: | Egor Suvorov |
---|---|---|---|
Component: | HW #3 (Huffman) | Version: | 3.0 |
Keywords: | Cc: |
Description
Change History (6)
comment:1 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|---|
Version: | 1.0 → 2.0 |
comment:2 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|
У меня только не до конца напсианы тесты, а все остальное готово, поэтому, наверное, нет смысла ждать четверга...
comment:3 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
comment:4 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|
comment:5 Changed 4 years ago by
Owner: | changed from Egor Suvorov to Brilliantov Kirill |
---|---|
Type: | ожидается проверка → ожидаются исправления |
Проверялась ревизия 4014 или ранее.
Третья попытка разблокирована.
Общее впечатление: стереть половину кода/функций/методов, распилить HuffmanArchiver.h
и
Utility.h` и станет сильно хорошо.
Корректность 7/9
- Регулярно ошибается на +- 1 в размере сжатого файла. На пустом файле, например. Иногда не ошибаюется, впрочем.
- Сейчас у вас нельзя обработать файл с именем
-foo.txt
, а зря. - Если произошла ошибка, код возврата должен быть ненулевой. У вас, судя по
main
, это не так ни в одном из трёх случаев (в одном вообще TODO стоит).
Тесты 5.5/8
- Не протестирован CLI
- Не протестирован подсчёт статистики (у вас как раз тут баг)
- Не протестирован битовый ввод-вывод отдельно от всего остального
TestHuffmanTree.cpp
- Дублирование кода:
isLeaf
дублирует метод вершины,onlyOne
— это просто^
или!=
на выбор. - Каждый из
existingLeafs
— это отдельныйCHECK
. - Лучше тестировать белый ящик: вы полностью знаете алгоритм и в каком порядке будут вершины. Для этого лучше использовать
stable_sort
. Тогда уйдёт вообще вся логика из тестов. Тем более чтоtest generating codes
у вас и так предполагает что-то серьёзное про алгоритм.
- Дублирование кода:
TestHuffmanArchiver.cpp
- Вместо чтения из
stringstream
и хитрых циклов спросите содержимое целиком при помощи.str()
и сравните с известным массивом. - Вообще неясно, что делает цикл в конце
write weight
— вы считали данные, но не проверили. Это странно.
- Вместо чтения из
Архитектура 1.5/5
- Вместо двух вложенных namespace лучше писать сразу
namespace hw_03::huf_cli
. А ещё лучшеhw_03::cli
, всё-таки huffman следует изhw_03
. - Неясно, зачем ограничивать move у
CLI
/IOStatistic
и ещё много кого. Вообще move обычно полезен. Copy ещё можно семантически ограничивать (если прям нельзя придумать "что такое копия"), а вот move обычно не стоит. Да и копия у вас практически везде делается очевидным образом и может иметь смысл. CLI
- Сеттеры лучше закрыть. И неясно, почему они принимают
const char*
, а не хотя быstring_view
(а ещё лучшеstring
по значению, потому что в поле всегда будет записыватьсяstring
). ACTION
скорее принадлежит кCLI
, а не кUtility
- Сеттеры лучше закрыть. И неясно, почему они принимают
ArgumentsFormatException
лучше отнаследовать отruntime_error
/logic_error
и сделатьusing
конструкторов.Utility.h
— сразу по названию понятно, что тут сборка всего подряд. Но, к сожалению, не по делу:Action
можно перенести- Обобщение
HuffmanByte
можно убрать, если сказать, что у нас нет спецсимвола для конца потока. Например, как-то по-другому понять длину потока (входного или выходного, смотря что проще). HuffmanByteLength
используется только в одном.cpp
.HuffmanBit
лучше убрать и использовать честныйbool
, напоретесь наvector<bool>
— нестрашно. Сейчас код сильно раздувается и обобщается, сложно читать. Лучше ужHuffmanCode
замените сразу на что-то ещё. А бит — всегдаbool
.LeftChildBit
/RightChildBit
— тоже лишнее обобщение, не нужно, это вряд ли будет меняться, лучше захардкодить, а не обобщать.getBit(HuffmanWeight, size_t)
— зачем получать i-й бит у _веса_ вершины? O_O А ещё это снова приватная дляHuffmanArchiver.cpp
функция. И наверняка ещё можно заинлайнить, она не ахти сложная, но код сильно раздувает, если вынести.- Категорически неясен смысл
ByteMap
. Чем обычныйmap
или массив не угодил? А так мне придётся для чтения кода абсолютно новый интерфейс с какими-то лямбдами учить. А ещё не работает list-initialization (в тестах бы пригодилось).
IOStatistic
— неshow()
, аoperator<<
. Но респект за подсчёт бит (правда, там косяк, смотри корректность).- Где-то
CHAR_BIT
, а где-то 8. Если уж знаете проCHAR_BIT
, то поставьте простоstatic_assert
на его размер, не надо подгадывать под древние машины с не тем размером байта. Huffman
using TreeNode
сослужил вам плохую службу: маскирует кучу стилистических замечаний (смотри ниже) плюс постоянно, постоянно путается сHuffmanNode
. Лучше явно написатьunique_ptr
.- Неясно, зачем отделять
merge
и конструктор от двух вершин. HuffmanTreeTraverser
- Не выполнено правило пяти. А лучше — правило нуля.
- Лучше не влево/вправо, а по значениям бит. И неясно, зачем
getLeftChildCursor()
, если класс копируемый. Лучше публичных методов по минимуму. Да иcanGoLeft
/canGoRight
наверняка убиваются при помощиassert
внутриgoLeft
. - Неясно, зачем куча
operator->
,get()
... Кстати, тогда уж иoperator*
надо, раз под умный указатель мимикрия. Но лучше не надо. - Кажется, что если полностью выкинуть
HuffmanTreeTraverser
и оставить только вершину с геттерами, будет примерно то же самое.
HuffmanTree
- Конструктор по умолчанию не инициализирует поля. Будет UB.
- Неясно, зачем отдельный конструктор и отдельный метод
build()
.
HuffmanArchiver
— снова надо распилить минимум на два файла.- Тут побайтовый/побитовый ввод-вывод не по делу. Это отдельные сущности.
- Аналогично,
createFrequencies
точно выносится. А ещё эти группы функций в концеHuffmanArchiver.h
тонко намекают, что, возможно, они на самом деле говорят про какой-то объект. shared_ptr
не по делу. По фактуIOStatistic
всегда живёт не меньше, чем соответствующий читатель/писатель.BitReader::getWeight()
— это чтение не веса, а числа определённого размера. Как минимум стоит назватьgetHuffmanWeight()
, а ещё лучше —read
(да и остальныеget
тоже). А ещё неясно, зачем эти функции, когда уже естьoperator>>
.BitReader::flush()
— шта.- Кажется, что
BitReader
стоит разбить как минимум на битовый-ввод и всё остальное (типа чтения байтов, кодов, весов). HuffmanArchiver
— кажется, чтоgetStats()
лучше заменить на возвращаемое значениеcompress
/extract
, будет очевиднее семантика "что за статистику получили".
Стиль 2.5/8 (болдом выделены очень существенные замечания, каждое на -1 балл сразу)
- Не используйте альтернативные названия операторов:
!
, неnot
. Это C++, не Pascal, не Python. Альтернативные названия были введены как триграфы — для клавиатур, где нет почти ничего, кроме латиницы — не наш случай. - Не используйте оператор
new
: используйте умные указатели и операции вродеmake_shared
. - Не хватает слов
final
иnoexcept
. - В
Makefile
для автогенерации зависимостей через gcc ещё хорошо бы давать ключ-MP
, чтобы при удалении заголовочного файла не было проблем. CLI
- Практически везде вместо
char*
надо написатьstd::string_view
. ACTION
- Лучше
Action
, это тип - Скорее принадлежит к
CLI.h
, а не к
- Лучше
struct Key
- деталь реализации, должен быть в
CLI.cpp
- Лучше делать не два вида опций, а сразу сделать
set<string>
из возможных альтернатив. Раз уж там полные синонимы.
- деталь реализации, должен быть в
- Вместо
compare
/equal
лучше==
, это не Java, тут принято перегружать операторы. parseNextArg
— бесполезная функция, используется ровно один раз и требует вообще все переменные из конструктораCLI
. Лучше заинлайнить.find_if
— в лямбде лучше сделать захват по ссылке всего[&]
, чтобы обозначить, что эта лямбда вызывает вот прямо сейчас и немедленно.
- Практически везде вместо
- Незачем явно удалять конструктор по умолчанию, если вы уже задали какие-то другие конструкторы.
IOStatistic
- Не используйте тернарный оператор вместо
if
. - Шесть приватных функций используются ровно один раз и имеют смысл только в контексте публичных. Никогда без них использоваться не будут. Лишние, заинлайнить.
IOStatistic
-->IOStatistics
- Не используйте тернарный оператор вместо
Huffman
- Принимайте
unique_ptr
по значению, а не по rvalue-ссылке. - Не возвращайте константную ссылку на
unique_ptr
, это бесполезно. - Странно, что у
HuffmanNode
есть конструктор сweight = 0
. - Неясно, зачем вынесена функция
isFinish
(сильно больше кода, но он теперь не такой локальный). extractMin
лучше лямбдой с захватом.- А ещё там
res
не используется. - А ещё его можно написать в один иф с не очень сложным условием, а не три. К тому же сейчас четыре
return
идут на разных уровнях.
- А ещё там
- Принимайте
CHECK_EQ(a, b)
-->CHECK(a == b)
. doctest разберётся.TestHuffmanTree.cpp
- Дублирование кода:
isLeaf
дублирует метод вершины,onlyOne
— это просто^
или!=
на выбор. - Каждый из
existingLeafs
— это отдельныйCHECK
. Тут действительно однообразный код, не надо пытаться это замаскировать. Тесты должны быть максимально дубовые.
- Дублирование кода:
TestHuffmanArchiver.cpp
- Вместо 128 лучше битовый литерал:
0b1'000'0000
- Название теста должно говорить, что именно тестируется/не работает. В частности, неясно, чем отличаются
write bit 1
иwrite bit 2
. Аналогичноcase1
/case2`.
- Вместо 128 лучше битовый литерал:
- Лучше не
std::abort()
, аassert
. - Строковые константы лучше не
const char*
, аconst char[]
, чтобы можно было спрашиватьsizeof
, если потребуется.
comment:6 Changed 4 years ago by
Owner: | changed from Brilliantov Kirill to Egor Suvorov |
---|---|
Type: | ожидаются исправления → ожидается проверка |
Version: | 2.0 → 3.0 |
Note: See
TracTickets for help on using
tickets.
Это уже вторая попытка, к сожалению. Я не уверен, что имеет смысл её проверять прямо сейчас. Поменяйте обратно на "ожидается проверка", если вы действительно хотите потратить вторую попытку (например, у вас должны выполняться требования к промежуточной попытке, чтобы получить третью).