#ifndef OSRM_STORAGE_IO_HPP_ #define OSRM_STORAGE_IO_HPP_ #include "util/exception.hpp" #include "util/fingerprint.hpp" #include "util/simple_logger.hpp" #include #include #include #include #include #include namespace osrm { namespace storage { namespace io { class FileReader { private: const std::string filename; boost::filesystem::ifstream input_stream; public: class LineWrapper : public std::string { friend std::istream &operator>>(std::istream &is, LineWrapper &line) { return std::getline(is, line); } }; auto GetLineIteratorBegin() { return std::istream_iterator(input_stream); } auto GetLineIteratorEnd() { return std::istream_iterator(); } enum FingerprintFlag { VerifyFingerprint, HasNoFingerprint }; FileReader(const std::string &filename, const FingerprintFlag flag) : FileReader(boost::filesystem::path(filename), flag) { } FileReader(const boost::filesystem::path &filename_, const FingerprintFlag flag) : filename(filename_.string()) { input_stream.open(filename_, std::ios::binary); if (!input_stream) throw util::exception("Error opening " + filename + ":" + std::strerror(errno)); if (flag == VerifyFingerprint && !ReadAndCheckFingerprint()) { throw util::exception("Fingerprint mismatch in " + filename); } } /* Read count objects of type T into pointer dest */ template void ReadInto(T *dest, const std::size_t count) { #if not defined __GNUC__ or __GNUC__ > 4 static_assert(std::is_trivially_copyable::value, "bytewise reading requires trivially copyable type"); #endif if (count == 0) return; const auto &result = input_stream.read(reinterpret_cast(dest), count * sizeof(T)); if (!result) { if (result.eof()) { throw util::exception("Error reading from " + filename + ": Unexpected end of file"); } throw util::exception("Error reading from " + filename + ": " + std::strerror(errno)); } } template void ReadInto(std::vector &target) { ReadInto(target.data(), target.size()); } template void ReadInto(T &target) { ReadInto(&target, 1); } template T ReadOne() { T tmp; ReadInto(tmp); return tmp; } template void Skip(const std::size_t element_count) { boost::iostreams::seek(input_stream, element_count * sizeof(T), BOOST_IOS::cur); } /*******************************************/ std::uint32_t ReadElementCount32() { return ReadOne(); } std::uint64_t ReadElementCount64() { return ReadOne(); } template void DeserializeVector(std::vector &data) { const auto count = ReadElementCount64(); data.resize(count); ReadInto(data.data(), count); } bool ReadAndCheckFingerprint() { auto fingerprint = ReadOne(); const auto valid = util::FingerPrint::GetValid(); // compare the compilation state stored in the fingerprint return valid.IsMagicNumberOK(fingerprint) && valid.TestContractor(fingerprint) && valid.TestGraphUtil(fingerprint) && valid.TestRTree(fingerprint) && valid.TestQueryObjects(fingerprint); } std::size_t Size() { auto current_pos = input_stream.tellg(); input_stream.seekg(0, input_stream.end); auto length = input_stream.tellg(); input_stream.seekg(current_pos, input_stream.beg); return length; } std::vector ReadLines() { std::vector result; std::string thisline; try { while (std::getline(input_stream, thisline)) { result.push_back(thisline); } } catch (const std::ios_base::failure &e) { // EOF is OK here, everything else, re-throw if (!input_stream.eof()) throw; } return result; } std::string ReadLine() { std::string thisline; try { std::getline(input_stream, thisline); } catch (const std::ios_base::failure &e) { // EOF is OK here, everything else, re-throw if (!input_stream.eof()) throw; } return thisline; } }; } } } #endif