Opened 4 years ago
Last modified 4 years ago
#921 assigned ожидается проверка
HW #3
Reported by: | Карнаухов Кирилл | Owned by: | Egor Suvorov |
---|---|---|---|
Component: | HW #3 (Huffman) | Version: | 3.0 |
Keywords: | Cc: |
Description
Change History (8)
comment:1 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
comment:2 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|
comment:3 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
Проверялась ревизия 3856.
Корректность 8/9.
- Беда с компиляцией. На самом деле, с предупреждениями, поэтому это в стиль.
/home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/src/Huffman.cpp:24:16: error: moving a temporary object prevents copy elision [-Werror,-Wpessimizing-move] root = std::move(heap.extractMin()); ^ /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/src/Huffman.cpp:24:16: note: remove std::move call here root = std::move(heap.extractMin()); ^~~~~~~~~~ ~ In file included from /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/src/Huffman.cpp:3: In file included from /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/include/Huffman.h:7: /usr/lib/llvm-10/bin/../include/c++/v1/set:1127:30: error: the specified comparator type does not provide a viable const call operator [-Werror,-Wuser-defined-warnings] static_assert(sizeof(__diagnose_non_const_comparator<_Key, _Compare>()), ""); ^ /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/include/Huffman.h:57:7: note: in instantiation of member function 'std::__1::multiset<std::__1::unique_ptr<Huffman::Tree::Node, std::__1::default_delete<Huffman::Tree::Node> >, Huffman::Tree::Node::Compare, std::__1::allocator<std::__1::unique_ptr<Huffman::Tree::Node, std::__1::default_delete<Huffman::Tree::Node> > > >::~multiset' requested here class NodeHeap final { ^ /usr/lib/llvm-10/bin/../include/c++/v1/__tree:976:5: note: from 'diagnose_if' attribute on '__diagnose_non_const_comparator<std::__1::unique_ptr<Huffman::Tree::Node, std::__1::default_delete<Huffman::Tree::Node> >, Huffman::Tree::Node::Compare>': _LIBCPP_DIAGNOSE_WARNING(!std::__invokable<_Compare const&, _Tp const&, _Tp const&>::value, ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/lib/llvm-10/bin/../include/c++/v1/__config:1297:21: note: expanded from macro '_LIBCPP_DIAGNOSE_WARNING' __attribute__((diagnose_if(__VA_ARGS__, "warning"))) ^ ~~~~~~~~~~~ 2 errors generated.
Потом:
In file included from /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/src/HuffmanArchiver.cpp:4: /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/include/HuffmanArchiver.h:22:1: error: 'Statistics' defined as a struct here but previously declared as a class; this is valid, but may result in linker errors under the Microsoft C++ ABI [-Werror,-Wmismatched-tags] struct Statistics final { ^ /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/include/HuffmanArchiver.h:8:1: note: did you mean struct here? class Statistics; ^~~~~ struct 1 error generated.Потом:
/home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/test/TestHuffman.cpp:21:28: error: moving a temporary object prevents copy elision [-Werror,-Wpessimizing-move] NodePointer node = std::move(std::make_unique<Node>(std::move(left), std::move(right))); ^ /home/osboxes/cpp2019/cpp19/karnaukhov.kirill/hw_03/test/TestHuffman.cpp:21:28: note: remove std::move call here NodePointer node = std::move(std::make_unique<Node>(std::move(left), std::move(right))); ^~~~~~~~~~ ~ 1 error generated.Потом [нашёлся баг](https://github.com/onqtam/doctest/issues/356) то ли в doctest, то ли в стандартной библиотеке, но это уже не ваша проблема :)
- Не сошёлся вывод: сумма дополнительных данных и сжатых не равна итоговому размеру сжатого файла. Почти на всех тестах, причём на некоторых довольно большое расхождение.
Тесты 6/8
- Совершенно лишние
try
/catch
. Если вылетит исключение, doctest его сам поймает и красиво упадёт, а чтобы ожидать исключение, есть специальные команды. - Лучше не хардкодить размеры массивов для
Flags
, а вычислять их черезstd::size
TestHuffmanCode.cpp
надо разделить на мелкие тесты.- В
checkTextEndToEnd
можно и размеры данных до/после в байтах. Как раз для корректности нужно. И размеры получившегося архива тоже лучше проверить. А вдруг не сжимает? - Вместо
getRandomUInt
и своих велосипедов используйтеuniform_int_distribution
. - Стоит протестировать точные длины кодов, которые создаёт
Tree
. И даже их значения.
Архитектура 3/5
- Если произошла ошибка, следует завершать программу с ненулевым кодом возврата.
- Непонятно, с чего бы конструктор
Flags
принимаетsize_t
, хотя исходно былint
. И вообще тут прекрасно подойдёт какой-нибудьvector<string_view>
, если уж на то пошло. CLIException
— унаследуйтесь лучше отruntime_error
/logic_error
numberOfBytes
а) нужен только для подсчёта статистики архиватором — лучше смотреть на количество выведенных байт; б) находится вHuffmanCode.h
не по делу, это вообще приватная функция дляHuffmanArchiver.cpp
Code::getByte()
как-то молча обрезает код по восьми битам. Заглушение ошибок, плохо.- Вообще не понял, зачем нужен
Code
, когда это просто обёртка наdeque<bool>
/vector<bool>
. Любой из них прекрасно подойдёт и по типам, и по семантике, казалось бы. Разве чтоgetByte()
придётся отдельно написать, но это, имхо, и к лучшему — будет явно везде написано, что да, мы действительно берём только первые восемь бит. Сейчас это всё равно не "код Хаффмана" — вы его также используете и для записи целых байт в поток. - Не стоит завязываться на размер
size_t
, особенно если вы претендуете на кроссплатформенность, не завязываясь на endianness. - Очень странно, что потребовался
getNextByte
у битового потока. Он же нужен только для сжатия данных. А вы читаете и в обход потока, смreadUInt
. Лучше как-то чётко разделить. stats
вы везде считаете руками. Лучше это делать автоматически, посмотрев на позиции внутри потоков.>>
— странное обозначение для операции "считай байты и посчитай частоты". Я бы ожидал, что это именно чтение таблицы частот в каком-то виде.- Незачем записывать длину кодируемой последовательности в битах. Её ещё и считать муторно.
- Хорошо бы вызывать
padToByte()
в деструкторе, чтобы нельзя было случайно недозаписать данные. Или лучше — проверять, что он был вызван. - Надо разделить "бор" и "итератор по бору".
- Не может ли
Node
быть вообще приватной дляTrie
структурой? - Файл
Huffman.h
содержит дерево, вершины, кучу вершин (которая вообще деталь реализации алгоритма, равно как иNode::Compare
, не должны торчать из.cpp
) — как-то не очень название файла. HuffmanTrie
ничего специфичного для Хаффмана не имеет.getAllCodes()
должен возвращать вектор. Иначе неясна семантика в случае, когда вcodes
уже кто-то есть.- Так ли уж таблице частот надо читать не напрямую из
istream
, а черезIO::
?
Стиль 5/8
Flags
— скорее уже как раз не флаги, а полноценные настройки архиватора. От флагов создаютсяюCLIException
на самом деле может возникнуть только при парсинге аргументов. Лучше так и назвать.checkCompleteness()
—isComplete()
.Lack of arguments.
-->Not enough arguments specified
.- Смотри предупреждения компилятора выше.
CLI.cpp:69
— лишние скобочки.BYTESIZE
--> стандартныйCHAR_BIT
и можноstatic_assert
на его значение.- Конструктор
Code::Code
можно сделать при помощи конструктора от двух итераторов,copy
или чего-то такого. padToByte()
у писателя -->flush()
padToByte()
у читателя -->skipUntilByte()
- Не надо сбрасывать буфер в
operator<<(ostream&, const Statistics&)
HuffmanArchiver.cpp:27
— лишние скобки. И вообще это лучше посчитать не руками. а черезstd::count_if
.extract
/compress
— лучше чтобы соответствовали терминам из задания.- В
Archiver::extract
[мойте тарелки перед едой](http://blog.algoprog.ru/init-not-clear/). Huffman.cpp:19
— лишняя промежуточная переменная- Вместо
x == nullptr
лучше!x
comment:5 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 1.0 → 2.0 |
- Мне кажется
x != nullptr
более читабельно, чем!x
. extract/compress
— такие термины использованы в задании.- Публичная функция
getAllCodes(...)
и так возвращает вектор. Однако приватная принимает вектор по ссылке для удобной реализации.
comment:6 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
Very nice. Третья попытка разблокирована.
Корректность 9/9
Тесты 7/8
Bits
- Тесты на свойства — это хорошо, но вы так проверите лишь внутреннюю консистентность. Добавьте несколько тестов, которые проверяют, что вы порядок не перепутали, крайние случаи работают...
TestFrequencyTable
- Проверьте всё-таки все значения, а не выборочно. Пусть тест будет полным.
TestHuffmanTree
- Лучше проверьте ещё и сами коды, не только длины. Алгоритм-то однозначный.
- Не стоит завязываться на корректность
readAndCount
. А если уж и завязываетесь (тоже можно), то хотя бы символы отсортируйте, чтобы человек мог легко проверить. - Тесты на ноду не проверяют пустоту детей.
Архитектура 4/5
- Лучше все размеры в
unit64_t
. 32-битные файлы — это всего 4 ГБ, прошлый век. Tree
- Непонятный метод
Tree::getValue()
. Не надо вводить лишнее состояние. Tree::curNode
— это не поле класса, а параметр внутренних методов. Не надо вводить лишнее состояние. Это как писать dfs на глобальных переменных.- Заодно надо избавиться от методов
goLeft
/goRight
/goUp
(они заменятся на простой иф, станет сильно проще читать) и не надо хранитьparent
.
- Непонятный метод
Huffman::Tree::Node
можно определить прямо вHuffmanTree.cpp
..?- Non-movable
Writer
/Reader
— это очень странно. - Конструктор
Iterator
лучше всё-таки сделать приватным. - Для бора имена
goLeft
/goRight
звучат не так понятно, какgo(bool)
.- Ещё раз уж они всегда должны работать (судя по
assert(false)
) давайте перенесём этотassert
внутрь методов.
- Ещё раз уж они всегда должны работать (судя по
- Непонятно, зачем
CharReader
/CharWriter
— их методы подсчёта символов нигде не нужны. А вHuffmanArchiver.cpp:109
можно простоlength
поставить (см. замечание по стилю про это место)- Но если уж их и оставлять, то давайте
BitReader
/BitWriter
будут через них работать, а не сами считать байты.
- Но если уж их и оставлять, то давайте
Стиль 6/8
const
-->constexpr
- Если вы пытаетесь делать
Bits
общим и не зависеть отCHAR_BITS
(я рекомендую считать, что это всегда 8 и захардкодить), то тесты должны делать так же, а там есть число 255.- Но у вас ещё потенциально поедет конструкция
1u << CHAR_BITS
... Наверное... В общем, выпилитеCHAR_BITS
и предполагайте, что всегда 8 бит вchar
, пожалуйста, и добавьте на этоstatic_assert
.
- Но у вас ещё потенциально поедет конструкция
output1
/output2
—compressed
/extracted
или что-то такое.getRandomFibonacciString
— сделайтеreserve
- По названию
readAndCount
неясно, что происходит с предыдущими данными в таблице. iterator.getValue().value()
— что-то странное. Не должно быть надо так писать. Как минимум первыйgetValue()
должен называться по-другому. А, следовательно, и в самой вершине тоже.uint32_t
в качестве счётчика цикла, причём по умолчанию — ну такое,int
гораздо лучше. Если везде размерuint32_t
(а теперь будет 64) — окей, цикл по "размеру" тоже окей, но в общем случае надо всё-такиint
.- А где-то у вас вообще цикл
size_t i = 0; i < uint32_t
O_O
- А где-то у вас вообще цикл
- В конструкторе
CLI
можно неstd::string
, аstring_view
. Аналогично в параметрах сеттеров. Владение нужно уже только в полях. - У потоков ввода-вывода надо ещё и делать
clear()
послеseekg
, кажется? HuffmanArchiver
while
сif (...) { break; }
в конце можно заменить на простоwhile
NodeHeap
: почемуmultiset
?NodePointer
лучше принимать по значению
- Пустая строчка перед
private:
,public:
, пожалуйста Tree::Tree
- не хватает пустых строк между блоками
for
/if
- Строчка 47: явно хочу
assert
в веткеelse
- Там же можно просто конструктор вызвать
- не хватает пустых строк между блоками
Node::Node
— используйте member initialization list.- Конструкторы
Node
/Iterator
—noexcept
~BinaryWriter
— лучше поставтьassert
, что все биты записаны. Иначе молчаливо для пользователя в момент уничтожения что-то дописываем в файл, у него может выравнивание поехать.flush()
/dump()
— очень путаются названия.flush()
окей, но, возможно, стоит назвать метод, добавляющий нули, как-то явнее?- У
dump
/flush
очень жёсткий инвариант: битов не слишком много. Пусть проверяют. А ещё лучше — вызывать их на каждый чих, а хитрыеwhile
перенести внутрь их.
- У
comment:7 Changed 4 years ago by
P.S. Код непортируемый: нужен бинарный режим файлов. Корректность 8/9.
comment:8 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 2.0 → 3.0 |
- Конструктор
CLI
принимаетconst char**
, чтобы ему сразу можно было отдать аргументыmain
. Мне показалось странным сначала требовать сделать какие-то манипуляции, чтобы отдать аргументы, а уже потом отдавать.
Note: See
TracTickets for help on using
tickets.
Как обсудили в личке: пока не проверяю, потому что обновилось условие. Чтобы первую попытку не тратить.
Как будете готовы — поменяйте обратно на "ожидается проверка".