summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/fud_c_file.hpp262
-rw-r--r--include/fud_directory.hpp2
-rw-r--r--include/fud_sqlite.hpp2
-rw-r--r--include/fud_string.hpp2
-rw-r--r--source/fud_c_file.cpp199
-rw-r--r--source/fud_directory.cpp12
-rw-r--r--source/fud_sqlite.cpp20
-rw-r--r--source/fud_string.cpp21
8 files changed, 305 insertions, 215 deletions
diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp
index 9605ff0..45a8b54 100644
--- a/include/fud_c_file.hpp
+++ b/include/fud_c_file.hpp
@@ -18,8 +18,8 @@
#ifndef FUD_C_FILE_HPP
#define FUD_C_FILE_HPP
-#include "fud_status.hpp"
#include "fud_result.hpp"
+#include "fud_status.hpp"
#include "fud_string.hpp"
#include <cstdint>
@@ -88,77 +88,289 @@ struct [[nodiscard]] WriteResult {
FudStatus status{FudStatus::Success};
};
-class CBinaryFile {
+namespace detail {
+
+template <typename Derived>
+class CFile {
public:
- CBinaryFile(const String& filename, CFileMode mode);
+ [[nodiscard]] bool isOpen() const
+ {
+ const auto& self = static_cast<const Derived&>(*this);
+ return self.m_file != nullptr;
+ }
- CBinaryFile(const String& filename, CFileMode mode, const String& extraFlags);
+ FudStatus open()
+ {
+ auto& self = static_cast<Derived&>(*this);
+ if (!self.m_filename.valid()) {
+ return FudStatus::ObjectInvalid;
+ }
+ self.m_file = fopen(self.m_filename.c_str(), self.m_mode.c_str());
+ return self.m_file != nullptr ? FudStatus::Success : FudStatus::Failure;
+ }
- CBinaryFile(const CBinaryFile& rhs) = delete;
+ void close()
+ {
+ auto& self = static_cast<Derived&>(*this);
+ if (self.m_file != nullptr) {
+ fclose(self.m_file);
+ self.m_file = nullptr;
+ }
+ }
- ~CBinaryFile();
+ const FILE* file() const
+ {
+ const auto& self = static_cast<const Derived&>(*this);
+ return self.m_file;
+ }
- CBinaryFile& operator=(const CBinaryFile& rhs) = delete;
+ FILE* file()
+ {
+ auto& self = static_cast<Derived&>(*this);
+ return self.m_file;
+ }
- CBinaryFile& operator=(CBinaryFile&& rhs);
+ [[nodiscard]] Result<size_t, FudStatus> size() const
+ {
+ const auto& self = static_cast<const Derived&>(*this);
+ using RetType = Result<size_t, FudStatus>;
+ if (!self.isOpen()) {
+ return RetType::error(FudStatus::OperationInvalid);
+ }
- FudStatus open();
+ auto seekStatus = fseek(self.m_file, 0, SEEK_END);
+ if (seekStatus != 0) {
+ return RetType::error(FudStatus::Failure);
+ }
- void close();
+ auto fileSizeResult = ftell(self.m_file);
+ if (fileSizeResult < 0) {
+ return RetType::error(FudStatus::Failure);
+ }
- const FILE* file() const;
- [[nodiscard]] FILE* file();
+ auto fileSize = static_cast<size_t>(fileSizeResult);
- [[nodiscard]] bool isOpen() const;
+ auto resetStatus = self.reset();
+ if (resetStatus != FudStatus::Success) {
+ return RetType::error(resetStatus);
+ }
- [[nodiscard]] Result<size_t, FudStatus> size() const;
+ return RetType::okay(fileSize);
+ }
- [[nodiscard]] ReadResult read(void* destination, size_t destinationSize, size_t length);
+ [[nodiscard]] ReadResult read(void* destination, size_t destinationSize, size_t length)
+ {
+ auto& self = static_cast<Derived&>(*this);
+ return self.read(destination, destinationSize, length, 0);
+ }
- [[nodiscard]] ReadResult read(void* destination, size_t destinationSize, size_t length, size_t offset);
+ [[nodiscard]] ReadResult read(void* destination, size_t destinationSize, size_t length, size_t offset)
+ {
+ auto& self = static_cast<Derived&>(*this);
+ ReadResult result{};
+ if (length == 0) {
+ return result;
+ }
+
+ if (destination == nullptr) {
+ result.status = FudStatus::NullPointer;
+ return result;
+ }
+
+ if (offset > LONG_MAX || SIZE_MAX - offset < length || destinationSize < length) {
+ result.status = FudStatus::InvalidInput;
+ return result;
+ }
+
+ auto fileSizeResult = self.size();
+ if (fileSizeResult.isError()) {
+ result.status = fileSizeResult.getError();
+ return result;
+ }
+
+ auto fileSize = fileSizeResult.getOkay();
+ if (offset + length > fileSize) {
+ result.status = FudStatus::InvalidInput;
+ return result;
+ }
+
+ auto seekResult = fseek(self.m_file, static_cast<long>(offset), SEEK_SET);
+ if (seekResult != 0) {
+ result.status = FudStatus::Failure;
+ return result;
+ }
+
+ auto* destBytes = static_cast<char*>(destination);
+ result.bytesRead = fread(destBytes, 1, length, self.m_file);
+ static_cast<void>(self.reset());
+ if (result.bytesRead != length) {
+ result.status = FudStatus::Partial;
+ } else {
+ result.status = FudStatus::Success;
+ }
+
+ return result;
+ }
template <typename T>
[[nodiscard]] ReadResult read(T& destination, size_t length)
{
- return read(destination, length, 0);
+ auto& self = static_cast<Derived&>(*this);
+ return self.read(destination, length, 0);
}
template <typename T>
[[nodiscard]] ReadResult read(T& destination, size_t length, size_t offset)
{
- return read(&destination, sizeof(destination), length, offset);
+ auto& self = static_cast<Derived&>(*this);
+ return self.read(&destination, sizeof(destination), length, offset);
+ }
+
+ [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length)
+ {
+ auto& self = static_cast<Derived&>(*this);
+ auto offsetResult = self.size();
+ if (offsetResult.isError()) {
+ return WriteResult{0, offsetResult.getError()};
+ }
+
+ return self.write(source, sourceSize, length, offsetResult.getOkay());
}
- [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length);
+ [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length, size_t offset)
+ {
+ auto& self = static_cast<Derived&>(*this);
+ WriteResult result{};
+ if (length == 0) {
+ return result;
+ }
+
+ if (source == nullptr) {
+ result.status = FudStatus::NullPointer;
+ return result;
+ }
+
+ if (offset > LONG_MAX || SIZE_MAX - offset < length || sourceSize < length) {
+ result.status = FudStatus::InvalidInput;
+ return result;
+ }
+
+ auto fileSizeResult = size();
+ if (fileSizeResult.isError()) {
+ result.status = fileSizeResult.getError();
+ return result;
+ }
+
+ // TODO: find the proper way of handling a write beyond the end of the file
+ auto fileSize = fileSizeResult.getOkay();
+ int seekResult;
+ if (offset > fileSize) {
+ seekResult = fseek(self.m_file, 0, SEEK_END);
+ } else {
+ seekResult = fseek(self.m_file, static_cast<long>(offset), SEEK_SET);
+ }
+
+ if (seekResult != 0) {
+ result.status = FudStatus::Failure;
+ return result;
+ }
+
+ auto* sourceBytes = static_cast<const char*>(source);
+ result.bytesWritten = fwrite(sourceBytes, 1, length, self.m_file);
+ static_cast<void>(self.reset());
+ if (result.bytesWritten != length) {
+ result.status = FudStatus::Partial;
+ } else {
+ result.status = FudStatus::Success;
+ }
- [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length, size_t offset);
+ return result;
+ }
template <typename T>
[[nodiscard]] WriteResult write(const T& source)
{
- return write(source, sizeof(source), sizeof(source));
+ auto& self = static_cast<Derived&>(*this);
+ return self.write(source, sizeof(source), sizeof(source));
}
template <typename T>
[[nodiscard]] WriteResult write(const T& source, size_t sourceSize, size_t length)
{
+ auto& self = static_cast<Derived&>(*this);
auto offsetResult = size();
if (offsetResult.isError()) {
return WriteResult{0, offsetResult.getError()};
}
- return write(source, sourceSize, length, offsetResult.getOkay());
+ return self.write(source, sourceSize, length, offsetResult.getOkay());
}
template <typename T>
[[nodiscard]] WriteResult write(const T& source, size_t sourceSize, size_t length, size_t offset)
{
- return write(static_cast<const void*>(&source), sourceSize, length, offset);
+ auto& self = static_cast<Derived&>(*this);
+ return self.write(static_cast<const void*>(&source), sourceSize, length, offset);
}
+private:
+ FudStatus reset() const
+ {
+ const auto& self = static_cast<const Derived&>(*this);
+ if (!isOpen()) {
+ return FudStatus::OperationInvalid;
+ }
+ auto result = fseek(self.m_file, 0, SEEK_SET);
+ return result == 0 ? FudStatus::Success : FudStatus::Failure;
+ }
+};
+
+} // namespace detail
+
+class CBinaryFile : public detail::CFile<CBinaryFile> {
+ friend class CFile;
+
+ public:
+ CBinaryFile(const String& filename, CFileMode mode);
+
+ CBinaryFile(const String& filename, CFileMode mode, const String& extraFlags);
+
+ CBinaryFile(const CBinaryFile& rhs) = delete;
+
+ CBinaryFile(CBinaryFile&& rhs);
+
+ ~CBinaryFile();
+
+ CBinaryFile& operator=(const CBinaryFile& rhs) = delete;
+
+ CBinaryFile& operator=(CBinaryFile&& rhs);
private:
- FudStatus reset() const;
+ String m_filename;
+ String m_extraFlags{};
+ String m_mode;
+ CFileMode m_modeFlags;
+ FILE* m_file{nullptr};
+};
+
+class CTextFile : public detail::CFile<CTextFile> {
+ friend class CFile;
+
+ public:
+ CTextFile(const String& filename, CFileMode mode);
+
+ CTextFile(const String& filename, CFileMode mode, const String& extraFlags);
- const String m_filename;
+ CTextFile(const CTextFile& rhs) = delete;
+
+ CTextFile(CTextFile&& rhs);
+
+ ~CTextFile();
+
+ CTextFile& operator=(const CTextFile& rhs) = delete;
+
+ CTextFile& operator=(CTextFile&& rhs);
+
+ private:
+ String m_filename;
String m_extraFlags{};
String m_mode;
CFileMode m_modeFlags;
diff --git a/include/fud_directory.hpp b/include/fud_directory.hpp
index e6052c4..cd3576e 100644
--- a/include/fud_directory.hpp
+++ b/include/fud_directory.hpp
@@ -96,7 +96,7 @@ class Directory {
Directory(Directory&& rhs);
~Directory();
Directory& operator=(const Directory& rhs) = delete;
- Directory& operator=(Directory&& rhs);
+ Directory& operator=(Directory&& rhs) = delete;
constexpr const String& name() const {
return m_name;
diff --git a/include/fud_sqlite.hpp b/include/fud_sqlite.hpp
index 26e9de3..555e487 100644
--- a/include/fud_sqlite.hpp
+++ b/include/fud_sqlite.hpp
@@ -105,7 +105,7 @@ class SqliteStatement {
SqliteStatement& operator=(const SqliteStatement&) = delete;
- SqliteStatement& operator=(SqliteStatement&& rhs);
+ SqliteStatement& operator=(SqliteStatement&& rhs) = delete;
bool valid() const;
diff --git a/include/fud_string.hpp b/include/fud_string.hpp
index 9e423ef..cd8e8f1 100644
--- a/include/fud_string.hpp
+++ b/include/fud_string.hpp
@@ -126,6 +126,8 @@ class String {
const utf8* end() const;
private:
+ void cleanup();
+
using BufType = Array<utf8, SSO_BUF_SIZE>;
union {
BufType m_buffer{BufType::constFill(0)};
diff --git a/source/fud_c_file.cpp b/source/fud_c_file.cpp
index b323847..e2e71bf 100644
--- a/source/fud_c_file.cpp
+++ b/source/fud_c_file.cpp
@@ -34,186 +34,71 @@ CBinaryFile::CBinaryFile(const String& filename, CFileMode mode, const String& e
{
}
-CBinaryFile::~CBinaryFile() {
- close();
-}
-
-FudStatus CBinaryFile::open()
+CBinaryFile::CBinaryFile(CBinaryFile&& rhs) :
+ m_filename{std::move(rhs.m_filename)},
+ m_extraFlags{std::move(rhs.m_extraFlags)},
+ m_mode{std::move(rhs.m_mode)},
+ m_modeFlags{std::move(rhs.m_modeFlags)},
+ m_file{rhs.m_file}
{
- if (!m_filename.valid()) {
- return FudStatus::ObjectInvalid;
- }
- m_file = fopen(m_filename.c_str(), m_mode.c_str());
- return m_file != nullptr ? FudStatus::Success : FudStatus::Failure;
}
-void CBinaryFile::close()
-{
- if (m_file != nullptr) {
- fclose(m_file);
- m_file = nullptr;
- }
+CBinaryFile::~CBinaryFile() {
+ close();
}
-const FILE* CBinaryFile::file() const
+CBinaryFile& CBinaryFile::operator=(CBinaryFile&& rhs)
{
- return m_file;
-}
+ close();
-FILE* CBinaryFile::file()
-{
- return m_file;
-}
+ m_filename = std::move(rhs.m_filename);
+ m_extraFlags = std::move(rhs.m_extraFlags);
+ m_mode = std::move(rhs.m_mode);
+ m_modeFlags = std::move(rhs.m_modeFlags);
+ m_file = rhs.m_file;
-bool CBinaryFile::isOpen() const
-{
- return m_file != nullptr;
+ return *this;
}
-Result<size_t, FudStatus> CBinaryFile::size() const
+CTextFile::CTextFile(const String& filename, CFileMode mode)
+ : m_filename{filename},
+ m_mode{CTextFileModeFromFlags(mode)},
+ m_modeFlags{mode}
{
- using RetType = Result<size_t, FudStatus>;
- if (!isOpen()) {
- return RetType::error(FudStatus::OperationInvalid);
- }
-
- auto seekStatus = fseek(m_file, 0, SEEK_END);
- if (seekStatus != 0) {
- return RetType::error(FudStatus::Failure);
- }
-
- auto fileSizeResult = ftell(m_file);
- if (fileSizeResult < 0) {
- return RetType::error(FudStatus::Failure);
- }
-
- auto fileSize = static_cast<size_t>(fileSizeResult);
-
- auto resetStatus = reset();
- if (resetStatus != FudStatus::Success) {
- return RetType::error(resetStatus);
- }
-
- return RetType::okay(fileSize);
}
-ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t length)
+CTextFile::CTextFile(const String& filename, CFileMode mode, const String& extraFlags)
+ : m_filename{filename},
+ m_extraFlags{extraFlags},
+ m_mode{String(CTextFileModeFromFlags(mode)).catenate(extraFlags)},
+ m_modeFlags{mode}
{
- return read(destination, destinationSize, length, 0);
}
-ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t length, size_t offset)
+CTextFile::CTextFile(CTextFile&& rhs) :
+ m_filename{std::move(rhs.m_filename)},
+ m_extraFlags{std::move(rhs.m_extraFlags)},
+ m_mode{std::move(rhs.m_mode)},
+ m_modeFlags{std::move(rhs.m_modeFlags)},
+ m_file{rhs.m_file}
{
- ReadResult result{};
- if (length == 0) {
- return result;
- }
-
- if (destination == nullptr) {
- result.status = FudStatus::NullPointer;
- return result;
- }
-
- if (offset > LONG_MAX || SIZE_MAX - offset < length || destinationSize < length) {
- result.status = FudStatus::InvalidInput;
- return result;
- }
-
- auto fileSizeResult = size();
- if (fileSizeResult.isError()) {
- result.status = fileSizeResult.getError();
- return result;
- }
-
- auto fileSize = fileSizeResult.getOkay();
- if (offset + length > fileSize) {
- result.status = FudStatus::InvalidInput;
- return result;
- }
-
- auto seekResult = fseek(m_file, static_cast<long>(offset), SEEK_SET);
- if (seekResult != 0) {
- result.status = FudStatus::Failure;
- return result;
- }
-
- auto* destBytes = static_cast<char*>(destination);
- result.bytesRead = fread(destBytes, 1, length, m_file);
- static_cast<void>(reset());
- if (result.bytesRead != length) {
- result.status = FudStatus::Partial;
- } else {
- result.status = FudStatus::Success;
- }
-
- return result;
}
-WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t length)
-{
- auto offsetResult = size();
- if (offsetResult.isError()) {
- return WriteResult{0, offsetResult.getError()};
- }
-
- return write(source, sourceSize, length, offsetResult.getOkay());
+CTextFile::~CTextFile() {
+ close();
}
-WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t length, size_t offset)
+CTextFile& CTextFile::operator=(CTextFile&& rhs)
{
- WriteResult result{};
- if (length == 0) {
- return result;
- }
-
- if (source == nullptr) {
- result.status = FudStatus::NullPointer;
- return result;
- }
-
- if (offset > LONG_MAX || SIZE_MAX - offset < length || sourceSize < length) {
- result.status = FudStatus::InvalidInput;
- return result;
- }
-
- auto fileSizeResult = size();
- if (fileSizeResult.isError()) {
- result.status = fileSizeResult.getError();
- return result;
- }
-
- // TODO: proper way of handling this
- auto fileSize = fileSizeResult.getOkay();
- int seekResult;
- if (offset > fileSize) {
- seekResult = fseek(m_file, 0, SEEK_END);
- } else {
- seekResult = fseek(m_file, static_cast<long>(offset), SEEK_SET);
- }
-
- if (seekResult != 0) {
- result.status = FudStatus::Failure;
- return result;
- }
-
- auto* sourceBytes = static_cast<const char*>(source);
- result.bytesWritten = fwrite(sourceBytes, 1, length, m_file);
- static_cast<void>(reset());
- if (result.bytesWritten != length) {
- result.status = FudStatus::Partial;
- } else {
- result.status = FudStatus::Success;
- }
-
- return result;
-}
+ close();
+
+ m_filename = std::move(rhs.m_filename);
+ m_extraFlags = std::move(rhs.m_extraFlags);
+ m_mode = std::move(rhs.m_mode);
+ m_modeFlags = std::move(rhs.m_modeFlags);
+ m_file = rhs.m_file;
-FudStatus CBinaryFile::reset() const {
- if (!isOpen()) {
- return FudStatus::OperationInvalid;
- }
- auto result = fseek(m_file, 0, SEEK_SET);
- return result == 0 ? FudStatus::Success : FudStatus::Failure;
+ return *this;
}
} // namespace fud
diff --git a/source/fud_directory.cpp b/source/fud_directory.cpp
index 6df5bcc..6851158 100644
--- a/source/fud_directory.cpp
+++ b/source/fud_directory.cpp
@@ -115,18 +115,6 @@ Directory::Directory(Directory&& rhs) :
rhs.m_dirFd = -1;
}
-Directory& Directory::operator=(Directory&& rhs)
-{
- m_name = std::move(rhs.m_name);
- m_directory = rhs.m_directory;
- m_dirFd = rhs.m_dirFd;
-
- rhs.m_directory = nullptr;
- rhs.m_dirFd = -1;
-
- return *this;
-}
-
Directory::~Directory()
{
if (m_directory != nullptr) {
diff --git a/source/fud_sqlite.cpp b/source/fud_sqlite.cpp
index 7ad8a12..f573f1c 100644
--- a/source/fud_sqlite.cpp
+++ b/source/fud_sqlite.cpp
@@ -49,6 +49,11 @@ SqliteDb::~SqliteDb()
SqliteDb& SqliteDb::operator=(SqliteDb&& rhs)
{
+ if (m_dbHandle != nullptr) {
+ sqlite3_close(m_dbHandle);
+ m_dbHandle = nullptr;
+ }
+
m_name = std::move(rhs.m_name);
m_nameValid = rhs.m_nameValid;
m_dbHandle = rhs.m_dbHandle;
@@ -162,21 +167,6 @@ SqliteStatement::SqliteStatement(SqliteStatement&& rhs) :
rhs.m_preparedStatement = nullptr;
}
-SqliteStatement& SqliteStatement::operator=(SqliteStatement&& rhs)
-{
- m_input = std::move(rhs.m_input);
- m_tail = rhs.m_tail;
- m_status = rhs.m_status;
- m_errorCode = rhs.m_errorCode;
- m_preparedStatement = rhs.m_preparedStatement;
-
- rhs.m_tail = nullptr;
- rhs.m_status = FudStatus::ObjectInvalid;
- rhs.m_preparedStatement = nullptr;
-
- return *this;
-}
-
SqliteStatement::~SqliteStatement()
{
if (m_preparedStatement != nullptr) {
diff --git a/source/fud_string.cpp b/source/fud_string.cpp
index 97acb52..b10f6ee 100644
--- a/source/fud_string.cpp
+++ b/source/fud_string.cpp
@@ -95,14 +95,17 @@ String::String(String&& rhs) : m_length{rhs.m_length}, m_capacity{rhs.m_capacity
String::~String()
{
- if (isLarge() && m_data != nullptr) {
- fudFree(m_data);
- m_data = nullptr;
- }
+ cleanup();
}
String& String::operator=(const String& rhs)
{
+ if (this == &rhs) {
+ return *this;
+ }
+
+ cleanup();
+
m_length = rhs.m_length;
m_capacity = rhs.m_capacity;
if (rhs.valid()) {
@@ -118,6 +121,8 @@ String& String::operator=(const String& rhs)
String& String::operator=(String&& rhs)
{
+ cleanup();
+
m_length = rhs.m_length;
m_capacity = rhs.m_capacity;
if (rhs.isLarge()) {
@@ -130,6 +135,14 @@ String& String::operator=(String&& rhs)
return *this;
}
+void String::cleanup()
+{
+ if (isLarge() && m_data != nullptr) {
+ fudFree(m_data);
+ m_data = nullptr;
+ }
+}
+
bool String::nullTerminated() const
{
return data() != nullptr && m_length < m_capacity && data()[m_length] == '\0';