Added using directives to avoid excessive namespaecs
Added explicit include directories to each file, even if an already included header defined them Removed using directives from header files
This commit is contained in:
parent
f8bfc78cad
commit
ad976a5a9e
10 changed files with 121 additions and 83 deletions
|
@ -1,19 +1,27 @@
|
|||
#include "tape_config.h"
|
||||
#include "tapelib/filetape.h"
|
||||
#include "tapelib/tape.h"
|
||||
#include "tapelib/tape_util.h"
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::milliseconds;
|
||||
using namespace tape;
|
||||
|
||||
size_t get_mem_peak() {
|
||||
const static std::string mem_info_file = "/proc/self/status";
|
||||
const static std::string mem_field = "VmPeak:";
|
||||
const static string mem_info_file = "/proc/self/status";
|
||||
const static string mem_field = "VmPeak:";
|
||||
std::ifstream status(mem_info_file);
|
||||
size_t mem = 0;
|
||||
std::string line;
|
||||
string line;
|
||||
while (std::getline(status, line)) {
|
||||
if (line.find(mem_field) != std::string::npos) {
|
||||
if (line.find(mem_field) != string::npos) {
|
||||
std::stringstream mem_line(line.substr(mem_field.size()));
|
||||
mem_line >> mem;
|
||||
return mem;
|
||||
|
@ -36,29 +44,27 @@ int main(int argc, char *argv[]) {
|
|||
!read_settings_from_file(settings)) {
|
||||
return -1;
|
||||
}
|
||||
tape::FileTape input(settings.input_file_name, settings.ft_settings);
|
||||
FileTape input(settings.input_file_name, settings.ft_settings);
|
||||
if (!input.is_open()) {
|
||||
std::cerr << "Failed to create INPUT tape - file not found or "
|
||||
"insufficient permissions"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
tape::FileTape output(input, settings.output_file_name,
|
||||
settings.ft_settings);
|
||||
FileTape output(input, settings.output_file_name, settings.ft_settings);
|
||||
if (!output.is_open()) {
|
||||
std::cerr << "Failed to create OUTPUT tape - insufficient permissions"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
// tmp tape factory that captures settings.ft_settings from local scope
|
||||
tape::TempTapeFactory factory =
|
||||
[&](size_t cells) -> std::unique_ptr<tape::Tape> {
|
||||
return std::make_unique<tape::FileTape>(
|
||||
tape::FileTape(cells, settings.ft_settings));
|
||||
TempTapeFactory factory = [&](size_t cells) -> std::unique_ptr<Tape> {
|
||||
return std::make_unique<FileTape>(
|
||||
FileTape(cells, settings.ft_settings));
|
||||
};
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
tape::external_sort(input, output, factory, settings.memory_limit);
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto start = high_resolution_clock::now();
|
||||
external_sort(input, output, factory, settings.memory_limit);
|
||||
auto end = high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<milliseconds>(end - start);
|
||||
std::cout << "Successfully sorted " << settings.input_file_name << " into "
|
||||
<< settings.output_file_name << std::endl;
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
#include "tape_config.h"
|
||||
#include "tapelib/filetape.h"
|
||||
#include <bits/getopt_core.h>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
const static struct std::vector<option> CMD_OPTS{
|
||||
{.name = "write-delay",
|
||||
|
@ -32,9 +39,9 @@ const static struct std::vector<option> CMD_OPTS{
|
|||
{.name = "help", .has_arg = no_argument, .flag = nullptr, .val = 'h'},
|
||||
{.name = nullptr, .has_arg = no_argument, .flag = nullptr, .val = 0}};
|
||||
|
||||
std::chrono::milliseconds parse_delay(const std::string &input) {
|
||||
milliseconds parse_delay(const string &input) {
|
||||
int delay_ms = std::stoi(input);
|
||||
return std::chrono::milliseconds(delay_ms);
|
||||
return milliseconds(delay_ms);
|
||||
}
|
||||
|
||||
AppSettings parse_command_line(int argc, char **argv) {
|
||||
|
@ -105,15 +112,15 @@ bool read_settings_from_file(AppSettings &settings) {
|
|||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string line;
|
||||
string line;
|
||||
size_t line_number = 1;
|
||||
while (std::getline(config, line)) {
|
||||
size_t delim_index = line.find(CFG_DELIMETER);
|
||||
if (delim_index >= line.size()) {
|
||||
continue;
|
||||
}
|
||||
std::string key = line.substr(0, delim_index);
|
||||
std::string value = line.substr(delim_index + 1);
|
||||
string key = line.substr(0, delim_index);
|
||||
string value = line.substr(delim_index + 1);
|
||||
try {
|
||||
if (key == "write-delay") {
|
||||
settings.ft_settings.write_delay = parse_delay(value);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define TAPE_CONFIG_H
|
||||
|
||||
#include "tapelib/filetape.h"
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
// stringizing opearator to convert macro into string literal
|
||||
#define xstr(s) str(s)
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
|
||||
#include "tape.h"
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
namespace tape {
|
||||
|
||||
/**
|
||||
|
@ -15,17 +16,17 @@ namespace tape {
|
|||
* such as read dealy, write delay etc.
|
||||
*/
|
||||
struct FileTapeSettings {
|
||||
milliseconds read_delay;
|
||||
milliseconds write_delay;
|
||||
milliseconds seek_forward_delay;
|
||||
milliseconds seek_backwards_delay;
|
||||
std::chrono::milliseconds read_delay;
|
||||
std::chrono::milliseconds write_delay;
|
||||
std::chrono::milliseconds seek_forward_delay;
|
||||
std::chrono::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)};
|
||||
FileTapeSettings{.read_delay = std::chrono::milliseconds(0),
|
||||
.write_delay = std::chrono::milliseconds(0),
|
||||
.seek_forward_delay = std::chrono::milliseconds(0),
|
||||
.seek_backwards_delay = std::chrono::milliseconds(0)};
|
||||
|
||||
const static char FT_DELIMETER = '\n';
|
||||
|
||||
|
|
|
@ -8,21 +8,19 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
using std::unique_ptr;
|
||||
|
||||
namespace tape {
|
||||
|
||||
/**
|
||||
* Lambda, which takes the amount of cells a tape should have and returns
|
||||
* a unique pointer to a temporary Tape with the specified amount of cells
|
||||
*/
|
||||
using TempTapeFactory = std::function<unique_ptr<Tape>(size_t)>;
|
||||
using TempTapeFactory = std::function<std::unique_ptr<Tape>(size_t)>;
|
||||
|
||||
/**
|
||||
* TempTapeFactory that creates a new temporary FileTape
|
||||
*/
|
||||
const static inline TempTapeFactory FILETAPE_FACTORY =
|
||||
[](size_t cells) -> unique_ptr<Tape> {
|
||||
[](size_t cells) -> std::unique_ptr<Tape> {
|
||||
return std::make_unique<FileTape>(FileTape(cells));
|
||||
};
|
||||
|
||||
|
|
|
@ -1,36 +1,43 @@
|
|||
#include "tapelib/filetape.h"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using std::fstream;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
using std::this_thread::sleep_for;
|
||||
using tape::FileTape;
|
||||
|
||||
std::string generate_tmp_file_name() {
|
||||
std::array<char, L_tmpnam> tmp_file_name{};
|
||||
// tmpnam is unsafe, but its cross-platform
|
||||
std::tmpnam(tmp_file_name.data());
|
||||
return tmp_file_name.data();
|
||||
}
|
||||
|
||||
FileTape::FileTape(const std::string file_name, const FileTapeSettings settings)
|
||||
FileTape::FileTape(const string file_name, const FileTapeSettings settings)
|
||||
: settings(settings), file_name(file_name) {
|
||||
this->file = fstream(file_name);
|
||||
}
|
||||
|
||||
FileTape::FileTape(const size_t cells, const std::string file_name,
|
||||
FileTape::FileTape(const size_t cells, const string file_name,
|
||||
const FileTapeSettings settings)
|
||||
: FileTape(file_name, settings) {
|
||||
this->file =
|
||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||
this->file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE) << '0';
|
||||
this->file << setfill('0') << setw(FT_CELL_SIZE) << '0';
|
||||
for (size_t i = 1; i < cells; i++) {
|
||||
this->file << FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(FT_CELL_SIZE) << '0';
|
||||
this->file << FT_DELIMETER << setfill('0') << setw(FT_CELL_SIZE) << '0';
|
||||
}
|
||||
this->file.seekg(0, fstream::beg);
|
||||
}
|
||||
|
@ -40,22 +47,21 @@ FileTape::FileTape(const size_t cells, const FileTapeSettings settings)
|
|||
this->tmp = true;
|
||||
}
|
||||
|
||||
FileTape::FileTape(FileTape &same_size_as, const std::string file_name,
|
||||
FileTape::FileTape(FileTape &same_size_as, const string file_name,
|
||||
const FileTapeSettings settings)
|
||||
: settings(settings), file_name(file_name) {
|
||||
this->file =
|
||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||
this->file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE) << '0';
|
||||
this->file << setfill('0') << setw(tape::FT_CELL_SIZE) << '0';
|
||||
while (same_size_as.seek_forward()) {
|
||||
file << tape::FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(tape::FT_CELL_SIZE) << '0';
|
||||
file << FT_DELIMETER << setfill('0') << setw(FT_CELL_SIZE) << '0';
|
||||
}
|
||||
this->file.seekg(0, fstream::beg);
|
||||
same_size_as.file.seekg(0, fstream::beg);
|
||||
}
|
||||
|
||||
FileTape::FileTape(FileTape &same_size_as, const FileTapeSettings settings)
|
||||
: tape::FileTape(same_size_as, generate_tmp_file_name(), settings) {
|
||||
: FileTape(same_size_as, generate_tmp_file_name(), settings) {
|
||||
this->tmp = true;
|
||||
}
|
||||
|
||||
|
@ -68,17 +74,16 @@ FileTape::FileTape(const std::vector<uint32_t> &data,
|
|||
if (data.empty()) {
|
||||
return;
|
||||
}
|
||||
this->file << std::setfill('0') << std::setw(FT_CELL_SIZE)
|
||||
<< std::to_string(data[0]);
|
||||
this->file << setfill('0') << setw(FT_CELL_SIZE) << to_string(data[0]);
|
||||
for (size_t i = 1; i < data.size(); i++) {
|
||||
this->file << FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(FT_CELL_SIZE) << std::to_string(data[i]);
|
||||
this->file << FT_DELIMETER << setfill('0') << setw(FT_CELL_SIZE)
|
||||
<< to_string(data[i]);
|
||||
}
|
||||
this->file.seekg(0, fstream::beg);
|
||||
}
|
||||
|
||||
bool FileTape::seek_backwards() {
|
||||
std::this_thread::sleep_for(this->settings.seek_backwards_delay);
|
||||
sleep_for(this->settings.seek_backwards_delay);
|
||||
if (this->file.tellg() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -87,7 +92,7 @@ bool FileTape::seek_backwards() {
|
|||
}
|
||||
|
||||
bool FileTape::seek_forward() {
|
||||
std::this_thread::sleep_for(this->settings.seek_forward_delay);
|
||||
sleep_for(this->settings.seek_forward_delay);
|
||||
this->file.seekg(FT_SEEK_OFFSET, fstream::cur);
|
||||
this->file.peek(); // peek to check if eof is reached
|
||||
if (this->file.eof()) {
|
||||
|
@ -99,7 +104,7 @@ bool FileTape::seek_forward() {
|
|||
}
|
||||
|
||||
uint32_t FileTape::read() {
|
||||
std::this_thread::sleep_for(this->settings.read_delay);
|
||||
sleep_for(this->settings.read_delay);
|
||||
uint32_t data = 0;
|
||||
this->file >> data;
|
||||
if (this->file.eof()) {
|
||||
|
@ -112,10 +117,9 @@ uint32_t FileTape::read() {
|
|||
}
|
||||
|
||||
void FileTape::write(const uint32_t data) {
|
||||
std::this_thread::sleep_for(this->settings.write_delay);
|
||||
sleep_for(this->settings.write_delay);
|
||||
std::stringstream cell;
|
||||
cell << std::setfill('0') << std::setw(FT_CELL_SIZE)
|
||||
<< std::to_string(data);
|
||||
cell << setfill('0') << setw(FT_CELL_SIZE) << to_string(data);
|
||||
this->file.write(cell.str().data(), FT_CELL_SIZE);
|
||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#include "tapelib/tape_util.h"
|
||||
#include "tapelib/tape.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::vector;
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
#include "tapelib/filetape.h"
|
||||
#include "tapelib/tape.h"
|
||||
#include "tapelib/tape_util.h"
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
const static std::vector<uint32_t> TEST_DATA = {123, 26, 87, 266, 111, 234,
|
||||
using std::vector;
|
||||
using namespace tape;
|
||||
|
||||
const static vector<uint32_t> TEST_DATA = {123, 26, 87, 266, 111, 234,
|
||||
6, 63, 28, 1, 90, 33};
|
||||
const static std::vector<uint32_t> TEST_DATA_SORTED = {
|
||||
1, 6, 26, 28, 33, 63, 87, 90, 111, 123, 234, 266};
|
||||
const static vector<uint32_t> TEST_DATA_SORTED = {1, 6, 26, 28, 33, 63,
|
||||
87, 90, 111, 123, 234, 266};
|
||||
|
||||
std::vector<uint32_t> read_from_tape_backwards(tape::Tape &tape) {
|
||||
std::vector<uint32_t> data;
|
||||
vector<uint32_t> read_from_tape_backwards(Tape &tape) {
|
||||
vector<uint32_t> data;
|
||||
do {
|
||||
data.push_back(tape.read());
|
||||
} while (tape.seek_backwards());
|
||||
|
@ -16,40 +23,39 @@ std::vector<uint32_t> read_from_tape_backwards(tape::Tape &tape) {
|
|||
return data;
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(*-magic-numbers)
|
||||
// NOLINTBEGIN
|
||||
TEST_CASE("Sorting FileTape with external sort", "[sort]") {
|
||||
tape::FileTape input(TEST_DATA);
|
||||
tape::FileTape output(input);
|
||||
FileTape input(TEST_DATA);
|
||||
FileTape output(input);
|
||||
|
||||
SECTION("Sorting with no limitations") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY);
|
||||
external_sort(input, output, FILETAPE_FACTORY);
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
|
||||
SECTION("Sorting with 4 elements in memory limit") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY, 4);
|
||||
external_sort(input, output, FILETAPE_FACTORY, 4);
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
|
||||
SECTION("Sorting with 9 elements in memory limit") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY, 9);
|
||||
external_sort(input, output, FILETAPE_FACTORY, 9);
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
|
||||
SECTION("Sorting with vector size elements in memory limit") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY,
|
||||
TEST_DATA.size());
|
||||
external_sort(input, output, FILETAPE_FACTORY, TEST_DATA.size());
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
|
||||
SECTION("Sorting with 1000 elements in memory limit") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY, 1000);
|
||||
external_sort(input, output, FILETAPE_FACTORY, 1000);
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
|
||||
SECTION("Sorting with 1 elements in memory limit") {
|
||||
tape::external_sort(input, output, tape::FILETAPE_FACTORY, 1);
|
||||
external_sort(input, output, FILETAPE_FACTORY, 1);
|
||||
REQUIRE(read_from_tape_backwards(output) == TEST_DATA_SORTED);
|
||||
}
|
||||
}
|
||||
// NOLINTEND(*-magic-numbers)
|
||||
// NOLINTEND
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#include "tapelib/filetape.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
const static std::vector<uint32_t> TEST_DATA = {1, 12345, 0, 2222222222,
|
||||
4294967295};
|
||||
using std::vector;
|
||||
using namespace tape;
|
||||
|
||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||
const static vector<uint32_t> TEST_DATA = {1, 12345, 0, 2222222222, 4294967295};
|
||||
|
||||
// NOLINTBEGIN
|
||||
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
||||
tape::FileTape tape(TEST_DATA);
|
||||
FileTape tape(TEST_DATA);
|
||||
|
||||
SECTION("Read all data sequentially") {
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
|
@ -38,7 +41,7 @@ TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
|||
}
|
||||
|
||||
TEST_CASE("Seeking forward and backwards", "[filetape]") {
|
||||
tape::FileTape tape(TEST_DATA);
|
||||
FileTape tape(TEST_DATA);
|
||||
|
||||
SECTION("Rewinding at the beginning of a file tape") {
|
||||
REQUIRE(tape.seek_backwards() == false);
|
||||
|
@ -67,7 +70,7 @@ TEST_CASE("Seeking forward and backwards", "[filetape]") {
|
|||
}
|
||||
|
||||
TEST_CASE("Writing to a file tape", "[filetape]") {
|
||||
tape::FileTape tape(3);
|
||||
FileTape tape(3);
|
||||
|
||||
tape.write(0);
|
||||
REQUIRE(tape.read() == 0);
|
||||
|
@ -83,4 +86,4 @@ TEST_CASE("Writing to a file tape", "[filetape]") {
|
|||
tape.write(4);
|
||||
REQUIRE(tape.read() == 4);
|
||||
}
|
||||
// NOLINTEND(readability-function-cognitive-complexity)
|
||||
// NOLINTEND
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
using namespace tape;
|
||||
|
||||
/**
|
||||
* Generate big input data sets for external sort testing.
|
||||
* Takes 2 positional arguments - first one is the ouput file name,
|
||||
|
@ -17,7 +23,7 @@ int main(int argc, char *argv[]) {
|
|||
std::cerr << "Not enough arguments" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::string out_name = argv[1]; // NOLINT
|
||||
string out_name = argv[1]; // NOLINT
|
||||
size_t cells = std::stoi(argv[2]); // NOLINT
|
||||
std::ofstream out(out_name);
|
||||
if (!out.is_open()) {
|
||||
|
@ -25,11 +31,10 @@ int main(int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
srand(time(nullptr));
|
||||
out << std::setfill('0') << std::setw(tape::FT_CELL_SIZE)
|
||||
<< std::to_string(rand());
|
||||
out << setfill('0') << setw(tape::FT_CELL_SIZE) << to_string(rand());
|
||||
for (size_t i = 1; i < cells; i++) {
|
||||
out << tape::FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(tape::FT_CELL_SIZE) << std::to_string(rand());
|
||||
out << FT_DELIMETER << setfill('0') << setw(tape::FT_CELL_SIZE)
|
||||
<< to_string(rand());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue