summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-11-10 15:14:54 -0600
committerDominick Allen <djallen@librehumanitas.org>2024-11-10 15:14:54 -0600
commit012df4bc38777c9053353ec2c4213bba67d63ab4 (patch)
tree4267c0cd4a7ed61119a44b31f0fc8b8adff2b4cf /include
parent1e89700693e92bb9c78ace739c71431b74d91e22 (diff)
Buffered file IO.
Diffstat (limited to 'include')
-rw-r--r--include/fud_drain.hpp2
-rw-r--r--include/fud_file.hpp119
-rw-r--r--include/fud_string.hpp17
-rw-r--r--include/fud_vector.hpp7
4 files changed, 116 insertions, 29 deletions
diff --git a/include/fud_drain.hpp b/include/fud_drain.hpp
index d630bc7..13c878a 100644
--- a/include/fud_drain.hpp
+++ b/include/fud_drain.hpp
@@ -32,6 +32,8 @@ struct DrainResult {
{
return status == FudStatus::Success;
}
+
+ constexpr bool operator==(const DrainResult&) const noexcept = default;
};
template <typename Sink, typename Source>
diff --git a/include/fud_file.hpp b/include/fud_file.hpp
index 7a53468..82f8291 100644
--- a/include/fud_file.hpp
+++ b/include/fud_file.hpp
@@ -18,13 +18,13 @@
#ifndef FUD_FILE_HPP
#define FUD_FILE_HPP
+#include "fud_drain.hpp"
#include "fud_option.hpp"
#include "fud_permissions.hpp"
#include "fud_result.hpp"
#include "fud_status.hpp"
#include "fud_string_view.hpp"
#include "fud_vector.hpp"
-#include "fud_drain.hpp"
#include <fcntl.h>
@@ -92,7 +92,8 @@ class OpenFlags {
return mode;
}
- constexpr uint32_t flags() const noexcept {
+ constexpr uint32_t flags() const noexcept
+ {
uint32_t openFlags = 0;
openFlags |= static_cast<uint32_t>(hasFlag(OpenFlagEnum::Append)) * O_APPEND;
openFlags |= static_cast<uint32_t>(hasFlag(OpenFlagEnum::Truncate)) * O_TRUNC;
@@ -125,18 +126,15 @@ using FileResult = Result<RegularFile, FudStatus>;
class RegularFile {
public:
- static FileResult open(
- StringView filename,
- FileAccessMode mode,
- OpenFlags flags,
- Option<int> dirFdoption);
+ friend class BufferedRegularFile;
+ static FileResult open(StringView filename, FileAccessMode mode, OpenFlags flags, Option<int> dirFdoption);
static FileResult create(
StringView filename,
FileAccessMode mode,
OpenFlags flags,
Permissions permissions,
- bool exclusive,
+ bool createOnly,
Option<int> dirFdOption);
FudStatus close();
@@ -145,13 +143,40 @@ class RegularFile {
Result<size_t, FudStatus> size() const;
+ constexpr int fileDescriptor() const
+ {
+ return m_fd;
+ }
+
+ [[nodiscard]] constexpr bool isOpen() const
+ {
+ return m_fd >= 0;
+ }
+
+ FudStatus seekStart();
+
+ FudStatus seekEnd();
+
+ FudStatus seek(size_t position);
+
+ /** \brief Write from source to file as sink. */
+ DrainResult write(const std::byte* source, size_t length, size_t maxExtraAttempts = 0);
+
+ DrainResult read(std::byte* sink, size_t length, size_t maxExtraAttempts = 0);
+
private:
- RegularFile() = default;
+ constexpr RegularFile() = default;
+
+ FudStatus validateIOParameters(const std::byte* source) const;
public:
RegularFile(const RegularFile& rhs) = delete;
- RegularFile(RegularFile&& rhs) noexcept;
+ constexpr RegularFile(RegularFile&& rhs) noexcept :
+ m_position{rhs.m_position}, m_fd{rhs.m_fd}, m_openFlags{rhs.m_openFlags}, m_modeFlags{rhs.m_modeFlags}
+ {
+ rhs.m_fd = -1;
+ }
~RegularFile();
@@ -160,28 +185,76 @@ class RegularFile {
RegularFile& operator=(RegularFile&& rhs) noexcept;
private:
+ size_t m_position{0};
int m_fd{-1};
OpenFlags m_openFlags{};
FileAccessMode m_modeFlags{};
};
-enum class ReadPolicy {
- Unbuffered,
- ReadAhead,
-};
-
class BufferedRegularFile {
-public:
+ public:
+ static BufferedRegularFile make(RegularFile&& file, Vector<std::byte>&& buffer = Vector<std::byte>::NullVector());
+
+ FudStatus close(bool discardBuffer);
+
/** \brief Write from source to file as sink. */
- DrainResult write(const std::byte* source, size_t sourceSize, size_t length, size_t offset);
+ DrainResult write(const std::byte* source, size_t length, Option<size_t> maxExtraAttempts);
+
/** \brief Read from file as source to sink. */
- DrainResult read(std::byte* sink, size_t sinkSize, size_t length, size_t offset);
-private:
- Vector<std::byte> m_readBuffer{Vector<std::byte>::NullVector()};
- Vector<std::byte> m_writeBuffer{Vector<std::byte>::NullVector()};
+ DrainResult read(std::byte* sink, size_t length, Option<size_t> maxExtraAttempts);
+
+ FudStatus setBuffer(Vector<std::byte>&& buffer, bool discardOldBuffer);
+
+ DrainResult flush(size_t maxExtraAttempts = 0);
+
+ void discard();
+
+ FudStatus resizeBuffer(size_t size);
+
+ FudStatus seekStart();
+
+ FudStatus seekEnd();
+
+ FudStatus seek(size_t position);
+
+ constexpr const RegularFile& file() const
+ {
+ return m_file;
+ }
+
+ constexpr RegularFile& file()
+ {
+ return m_file;
+ }
+
+ [[nodiscard]] constexpr bool bufferEmpty() const
+ {
+ return m_bufferLength == 0;
+ }
+
+ private:
+ constexpr BufferedRegularFile() noexcept = default;
+
+ constexpr BufferedRegularFile(RegularFile&& regularFile, Vector<std::byte>&& buffer) noexcept :
+ m_buffer{std::move(buffer)}, m_file{std::move(regularFile)}
+ {
+ }
+
+ Vector<std::byte> m_buffer{Vector<std::byte>::NullVector()};
+
RegularFile m_file;
- bool m_readBuffered{false};
- bool m_writeBuffered{false};
+
+ size_t m_bufferLength{0};
+ size_t m_bufferPosition{0};
+
+ enum class Operation : uint8_t
+ {
+ None,
+ Write,
+ Read
+ };
+
+ Operation m_lastOperation{Operation::None};
};
} // namespace fud
diff --git a/include/fud_string.hpp b/include/fud_string.hpp
index 935e1c1..a20b067 100644
--- a/include/fud_string.hpp
+++ b/include/fud_string.hpp
@@ -307,22 +307,31 @@ class String {
* length is greater than zero. */
Option<utf8> pop();
+ /** \brief Append a C string to the back of the string, growing it as necessary. */
FudStatus append(const char* source);
+ /** \brief Append a String to the back of the string, growing it as necessary. */
FudStatus append(const String& source);
+ /** \brief Append a StringView to the back of the string, growing it as necessary. */
FudStatus append(StringView source);
+ /** \brief Create a new string with the contents of this string and rhs. */
+ [[nodiscard]] StringResult catenate(const String& rhs) const;
+
+ /** \@copydoc String::catenate(const String& rhs) const */
+ [[nodiscard]] StringResult catenate(const char* rhs) const;
+
+ /** \brief Insert as much of source into the string as possible, returning
+ * how many bytes and the status of the insertion. */
DrainResult drain(const char* source);
+ /** @copydoc String::drain(const char* source) */
DrainResult drain(const String& source);
+ /** @copydoc String::drain(const char* source) */
DrainResult drain(StringView source);
- [[nodiscard]] StringResult catenate(const String& rhs) const;
-
- [[nodiscard]] StringResult catenate(const char* rhs) const;
-
[[nodiscard]] bool compare(const String& rhs) const;
FudStatus clear();
diff --git a/include/fud_vector.hpp b/include/fud_vector.hpp
index a2a0984..9159770 100644
--- a/include/fud_vector.hpp
+++ b/include/fud_vector.hpp
@@ -120,7 +120,7 @@ class Vector {
static Result<Vector<T>, FudStatus> withSize(size_t count, Allocator* allocator = &globalFudAllocator)
{
Vector<T> output{};
- auto status = initializeWithCapacity(output, count, allocator);
+ auto status = initializeWithSize(output, count, allocator);
if (status != FudStatus::Success) {
return FudError{status};
}
@@ -402,7 +402,10 @@ class Vector {
FudStatus clear()
{
if (m_allocator == nullptr || m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ if (m_length > 0) {
+ return FudStatus::ObjectInvalid;
+ }
+ return FudStatus::Success;
}
for (size_t index = 0; index < m_length; ++index) {
m_data[index].~T();