#ifndef FILE_TAPE_H #define FILE_TAPE_H #include "tape.h" #include #include #include using std::chrono::milliseconds; namespace tape { /** * Strcuture for storing all possible settings for a file tape, * such as read dealy, write delay etc. */ struct FileTapeSettings { milliseconds read_delay; milliseconds write_delay; milliseconds seek_forward_delay; milliseconds seek_backwards_delay; }; const static struct FileTapeSettings FT_DEFAULT_SETTINGS = FileTapeSettings{.read_delay = milliseconds(0), .write_delay = milliseconds(0), .seek_forward_delay = milliseconds(0), .seek_backwards_delay = milliseconds(0)}; const static char FT_DELIMETER = '\n'; // uint32_t digits max count is 10 const static int FT_CELL_SIZE = 10; const static int FT_SEEK_OFFSET = FT_CELL_SIZE + 1; /** * Mock tape implementation that uses text files as data source. * * Simulates tape operations by artificially pausing the execution of some * methods using time intervals, specified in command line arguments or a * configuration file. Each cell is represented as a plain text 32-bit unsigned * int, padded to FT_CELL_SIZE with leading zeroes, separated by FT_DELIMETER. * Each cell MUST be FT_CELL_SIZE long to correctly implement write operation * without re-writing the entire file. * * Example of a valid file for a FileTape * - example.txt * 000000001 * 000000034 * 000001234 * 123456789 * 000000000 */ class FileTape : public Tape { private: std::string file_name; std::fstream file; FileTapeSettings settings; bool tmp = false; public: /** * Creating copies of FileTape creates 2+ fstreams to one file, which * could introduce IO errors or data races if implemented incorrectly - * mark the copy constructor as deleted. Moving is fine. */ FileTape(const FileTape &) = delete; FileTape(FileTape &&) noexcept = default; FileTape &operator=(const FileTape &) = delete; FileTape &operator=(FileTape &&tape) = default; /** * Initializes a new instance of FileTape that will open an existing file * with the specified name, already filled with data. File must be read and * write accessible. * * @param file_name Name of a file to be opened. * @param settings FileTape settings */ FileTape(std::string file_name, FileTapeSettings settings = FT_DEFAULT_SETTINGS); /** * Initializes a new instance of FileTape that will create and open a file * with the specified name and fill it with *cells* amount of zeroed cells. * File must not exist and directory must be write accessible. * * Writing operations when filling file with zeroes will not introduce any * delay. * * @param size Size of a newly created FileTpae * @param file_name Name of a file to be created and opened * @param settings FileTape settings */ FileTape(size_t cells, std::string file_name, FileTapeSettings settings = FT_DEFAULT_SETTINGS); /** * Initializes a new instance of FileTape that will create and open a file * with the specified name and fill it with zeroed cells - the amount of * cells will be the same as the specified FileTape. * File must not exist and directory must be write accessible. * * This is necessary in the situations when the FileTapse size is a bigger * than size_t max value. Seeking will not introduce delay during this * operation. * * @param same_size_as FileTape, the size of which will be carried over to * the new FileTape * @param file_name Name of a file to be created and opened * @param settings FileTape settings */ FileTape(FileTape &same_size_as, std::string file_name, FileTapeSettings = FT_DEFAULT_SETTINGS); /** * Initializes a new instance of FileTape that will create and open a * temporary file and fill it with *cells* amount of zeroed cells. * * Writing operations when filling file with zeroes will not introduce any * delay. * * @param size Size of a newly created FileTape * @param settings FileTape settings */ FileTape(size_t cells, FileTapeSettings settings = FT_DEFAULT_SETTINGS); /** * Initializes a new instance of FileTape that will create and open a * temporary file and fill it with zeroed cells - * the amount of cells will be the same as the specified FileTape. File must * not exist and directory must be write accessible. * * This is necessary in the situations when the FileTapse size is a bigger * than size_t max value. Seeking will not introduce delay during this * operation. * * @param same_size_as FileTape, the size of which will be carried over to * the new FileTape * @param file_name Name of a file to be created and opened * @param settings FileTape settings */ FileTape(FileTape &same_size_as, FileTapeSettings = FT_DEFAULT_SETTINGS); /** * Initializes a new instance of FileTape that will create and open a * temporary file, and fill it with the data from the provided vector. * * Writing operations when copying vector to a FileTape will not have any * delay. * Use this constructor ONLY FOR TESTING. Do NOT use it to copy one * FileTape's data to another. * * @param data Vector of uint32 contents of which will be copied to FileTape * @param settings FileTape settings */ FileTape(const std::vector &data, FileTapeSettings settings = FT_DEFAULT_SETTINGS); /** * Advances the underlying fstream to a new line. * * @return false if empty line is reached, otherwise true. */ bool seek_forward() override; /** * Rewinds the underlying fstream to a previous line. * * @return false if called from the first line of a file, otherwise true. */ bool seek_backwards() override; /** * Reads and parses data from the current line. * * @return number from the line, or 0 if data can not be parsed. */ uint32_t read() override; /** * Writes data to the current line. * * @param data Number, that should be written to the current line. */ void write(uint32_t data) override; /** * Close the undetlying fstream, and, in case the FileTape is marked as * temporary (tmp is set to true), remove the temporary file */ ~FileTape() override; // Define getters in header file since they are implicitly inlined bool is_tmp() const { return this->tmp; } const FileTapeSettings &get_settings() const { return this->settings; } const std::string &get_file_name() const { return this->file_name; } const std::fstream &get_file() const { return this->file; } }; } // namespace tape #endif // !FILE_TAPE_H