Это уже стало доброй традицией, что когда я еду в поезде или нахожусь в командировке, то вношу изменения в testlib. Видимо, причина тому — невозможность погрузиться в сложную задачу с большим контекстом по Polygon/Codeforces, но желание сделать что-то полезное здесь и сейчас.
Напоминаю, что testlib — мощная библиотека и стандард де-факто для подготовки задач по программированию, если вы используете С++. С помощью testlib можно значительно упростить подготовку: валидаторов, генераторов, чекеров и интеракторов. Все эти программы ниже буду называть testlib-программами.
Вот код ревизии, о которой идет речь. А вот ссылка с подсвеченными изменениями, которая может заменить весь текст поста. Как только будет понятно, что последние изменения финализированы, то будет выпущен новый релиз и обновим testlib в Полигоне. Выпущен релиз 0.9.4, который доступен со страницы загрузок.
Короткий список основных изменений:
Улучшена совместимость с компиляторами
В промежуточных версиях были сложности с компиляцией testlib-программ в Borland C++, некоторых версиях g++ и Microsoft Visual Studio C++. Всё это было исправлено, текущая версия компилируется в Borland C++ 5.6.4, g++ версий 0.7.2 и 0.8.1, Microsoft VS C++ версий 2005, 2008, 2010 и 2012.
Производительность
Сделаны некоторые улучшения производительности. Например, ранее ensure
(функция наподобие assert
, приводит к аварийному останову testlib-программы, если аргумент равен false
) приводил к созданию std::string даже, если вызов не приводил к аварийному останову.
Другое
- У InStream больше нет доступных конструктора копирования и оператора присваивания. Это запрещает передавать объекты InStream по значению, ведь такая передача является логической ошибкой.
- Добавлена функция
disableFinalizeGuard()
, чтобы отключить проверку вызова quitf в чекере и readEof в валидаторе перед выходом. Честно говоря, так и не понял зачем это надо было, но просили. Видимо, для каких-то хакерских целей из-за нетипичного использования testlib. - Добавлена функция
expectedButFound
для выхода с красивым сообщением. Вот примеры использования:expectedButFound(_wa, 5, 6)
— будет выход с _wa и сообщением типаexpected 5, but found 6
, еще примерexpectedButFound(_wa, 5, 6, "test case %d", 13)
завершит работу с _wa и сообщениемtest case 13: expected 5, but found 6
. Умеет сам красиво форматировать вещественные числа и сокращать сверхдлинные строки (добавлять в середине многоточие).
Создание InStream от строки
Теперь всю мощь InStream можно применять для произвольной строки. Т.е. вычитывать данные с помощью всяких readToken и проч. можно из произвольной строки. При создании InStream следует указать тот поток, от которого унаследуется поведение в случае ошибок. Например, InStream yesOrNo(inf, "YES")
. Может быть полезно в случае сложных разборов вывода (например, если удобно прочесть строку, что-то в ней проверить, а потом еще попарсить ее с помощью InStream).
Warnings
Неугомонный PavelKunyavskiy помог локализовать и закрыть пачку warnings в g++. В настоящее время testlib не порождает warnings даже при ключах -Wall -Wextra -Wconversion.
Опциональный новый вердикт: Unexpected EOF
Если скомпилировать с -DENABLE_UNEXPECTED_EOF, то при попытки прочитать что-то из потока произойдет вердикт unexpected eof
, если этого чего-то в потоке нет. Код выхода по умолчанию: 8. Полезно для интеракторов, так как иначе они могут путать некоторые вердикты.
Исправления ошибок
- выход с вердиктом о частичном решении класса 1, т.е. так:
quitf(_pc(1), "...message...")
; приводил к неправильному поведению; - генератор случайных чисел всегда оставлял один из битов нулевым (имеет значение только при генерации long long). Теперь рекомендуется явно указывать текущую версию генератора случайных чисел в генераторе вот так
registerGen(argc, argv, 1)
; - было некорректное поведение при чтении nan в качестве double на некоторых компиляторах;
- иногда неправильно обрабатывался дефис в паттернах для валидаторов/генераторов.