From 6f4c6e84ae6bae5530da00ff561ff17b2241d65c Mon Sep 17 00:00:00 2001 From: Pepijn Schoen Date: Fri, 2 Dec 2016 19:17:22 +0100 Subject: [PATCH] Handle file output through a FileWriter, align interfaces for FileWriter and FileReader --- include/storage/io.hpp | 89 +++++++++++++++++++++++++++++++++++++----- include/util/io.hpp | 16 +++++--- unit_tests/util/io.cpp | 2 +- 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/include/storage/io.hpp b/include/storage/io.hpp index 4b4e66baaeb..e5121e7d656 100644 --- a/include/storage/io.hpp +++ b/include/storage/io.hpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -23,7 +22,7 @@ namespace io class FileReader { private: - const std::string filename; + const boost::filesystem::path filepath; boost::filesystem::ifstream input_stream; public: @@ -47,16 +46,16 @@ class FileReader { } - FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag) - : filename(filename_.string()) + FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag) + : filepath(filepath_) { - input_stream.open(filename_, std::ios::binary); + input_stream.open(filepath, std::ios::binary); if (!input_stream) - throw util::exception("Error opening " + filename + ":" + std::strerror(errno)); + throw util::exception("Error opening " + filepath.string()); if (flag == VerifyFingerprint && !ReadAndCheckFingerprint()) { - throw util::exception("Fingerprint mismatch in " + filename); + throw util::exception("Fingerprint mismatch in " + filepath.string()); } } @@ -77,10 +76,10 @@ class FileReader { if (result.eof()) { - throw util::exception("Error reading from " + filename + + throw util::exception("Error reading from " + filepath.string() + ": Unexpected end of file"); } - throw util::exception("Error reading from " + filename + ": " + std::strerror(errno)); + throw util::exception("Error reading from " + filepath.string()); } } @@ -170,6 +169,78 @@ class FileReader return thisline; } }; + +class FileWriter +{ + private: + const boost::filesystem::path filepath; + boost::filesystem::ofstream output_stream; + + public: + enum FingerprintFlag + { + GenerateFingerprint, + HasNoFingerprint + }; + + FileWriter(const std::string &filename, const FingerprintFlag flag) + : FileWriter(boost::filesystem::path(filename), flag) + { + } + + FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag) + : filepath(filepath_) + { + output_stream.open(filepath, std::ios::binary); + if (!output_stream) + throw util::exception("Error opening " + filepath.string()); + + if (flag == GenerateFingerprint) + { + WriteFingerprint(); + } + } + + /* Write count objects of type T from pointer src to output stream */ + template bool WriteFrom(T *src, const std::size_t count) + { +#if not defined __GNUC__ or __GNUC__ > 4 + static_assert(std::is_trivially_copyable::value, + "bytewise writing requires trivially copyable type"); +#endif + + if (count == 0) + return true; + + const auto &result = output_stream.write(reinterpret_cast(src), count * sizeof(T)); + if (!result) + { + throw util::exception("Error writing to " + filepath.string()); + } + + return static_cast(output_stream); + } + + template bool WriteFrom(T &target) { return WriteFrom(&target, 1); } + + template bool WriteOne(T tmp) { return WriteFrom(tmp); } + + bool WriteElementCount32(const std::uint32_t count) { return WriteOne(count); } + bool WriteElementCount64(const std::uint64_t count) { return WriteOne(count); } + + template bool SerializeVector(std::vector &data) + { + const auto count = data.size(); + WriteElementCount64(count); + return WriteFrom(data.data(), count); + } + + bool WriteFingerprint() + { + const auto fingerprint = util::FingerPrint::GetValid(); + return WriteOne(fingerprint); + } +}; } } } diff --git a/include/util/io.hpp b/include/util/io.hpp index 21d46d15371..28596cc41b0 100644 --- a/include/util/io.hpp +++ b/include/util/io.hpp @@ -54,7 +54,8 @@ template bool serializeVectorIntoAdjacencyArray(const std::string &filename, const std::vector> &data) { - std::ofstream out_stream(filename, std::ios::binary); + storage::io::FileWriter file(filename, storage::io::FileWriter::HasNoFingerprint); + std::vector offsets; offsets.reserve(data.size() + 1); std::uint64_t current_offset = 0; @@ -64,18 +65,23 @@ bool serializeVectorIntoAdjacencyArray(const std::string &filename, current_offset += vec.size(); offsets.push_back(boost::numeric_cast(current_offset)); } - if (!serializeVector(out_stream, offsets)) - return false; std::vector all_data; all_data.reserve(offsets.back()); for (auto const &vec : data) all_data.insert(all_data.end(), vec.begin(), vec.end()); - if (!serializeVector(out_stream, all_data)) + if (!file.SerializeVector(offsets)) + { return false; + } - return static_cast(out_stream); + if (!file.SerializeVector(all_data)) + { + return false; + } + + return true; } template diff --git a/unit_tests/util/io.cpp b/unit_tests/util/io.cpp index 9201e6d95c0..3836ee17388 100644 --- a/unit_tests/util/io.cpp +++ b/unit_tests/util/io.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(io_nonexistent_file) { std::cout << e.what() << std::endl; BOOST_REQUIRE(std::string(e.what()) == - "Error opening non_existent_test_io.tmp:No such file or directory"); + "Error opening non_existent_test_io.tmp"); } }