kmichaelk / yadro-cpp-test

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Сборка

В качестве системы сборки используется CMake, проект компилируется с помощью GCC или MinGW.

git clone https://github.com/kmichaelk/yadro-cpp-test
cd yadro-cpp-test
mkdir build
cd build
cmake ../
cmake --build .

После сборки в режиме Debug:

$ cd Debug

Запуск программы:

$ ./task <file>

Тестирование

Для автоматического тестирования написаны юнит-тесты для gtest и автоматизированная тестирующая программа cases_test, тестирующая все входные файлы *.txt из /cases с поиском решений в /cases/solutions.

Особенности

Программа имеет модульную структуру. Центральная часть программы - модель компьютерного клуба, хранящая информацию о своем состоянии, обрабатывающая и рассылающая события. Обработка непосредственных потоков ввода-вывода осуществляется в коде, компилируемом в исполняемый файл task.

В основе коммуникации между ними лежит событийная модель обработки данных с полиморфным классом полезной нагрузки: модель компьютерного клуба cclub принимает входящие события и рассылает исходящие всем подписанным на ее обновления слушателям. Для реализации чтения из входного потока и записи в выходной поток реализован вспомогательный класс event_stream, занимающийся десериализацией сообщенных ему событий и их дальнейшей переадресации в cclub.

При своем создании event_stream принимает на вход экземпляр cclub, в который в дальнейшем будет пересылать десериализованные события, и подписывает свой слушатель на его обновления. Каждое полученное событие добавляется в очередь для последующего извлечения.

В задании предлагается сначала прочитать все данные, а уже потом начать выводить результат - это оправданно из-за требования о выводе в случае некорректного ввода только одной строки - строки, вызвавшей сбой; если бы такового требования не было, то быстрее выводить данные сразу, такая реализация приведена в task_fast.

При неудачной десериализации поток переводится в состояние ошибки (std::ios::failbit) и обработка прерывается.

В силу специфики задания cclub рассылает не только исходящие, но и входящие события - логику сохранения входящих событий можно перенести и в event_stream, добавляя их в очередь перед отправкой в cclub.

Для соответствия требованиям задания был выбран такой способ хранения состояния модели клуба:

  • Каждый стол описывается выручкой, количеством проведеного за ним время и, если он не свободен, временем его занятия. Столы, с которыми не происходило никаких событий за время журналирования, хранить смысла нет, поэтому данные о столах представлены в виде хеш-таблицы с идентификатором стола в роли ключа и вышеописанной структурой в роли значения.
  • Данные о клиентах представлены в виде хеш-таблицы с идентификатором клиента (его именем) в роли ключа и структурой из опционального значения занимаемого клиентом стола и состояния его нахождения в очереди ожидания во избежание повторного включения.
  • Очередь ожидающих клиентов представлена в виде очереди константных указателей на идентификаторы клиентов - хранить копию может выйти слишком дорого, а std::unordered_map при модифицкации не инвалидирует ссылки на сами элементы (только на итераторы), что позволяет применить такую оптимизацию. В зависимости от соотношения операций записи и чтения, эффективнее может быть и упорядоченная таблица (std::map).

После закрытия клуба необходимо сообщить о выручке и занятых часах каждого стола, а также в алфавитном порядке исключить всех клиентов, оставшихся в клубе. Делается это всего лишь один раз, поэтому целесообразно упорядочить данные именно сейчас, а не хранить их упорядоченными все время. Для оптимизации использования памяти при упорядочивании этих данных используются не сами данные, а указатели на места, где они хранятся по факту. Инвалидация ссылок здесь не страшна, поскольку в процессе обработки соответствующие контейнеры модифицироваться не будут.

Неясно, должна ли выводиться информация о столах по порядку их идентификаторов, будем считать, что да. Чтобы, опять же, не хранить информацию о неиспользованных столах, воспользуемся этой особенностью и заполним "пробелы" в числовых промежутках строками, содержащими "пустую" информацию.

Примечания

  • В тексте задания не уточнено, когда и при каких условиях нужно добавлять клиента в очередь - будем считать, что клиент отправляется в очередь при получении входящего события об ожидании (ID#3).
  • В целях поддержки maintainability события представлены в виде перечисления, а вывод их названий осуществлен с помощью X Macro, генерирующего кейсы для блока switch. Одно из событий (ICanWaitNoLonger!) содержит в названии недопустимый для использования в качестве элемента перечисления символ, а именно восклицательный знак. На случай, если тестирование программы производится автоматически с использованием готового набора тестов, недостающий восклицательный знак выводится после дополнительной проверки.

About


Languages

Language:C++ 96.0%Language:CMake 3.4%Language:C 0.7%