diff options
author | 2024-02-25 02:27:26 +1100 | |
---|---|---|
committer | 2024-02-25 02:27:26 +1100 | |
commit | 1615b8551a3a73532ac234973cfb04dd8ed98ba4 (patch) | |
tree | 25575506b4117afa614b94b4370af7f16eb9dbb5 /src/lib/util/ioprocs.cpp | |
parent | 334ec12e0043ef939be418283235e3dbe5a005fe (diff) |
util/ioprocs.cpp: Added wrappers for common patterns. (#11608)
emu/diimage.h: Removed fread overloads that allocate memory for output.
util/core_file.cpp: Changed output size of load to size_t.
Diffstat (limited to 'src/lib/util/ioprocs.cpp')
-rw-r--r-- | src/lib/util/ioprocs.cpp | 199 |
1 files changed, 143 insertions, 56 deletions
diff --git a/src/lib/util/ioprocs.cpp b/src/lib/util/ioprocs.cpp index 0477f1efae1..37a958713b3 100644 --- a/src/lib/util/ioprocs.cpp +++ b/src/lib/util/ioprocs.cpp @@ -20,6 +20,7 @@ #include <cstring> #include <iterator> #include <limits> +#include <new> #include <type_traits> @@ -120,14 +121,14 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { do_read(this->m_pointer, buffer, length, actual); this->m_pointer += actual; return std::error_condition(); } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { do_read(offset, buffer, length, actual); return std::error_condition(); @@ -239,7 +240,7 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { if (m_dangling_write) { @@ -270,7 +271,7 @@ public: return std::error_condition(); } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -338,7 +339,7 @@ public: return std::error_condition(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { if (m_dangling_read) { @@ -361,7 +362,7 @@ public: return std::error_condition(); } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -409,7 +410,7 @@ public: set_filler(fill); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -473,7 +474,7 @@ public: return std::error_condition(); } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -634,18 +635,12 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { - // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? - if (std::numeric_limits<std::uint32_t>::max() < length) - { - actual = 0U; - return std::errc::invalid_argument; - } - // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); std::uint32_t count; - std::error_condition err = file().read(buffer, m_pointer, std::uint32_t(length), count); + std::error_condition err = file().read(buffer, m_pointer, chunk, count); if (!err) { m_pointer += count; @@ -658,18 +653,12 @@ public: return err; } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { - // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? - if (std::numeric_limits<std::uint32_t>::max() < length) - { - actual = 0U; - return std::errc::invalid_argument; - } - // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); std::uint32_t count; - std::error_condition err = file().read(buffer, offset, std::uint32_t(length), count); + std::error_condition err = file().read(buffer, offset, chunk, count); if (!err) actual = std::size_t(count); else @@ -696,48 +685,146 @@ public: return file().flush(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { - actual = 0U; - while (length) + // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t count; + std::error_condition err = file().write(buffer, m_pointer, chunk, count); + if (!err) { - // actual length not valid on error - std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); - std::uint32_t written; - std::error_condition err = file().write(buffer, m_pointer, chunk, written); - if (err) - return err; - m_pointer += written; - buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; - length -= written; - actual += written; + actual = std::size_t(count); + m_pointer += count; } - return std::error_condition(); + else + { + actual = 0U; + } + return err; } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { - actual = 0U; - while (length) - { - // actual length not valid on error - std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); - std::uint32_t written; - std::error_condition err = file().write(buffer, offset, chunk, written); - if (err) - return err; - offset += written; - buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; - length -= written; - actual += written; - } - return std::error_condition(); + // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t count; + std::error_condition err = file().write(buffer, offset, chunk, count); + if (!err) + actual = std::size_t(count); + else + actual = 0U; + return err; } }; } // anonymous namespace +// helper functions for common patterns + +std::pair<std::error_condition, std::size_t> read(read_stream &stream, void *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t count; + std::error_condition err = stream.read_some(buffer, length, count); + actual += count; + if (!err) + { + if (!count) + break; + } + else if (std::errc::interrupted != err) + { + return std::make_pair(err, actual); + } + buffer = reinterpret_cast<std::uint8_t *>(buffer) + count; + length -= count; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read(read_stream &stream, std::size_t length) noexcept +{ + std::unique_ptr<std::uint8_t []> buffer(new (std::nothrow) std::uint8_t [length]); + if (!buffer) + return std::make_tuple(std::errc::not_enough_memory, std::move(buffer), std::size_t(0)); + auto [err, actual] = read(stream, buffer.get(), length); + return std::make_tuple(err, std::move(buffer), actual); +} + +std::pair<std::error_condition, std::size_t> read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t count; + std::error_condition err = stream.read_some_at(offset, buffer, length, count); + actual += count; + if (!err) + { + if (!count) + break; + } + else if (std::errc::interrupted != err) + { + return std::make_pair(err, actual); + } + offset += count; + buffer = reinterpret_cast<std::uint8_t *>(buffer) + count; + length -= count; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept +{ + std::unique_ptr<std::uint8_t []> buffer(new (std::nothrow) std::uint8_t [length]); + if (!buffer) + return std::make_tuple(std::errc::not_enough_memory, std::move(buffer), std::size_t(0)); + auto [err, actual] = read_at(stream, offset, buffer.get(), length); + return std::make_tuple(err, std::move(buffer), actual); +} + +std::pair<std::error_condition, std::size_t> write(write_stream &stream, void const *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t written; + std::error_condition err = stream.write_some(buffer, length, written); + actual += written; + if (err && (std::errc::interrupted != err)) + return std::make_pair(err, actual); + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::pair<std::error_condition, std::size_t> write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t written; + std::error_condition err = stream.write_some_at(offset, buffer, length, written); + actual += written; + if (err && (std::errc::interrupted != err)) + return std::make_pair(err, actual); + offset += written; + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + + // creating RAM read adapters random_read::ptr ram_read(void const *data, std::size_t size) noexcept |