Added file_name and temp fields to FileTape
Removed explicit keyword before every constructor in FileTape Added getters for private fields in FileTape Made Tape's copy construcot marked as delete by default Implemented custom destrucor for FileTape Added explicit move and copy constructors to FileTape Added generate_tmp_file_name method to tape namespace Removed assets directory from tests - testing data should be provided in the test's cpp file
This commit is contained in:
parent
f3aaa26df8
commit
680ec28b57
6 changed files with 78 additions and 29 deletions
|
@ -52,10 +52,22 @@ const static int FT_SEEK_OFFSET = FT_CELL_SIZE + 1;
|
||||||
*/
|
*/
|
||||||
class FileTape : public Tape {
|
class FileTape : public Tape {
|
||||||
private:
|
private:
|
||||||
|
std::string file_name;
|
||||||
std::fstream file;
|
std::fstream file;
|
||||||
FileTapeSettings settings;
|
FileTapeSettings settings;
|
||||||
|
bool temp = false;
|
||||||
|
|
||||||
public:
|
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
|
* 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
|
* with the specified name, already filled with data. File must be read and
|
||||||
|
@ -64,8 +76,8 @@ class FileTape : public Tape {
|
||||||
* @param file_name Name of a file to be opened.
|
* @param file_name Name of a file to be opened.
|
||||||
* @param settings FileTape settings
|
* @param settings FileTape settings
|
||||||
*/
|
*/
|
||||||
explicit FileTape(const std::string &file_name,
|
FileTape(std::string file_name,
|
||||||
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of FileTape that will create and open a file
|
* Initializes a new instance of FileTape that will create and open a file
|
||||||
|
@ -76,8 +88,8 @@ class FileTape : public Tape {
|
||||||
* @param file_name Name of a file to be created and opened
|
* @param file_name Name of a file to be created and opened
|
||||||
* @param settings FileTape settings
|
* @param settings FileTape settings
|
||||||
*/
|
*/
|
||||||
explicit FileTape(size_t size, const std::string &file_name,
|
FileTape(size_t size, std::string file_name,
|
||||||
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of FileTape that will create and open a
|
* Initializes a new instance of FileTape that will create and open a
|
||||||
|
@ -86,8 +98,7 @@ class FileTape : public Tape {
|
||||||
* @param size Size of a newly created FileTape
|
* @param size Size of a newly created FileTape
|
||||||
* @param settings FileTape settings
|
* @param settings FileTape settings
|
||||||
*/
|
*/
|
||||||
explicit FileTape(size_t size,
|
FileTape(size_t size, FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||||
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Advances the underlying fstream to a new line.
|
* Advances the underlying fstream to a new line.
|
||||||
|
@ -116,6 +127,18 @@ class FileTape : public Tape {
|
||||||
* @param data Number, that should be written to the current line.
|
* @param data Number, that should be written to the current line.
|
||||||
*/
|
*/
|
||||||
void write(uint32_t data) override;
|
void write(uint32_t data) override;
|
||||||
|
|
||||||
|
~FileTape() override;
|
||||||
|
|
||||||
|
// Define getters in header file since they are implicitly inlined
|
||||||
|
|
||||||
|
bool is_temp() const { return this->temp; }
|
||||||
|
|
||||||
|
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
|
} // namespace tape
|
||||||
|
|
|
@ -17,11 +17,16 @@ namespace tape {
|
||||||
*/
|
*/
|
||||||
class Tape {
|
class Tape {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Compiler provided constructors and destructor definitions.
|
||||||
|
* Make move constructor and destructor default, copy construcotr delete,
|
||||||
|
* and allow destrucor to be overriden.
|
||||||
|
*/
|
||||||
Tape() = default;
|
Tape() = default;
|
||||||
Tape(const Tape &) = default;
|
Tape(const Tape &) = delete;
|
||||||
Tape(Tape &&) = delete;
|
Tape(Tape &&) = default;
|
||||||
Tape &operator=(const Tape &) = default;
|
Tape &operator=(const Tape &) = delete;
|
||||||
Tape &operator=(Tape &&) = delete;
|
Tape &operator=(Tape &&) = default;
|
||||||
virtual ~Tape() = default;
|
virtual ~Tape() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,6 @@ namespace tape {
|
||||||
|
|
||||||
void sort(Tape &input, Tape &output);
|
void sort(Tape &input, Tape &output);
|
||||||
|
|
||||||
}
|
} // namespace tape
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#include "filetape.h"
|
#include "filetape.h"
|
||||||
|
#include <filesystem>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using std::fstream;
|
using std::fstream;
|
||||||
using tape::FileTape;
|
using tape::FileTape;
|
||||||
|
|
||||||
FileTape::FileTape(const std::string &file_name, FileTapeSettings settings)
|
std::string generate_tmp_file_name() {
|
||||||
: settings(settings) {
|
std::array<char, L_tmpnam> tmp_file_name{};
|
||||||
this->file = fstream(file_name);
|
// tmpnam is unsafe, but its cross-platform
|
||||||
|
// TODO: make a safe, cross-platform tmp file handler
|
||||||
|
// (possibly utilizing std::filesystem::temp_directory_path())
|
||||||
|
std::tmpnam(tmp_file_name.data());
|
||||||
|
return tmp_file_name.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_file_with_empty_cells(size_t size, fstream &file) {
|
void fill_file_with_empty_cells(size_t size, fstream &file) {
|
||||||
|
@ -18,23 +23,25 @@ void fill_file_with_empty_cells(size_t size, fstream &file) {
|
||||||
file.seekg(0, fstream::beg);
|
file.seekg(0, fstream::beg);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileTape::FileTape(size_t size, const std::string &file_name,
|
FileTape::FileTape(std::string file_name, FileTapeSettings settings)
|
||||||
|
: settings(settings), file_name(file_name) {
|
||||||
|
this->file = fstream(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileTape::FileTape(size_t size, std::string file_name,
|
||||||
FileTapeSettings settings)
|
FileTapeSettings settings)
|
||||||
: FileTape(file_name, settings) {
|
: FileTape(file_name, settings) {
|
||||||
this->file =
|
this->file =
|
||||||
fstream(file_name, fstream::in | fstream::out | fstream::trunc);
|
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||||
fill_file_with_empty_cells(size, file);
|
fill_file_with_empty_cells(size, this->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileTape::FileTape(size_t size, FileTapeSettings settings)
|
FileTape::FileTape(size_t size, FileTapeSettings settings)
|
||||||
: settings(settings) {
|
: settings(settings), temp(true) {
|
||||||
std::array<char, L_tmpnam> file_name{};
|
this->file_name = generate_tmp_file_name();
|
||||||
// tmpnam is unsafe, but its cross-platform
|
|
||||||
// create a platform dependant tmp file handler later
|
|
||||||
std::tmpnam(file_name.data());
|
|
||||||
this->file =
|
this->file =
|
||||||
fstream(file_name.data(), fstream::in | fstream::out | fstream::trunc);
|
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||||
fill_file_with_empty_cells(size, file);
|
fill_file_with_empty_cells(size, this->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileTape::seek_backwards() {
|
bool FileTape::seek_backwards() {
|
||||||
|
@ -79,3 +86,10 @@ void FileTape::write(uint32_t data) {
|
||||||
this->file.write(cell.str().data(), FT_CELL_SIZE);
|
this->file.write(cell.str().data(), FT_CELL_SIZE);
|
||||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileTape::~FileTape() {
|
||||||
|
this->file.close();
|
||||||
|
if (this->is_temp()) {
|
||||||
|
std::filesystem::remove(this->file_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
0000000001
|
|
||||||
0000000002
|
|
||||||
0000000003
|
|
||||||
0000000004
|
|
||||||
0000000005
|
|
|
@ -1,6 +1,18 @@
|
||||||
#include "filetape.h"
|
#include "filetape.h"
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
const static std::string TEST_DATA = "0000000001\n"
|
||||||
|
"0000012345\n"
|
||||||
|
"0000000000\n"
|
||||||
|
"2222222222\n"
|
||||||
|
"4294967295";
|
||||||
|
|
||||||
|
tape::FileTape prepare_test_filetape() {
|
||||||
|
tape::FileTape tape(0);
|
||||||
|
|
||||||
|
return tape;
|
||||||
|
}
|
||||||
|
|
||||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||||
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
||||||
tape::FileTape tape(FILETAPE_TEST_FILE);
|
tape::FileTape tape(FILETAPE_TEST_FILE);
|
||||||
|
|
Loading…
Reference in a new issue