Handle file output through a FileWriter, align interfaces for FileWriter and FileReader
This commit is contained in:
parent
4b1aae40af
commit
6f4c6e84ae
@ -8,7 +8,6 @@
|
|||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
#include <boost/iostreams/seek.hpp>
|
#include <boost/iostreams/seek.hpp>
|
||||||
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@ -23,7 +22,7 @@ namespace io
|
|||||||
class FileReader
|
class FileReader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const std::string filename;
|
const boost::filesystem::path filepath;
|
||||||
boost::filesystem::ifstream input_stream;
|
boost::filesystem::ifstream input_stream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -47,16 +46,16 @@ class FileReader
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag)
|
FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag)
|
||||||
: filename(filename_.string())
|
: filepath(filepath_)
|
||||||
{
|
{
|
||||||
input_stream.open(filename_, std::ios::binary);
|
input_stream.open(filepath, std::ios::binary);
|
||||||
if (!input_stream)
|
if (!input_stream)
|
||||||
throw util::exception("Error opening " + filename + ":" + std::strerror(errno));
|
throw util::exception("Error opening " + filepath.string());
|
||||||
|
|
||||||
if (flag == VerifyFingerprint && !ReadAndCheckFingerprint())
|
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())
|
if (result.eof())
|
||||||
{
|
{
|
||||||
throw util::exception("Error reading from " + filename +
|
throw util::exception("Error reading from " + filepath.string() +
|
||||||
": Unexpected end of file");
|
": 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;
|
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 <typename T> bool WriteFrom(T *src, const std::size_t count)
|
||||||
|
{
|
||||||
|
#if not defined __GNUC__ or __GNUC__ > 4
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||||||
|
"bytewise writing requires trivially copyable type");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const auto &result = output_stream.write(reinterpret_cast<char *>(src), count * sizeof(T));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw util::exception("Error writing to " + filepath.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<bool>(output_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool WriteFrom(T &target) { return WriteFrom(&target, 1); }
|
||||||
|
|
||||||
|
template <typename T> bool WriteOne(T tmp) { return WriteFrom(tmp); }
|
||||||
|
|
||||||
|
bool WriteElementCount32(const std::uint32_t count) { return WriteOne<std::uint32_t>(count); }
|
||||||
|
bool WriteElementCount64(const std::uint64_t count) { return WriteOne<std::uint64_t>(count); }
|
||||||
|
|
||||||
|
template <typename T> bool SerializeVector(std::vector<T> &data)
|
||||||
|
{
|
||||||
|
const auto count = data.size();
|
||||||
|
WriteElementCount64(count);
|
||||||
|
return WriteFrom(data.data(), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteFingerprint()
|
||||||
|
{
|
||||||
|
const auto fingerprint = util::FingerPrint::GetValid();
|
||||||
|
return WriteOne(fingerprint);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,8 @@ template <typename simple_type>
|
|||||||
bool serializeVectorIntoAdjacencyArray(const std::string &filename,
|
bool serializeVectorIntoAdjacencyArray(const std::string &filename,
|
||||||
const std::vector<std::vector<simple_type>> &data)
|
const std::vector<std::vector<simple_type>> &data)
|
||||||
{
|
{
|
||||||
std::ofstream out_stream(filename, std::ios::binary);
|
storage::io::FileWriter file(filename, storage::io::FileWriter::HasNoFingerprint);
|
||||||
|
|
||||||
std::vector<std::uint32_t> offsets;
|
std::vector<std::uint32_t> offsets;
|
||||||
offsets.reserve(data.size() + 1);
|
offsets.reserve(data.size() + 1);
|
||||||
std::uint64_t current_offset = 0;
|
std::uint64_t current_offset = 0;
|
||||||
@ -64,18 +65,23 @@ bool serializeVectorIntoAdjacencyArray(const std::string &filename,
|
|||||||
current_offset += vec.size();
|
current_offset += vec.size();
|
||||||
offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset));
|
offsets.push_back(boost::numeric_cast<std::uint32_t>(current_offset));
|
||||||
}
|
}
|
||||||
if (!serializeVector(out_stream, offsets))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<simple_type> all_data;
|
std::vector<simple_type> all_data;
|
||||||
all_data.reserve(offsets.back());
|
all_data.reserve(offsets.back());
|
||||||
for (auto const &vec : data)
|
for (auto const &vec : data)
|
||||||
all_data.insert(all_data.end(), vec.begin(), vec.end());
|
all_data.insert(all_data.end(), vec.begin(), vec.end());
|
||||||
|
|
||||||
if (!serializeVector(out_stream, all_data))
|
if (!file.SerializeVector(offsets))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<bool>(out_stream);
|
if (!file.SerializeVector(all_data))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename simple_type, std::size_t WRITE_BLOCK_BUFFER_SIZE = 1024>
|
template <typename simple_type, std::size_t WRITE_BLOCK_BUFFER_SIZE = 1024>
|
||||||
|
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(io_nonexistent_file)
|
|||||||
{
|
{
|
||||||
std::cout << e.what() << std::endl;
|
std::cout << e.what() << std::endl;
|
||||||
BOOST_REQUIRE(std::string(e.what()) ==
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user