summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/ioprocs.cpp
diff options
context:
space:
mode:
author Vas Crabb <cuavas@users.noreply.github.com>2024-02-25 02:27:26 +1100
committer GitHub <noreply@github.com>2024-02-25 02:27:26 +1100
commit1615b8551a3a73532ac234973cfb04dd8ed98ba4 (patch)
tree25575506b4117afa614b94b4370af7f16eb9dbb5 /src/lib/util/ioprocs.cpp
parent334ec12e0043ef939be418283235e3dbe5a005fe (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.cpp199
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