From 2c953a8012d07d76ae7f08e5a73504499d3047e2 Mon Sep 17 00:00:00 2001 From: Jan Sucan Date: Sat, 18 Jan 2025 14:41:39 +0100 Subject: Rename buffered_file to buffered_stream --- src/backup.cpp | 12 ++-- src/buffered_file.cpp | 173 ------------------------------------------------ src/buffered_file.h | 84 ----------------------- src/buffered_stream.cpp | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ src/buffered_stream.h | 84 +++++++++++++++++++++++ src/format_v2.h | 11 +-- 6 files changed, 270 insertions(+), 267 deletions(-) delete mode 100644 src/buffered_file.cpp delete mode 100644 src/buffered_file.h create mode 100644 src/buffered_stream.cpp create mode 100644 src/buffered_stream.h diff --git a/src/backup.cpp b/src/backup.cpp index 238c3ae..b6b1471 100644 --- a/src/backup.cpp +++ b/src/backup.cpp @@ -25,7 +25,7 @@ */ #include "backup.h" -#include "buffered_file.h" +#include "buffered_stream.h" #include "format_v2.h" #include @@ -77,7 +77,7 @@ class PagedStreamReader m_buffers[0] = std::shared_ptr(new char[m_page_size_bytes]); m_buffers[1] = std::shared_ptr(new char[m_page_size_bytes]); } catch (const std::bad_alloc &e) { - throw BufferedFile::Error( + throw BufferedStream::Error( "cannot allocate pages for input stream data"); } }; @@ -114,7 +114,7 @@ class PagedStreamReader m_istream.read(data, m_page_size_bytes); if (!m_istream.good() && !m_istream.eof()) { - throw BufferedFile::Error("cannot read from stream"); + throw BufferedStream::Error("cannot read from stream"); } return m_istream.gcount(); @@ -387,13 +387,13 @@ backup(const OptionsBackup &opts) std::ifstream in_istream{opts.getInFilePath(), std::ifstream::in | std::ifstream::binary}; if (!in_istream) { - throw BufferedFile::Error("cannot open input file"); + throw BufferedStream::Error("cannot open input file"); } std::ifstream base_istream{opts.getBaseFilePath(), std::ifstream::in | std::ifstream::binary}; if (!base_istream) { - throw BufferedFile::Error("cannot open base file"); + throw BufferedStream::Error("cannot open base file"); } // When backing up, the output file is truncated to hold the new data @@ -401,7 +401,7 @@ backup(const OptionsBackup &opts) std::ofstream::trunc | std::ofstream::binary}; if (!out_ostream) { - throw BufferedFile::Error("cannot open output file"); + throw BufferedStream::Error("cannot open output file"); } DiffFinder diff_finder(base_istream, in_istream, opts.getBufferSize(), diff --git a/src/buffered_file.cpp b/src/buffered_file.cpp deleted file mode 100644 index 5ab5094..0000000 --- a/src/buffered_file.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright 2024 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "buffered_file.h" -#include "exception.h" - -#include -#include -#include -#include -#include - -namespace BufferedFile -{ - -Reader::Reader(std::istream &istream, size_t buffer_capacity) - : m_istream(istream), m_buffer_offset(0), m_buffer_size(0), - m_buffer_capacity(buffer_capacity) -{ - try { - m_buffer = std::make_unique(m_buffer_capacity); - } catch (const std::bad_alloc &e) { - throw Error("cannot allocate buffer for input file data"); - } -}; - -size_t -Reader::read(char *data, size_t data_size) -{ - size_t retry_count{0}; - size_t offset{0}; - - while ((data_size > 0) && (retry_count < 2)) { - char *d; - const size_t r{tryRead(data_size, &d)}; - if (r == 0) { - ++retry_count; - continue; - } - - memcpy(data + offset, d, r); - offset += r; - data_size -= r; - } - - return offset; -} - -size_t -Reader::tryRead(size_t data_size, char **return_data) -{ - const size_t size_left{m_buffer_size - m_buffer_offset}; - if (size_left == 0) { - refill_buffer(); - if (m_buffer_size == 0) { - return 0; - } - } - // There is at least one byte in the buffer - const size_t size_read{read_buffer(data_size, return_data)}; - assert(size_read > 0); - return size_read; -}; - -size_t -Reader::read_buffer(size_t data_size, char **return_data) -{ - *return_data = static_cast(m_buffer.get()) + m_buffer_offset; - - const size_t size_left{m_buffer_size - m_buffer_offset}; - const size_t size_read{std::min(data_size, size_left)}; - m_buffer_offset += size_read; - return size_read; -}; - -void -Reader::refill_buffer() -{ - m_buffer_size = read_file(m_buffer.get(), m_buffer_capacity); - m_buffer_offset = 0; -}; - -size_t -Reader::read_file(char *data, size_t data_size) -{ - m_istream.read(data, data_size); - - if (!m_istream.good() && !m_istream.eof()) { - throw Error("cannot read from file"); - } - - return m_istream.gcount(); -}; - -Writer::Writer(std::ostream &ostream, size_t buffer_capacity) - : m_ostream(ostream), m_buffer_size(0), m_buffer_capacity(buffer_capacity) -{ - try { - m_buffer = std::make_unique(m_buffer_capacity); - } catch (const std::bad_alloc &e) { - throw Error("cannot allocate buffer for output file data"); - } -}; -Writer::~Writer() { flush_buffer(); }; - -void -Writer::write(const char *data, size_t data_size) -{ - size_t free{m_buffer_capacity - m_buffer_size}; - if (data_size <= free) { - // There is free space in the buffer - write_buffer(data, data_size); - } else { - // No free space - flush_buffer(); - if (data_size <= m_buffer_capacity) { - // Data fits into the buffer - write_buffer(data, data_size); - } else { - // Doesn't fit - write_file(data, data_size); - } - } -}; - -void -Writer::write_buffer(const char *data, size_t data_size) -{ - memcpy(reinterpret_cast(m_buffer.get()) + m_buffer_size, data, - data_size); - m_buffer_size += data_size; -}; - -void -Writer::flush_buffer() -{ - write_file(m_buffer.get(), m_buffer_size); - m_buffer_size = 0; -}; - -void -Writer::write_file(const char *data, size_t data_size) -{ - m_ostream.write(data, data_size); - if (!m_ostream) { - throw Error("cannot write to output file"); - } -}; - -} // namespace BufferedFile diff --git a/src/buffered_file.h b/src/buffered_file.h deleted file mode 100644 index 23fa823..0000000 --- a/src/buffered_file.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2024 Ján Sučan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include "exception.h" - -#include -#include -#include - -namespace BufferedFile -{ - -class Error : public DiffddError -{ - public: - explicit Error(const std::string &message) : DiffddError(message) {} -}; - -class Reader -{ - public: - Reader(std::istream &istream, size_t buffer_capacity); - virtual ~Reader() = default; - - size_t read(char *data, size_t data_size); - size_t tryRead(size_t data_size, char **return_data); - - private: - std::istream &m_istream; - std::unique_ptr m_buffer; - size_t m_buffer_offset; - size_t m_buffer_size; - const size_t m_buffer_capacity; - - size_t read_buffer(size_t data_size, char **return_data); - void refill_buffer(); - size_t read_file(char *data, size_t data_size); -}; - -class Writer -{ - public: - Writer(std::ostream &ostream, size_t buffer_capacity); - virtual ~Writer(); - - void write(const char *data, size_t data_size); - - private: - std::ostream &m_ostream; - std::unique_ptr m_buffer; - size_t m_buffer_size; - const size_t m_buffer_capacity; - - void write_buffer(const char *data, size_t data_size); - void flush_buffer(); - void write_file(const char *data, size_t data_size); -}; - -} // namespace BufferedFile diff --git a/src/buffered_stream.cpp b/src/buffered_stream.cpp new file mode 100644 index 0000000..371e221 --- /dev/null +++ b/src/buffered_stream.cpp @@ -0,0 +1,173 @@ +/* Copyright 2024 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "buffered_stream.h" +#include "exception.h" + +#include +#include +#include +#include +#include + +namespace BufferedStream +{ + +Reader::Reader(std::istream &istream, size_t buffer_capacity) + : m_istream(istream), m_buffer_offset(0), m_buffer_size(0), + m_buffer_capacity(buffer_capacity) +{ + try { + m_buffer = std::make_unique(m_buffer_capacity); + } catch (const std::bad_alloc &e) { + throw Error("cannot allocate buffer for input stream data"); + } +}; + +size_t +Reader::read(char *data, size_t data_size) +{ + size_t retry_count{0}; + size_t offset{0}; + + while ((data_size > 0) && (retry_count < 2)) { + char *d; + const size_t r{tryRead(data_size, &d)}; + if (r == 0) { + ++retry_count; + continue; + } + + memcpy(data + offset, d, r); + offset += r; + data_size -= r; + } + + return offset; +} + +size_t +Reader::tryRead(size_t data_size, char **return_data) +{ + const size_t size_left{m_buffer_size - m_buffer_offset}; + if (size_left == 0) { + refill_buffer(); + if (m_buffer_size == 0) { + return 0; + } + } + // There is at least one byte in the buffer + const size_t size_read{read_buffer(data_size, return_data)}; + assert(size_read > 0); + return size_read; +}; + +size_t +Reader::read_buffer(size_t data_size, char **return_data) +{ + *return_data = static_cast(m_buffer.get()) + m_buffer_offset; + + const size_t size_left{m_buffer_size - m_buffer_offset}; + const size_t size_read{std::min(data_size, size_left)}; + m_buffer_offset += size_read; + return size_read; +}; + +void +Reader::refill_buffer() +{ + m_buffer_size = read_stream(m_buffer.get(), m_buffer_capacity); + m_buffer_offset = 0; +}; + +size_t +Reader::read_stream(char *data, size_t data_size) +{ + m_istream.read(data, data_size); + + if (!m_istream.good() && !m_istream.eof()) { + throw Error("cannot read from stream"); + } + + return m_istream.gcount(); +}; + +Writer::Writer(std::ostream &ostream, size_t buffer_capacity) + : m_ostream(ostream), m_buffer_size(0), m_buffer_capacity(buffer_capacity) +{ + try { + m_buffer = std::make_unique(m_buffer_capacity); + } catch (const std::bad_alloc &e) { + throw Error("cannot allocate buffer for output stream data"); + } +}; +Writer::~Writer() { flush_buffer(); }; + +void +Writer::write(const char *data, size_t data_size) +{ + size_t free{m_buffer_capacity - m_buffer_size}; + if (data_size <= free) { + // There is free space in the buffer + write_buffer(data, data_size); + } else { + // No free space + flush_buffer(); + if (data_size <= m_buffer_capacity) { + // Data fits into the buffer + write_buffer(data, data_size); + } else { + // Doesn't fit + write_stream(data, data_size); + } + } +}; + +void +Writer::write_buffer(const char *data, size_t data_size) +{ + memcpy(reinterpret_cast(m_buffer.get()) + m_buffer_size, data, + data_size); + m_buffer_size += data_size; +}; + +void +Writer::flush_buffer() +{ + write_stream(m_buffer.get(), m_buffer_size); + m_buffer_size = 0; +}; + +void +Writer::write_stream(const char *data, size_t data_size) +{ + m_ostream.write(data, data_size); + if (!m_ostream) { + throw Error("cannot write to output stream"); + } +}; + +} // namespace BufferedStream diff --git a/src/buffered_stream.h b/src/buffered_stream.h new file mode 100644 index 0000000..4b05a64 --- /dev/null +++ b/src/buffered_stream.h @@ -0,0 +1,84 @@ +/* Copyright 2024 Ján Sučan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "exception.h" + +#include +#include +#include + +namespace BufferedStream +{ + +class Error : public DiffddError +{ + public: + explicit Error(const std::string &message) : DiffddError(message) {} +}; + +class Reader +{ + public: + Reader(std::istream &istream, size_t buffer_capacity); + virtual ~Reader() = default; + + size_t read(char *data, size_t data_size); + size_t tryRead(size_t data_size, char **return_data); + + private: + std::istream &m_istream; + std::unique_ptr m_buffer; + size_t m_buffer_offset; + size_t m_buffer_size; + const size_t m_buffer_capacity; + + size_t read_buffer(size_t data_size, char **return_data); + void refill_buffer(); + size_t read_stream(char *data, size_t data_size); +}; + +class Writer +{ + public: + Writer(std::ostream &ostream, size_t buffer_capacity); + virtual ~Writer(); + + void write(const char *data, size_t data_size); + + private: + std::ostream &m_ostream; + std::unique_ptr m_buffer; + size_t m_buffer_size; + const size_t m_buffer_capacity; + + void write_buffer(const char *data, size_t data_size); + void flush_buffer(); + void write_stream(const char *data, size_t data_size); +}; + +} // namespace BufferedStream diff --git a/src/format_v2.h b/src/format_v2.h index a455035..4c3b7dc 100644 --- a/src/format_v2.h +++ b/src/format_v2.h @@ -24,6 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "buffered_stream.h" + #include #include @@ -42,7 +44,7 @@ class Writer { public: Writer(std::ostream &ostream, size_t buffer_size) - : m_writer{BufferedFile::Writer{ostream, buffer_size}} {}; + : m_writer{BufferedStream::Writer{ostream, buffer_size}} {}; void writeDiffRecord( uint64_t offset, size_t size, @@ -56,7 +58,7 @@ class Writer } private: - BufferedFile::Writer m_writer; + BufferedStream::Writer m_writer; void writeOffset(uint64_t offset) { @@ -80,7 +82,8 @@ class Reader { public: Reader(std::istream &istream, size_t buffer_size) - : m_reader{BufferedFile::Reader{istream, buffer_size}}, m_eof{false} {}; + : m_reader{BufferedStream::Reader{istream, buffer_size}}, m_eof{ + false} {}; bool eof() { return m_eof; }; @@ -112,7 +115,7 @@ class Reader }; private: - BufferedFile::Reader m_reader; + BufferedStream::Reader m_reader; bool m_eof; }; -- cgit v1.2.3