summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--include/fud_allocator.hpp70
-rw-r--r--include/fud_directory.hpp11
-rw-r--r--include/fud_memory.hpp10
-rw-r--r--include/fud_result.hpp1
-rw-r--r--include/fud_status.hpp3
-rw-r--r--include/fud_string.hpp43
-rw-r--r--source/fud_allocator.cpp48
-rw-r--r--source/fud_c_file.cpp24
-rw-r--r--source/fud_directory.cpp98
-rw-r--r--source/fud_sqlite.cpp5
-rw-r--r--source/fud_string.cpp105
-rw-r--r--source/libfud.cpp2
-rw-r--r--test/CMakeLists.txt6
-rw-r--r--test/test_common.cpp2
-rw-r--r--test/test_directory.cpp13
-rw-r--r--test/test_string.cpp8
17 files changed, 313 insertions, 144 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cea07dd..0644d2d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ find_package(SQLite3 REQUIRED)
add_library(fud SHARED
source/libfud.cpp
+ source/fud_allocator.cpp
source/fud_assert.cpp
source/fud_memory.cpp
source/fud_c_file.cpp
@@ -87,21 +88,22 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FudConfig.cmake
set(FUD_HEADERS
"include/libfud.hpp"
+ "include/fud_allocator.hpp"
"include/fud_array.hpp"
"include/fud_assert.hpp"
"include/fud_c_file.hpp"
+ "include/fud_directory.hpp"
"include/fud_fud_type_traits.hpp"
"include/fud_memory.hpp"
+ "include/fud_permissions.hpp"
"include/fud_result.hpp"
"include/fud_status.hpp"
"include/fud_string.hpp"
"include/fud_string_view.hpp"
+ "include/fud_sqlite.hpp"
"include/fud_unique_array.hpp"
"include/fud_utf8.hpp"
"include/fud_utf8_iterator.hpp"
- "include/fud_sqlite.hpp"
- "include/fud_directory.hpp"
- "include/fud_permissions.hpp"
)
set_target_properties(fud PROPERTIES PUBLIC_HEADER "${FUD_HEADERS}")
diff --git a/include/fud_allocator.hpp b/include/fud_allocator.hpp
new file mode 100644
index 0000000..8955fae
--- /dev/null
+++ b/include/fud_allocator.hpp
@@ -0,0 +1,70 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FUD_ALLOCATOR_HPP
+#define FUD_ALLOCATOR_HPP
+
+#include "fud_result.hpp"
+#include "fud_status.hpp"
+
+#include <cstddef>
+#include <limits>
+
+namespace fud {
+
+class Allocator {
+ public:
+ virtual ~Allocator() = default;
+
+ virtual Result<void*, FudStatus> allocate(size_t bytes, size_t alignment = alignof(std::max_align_t)) = 0;
+
+ /* ...should this be void? */
+ virtual void deallocate(void* pointer, size_t bytes, size_t alignment = alignof(std::max_align_t)) = 0;
+
+ virtual bool isEqual(const Allocator& rhs) const = 0;
+};
+
+constexpr bool operator==(const Allocator& lhs, const Allocator& rhs) {
+ return &lhs == &rhs;
+}
+
+class FudAllocator : public Allocator {
+ public:
+ virtual ~FudAllocator() override = default;
+
+ virtual Result<void*, FudStatus> allocate(size_t bytes, size_t alignment = alignof(std::max_align_t)) override;
+
+ /* ...should this be void? */
+ virtual void deallocate(void* pointer, size_t bytes, size_t alignment = alignof(std::max_align_t)) override;
+
+ virtual bool isEqual(const Allocator& rhs) const override;
+};
+
+extern FudAllocator globalFudAllocator;
+
+/** \brief The default allocation function for globalFudAllocator. */
+extern void* fudAlloc(size_t size);
+
+/** \brief The default allocation function for globalFudAllocator. */
+extern void* fudRealloc(void* ptr, size_t size);
+
+extern void fudFree(void* ptr);
+
+
+} // namespace fud
+
+#endif
diff --git a/include/fud_directory.hpp b/include/fud_directory.hpp
index ca94528..d2bd53d 100644
--- a/include/fud_directory.hpp
+++ b/include/fud_directory.hpp
@@ -91,7 +91,8 @@ struct DirectoryEntry {
class Directory {
public:
- explicit Directory(const String& name);
+ // explicit Directory(const String& name);
+ static Result<Directory, FudStatus> make(const String& name);
Directory(const Directory& rhs) = delete;
Directory(Directory&& rhs) noexcept;
~Directory();
@@ -102,11 +103,6 @@ class Directory {
return m_name;
}
- constexpr FudStatus status() const
- {
- return m_status;
- }
-
constexpr int errorCode() const
{
return m_errorCode;
@@ -119,11 +115,10 @@ class Directory {
FudStatus reset();
private:
- bool valid() const;
+ Directory() = default;
String m_name{};
DIR* m_directory{nullptr};
- FudStatus m_status{FudStatus::ObjectInvalid};
int m_errorCode{-1};
int m_dirFd{-1};
};
diff --git a/include/fud_memory.hpp b/include/fud_memory.hpp
index 62ff81a..97328a9 100644
--- a/include/fud_memory.hpp
+++ b/include/fud_memory.hpp
@@ -27,16 +27,6 @@
namespace fud {
-extern void* fudAlloc(size_t size);
-extern void* fudRealloc(void* ptr, size_t size);
-extern void fudFree(void* ptr);
-
-// An allocating function which returns null on failure.
-using FudAllocOne = void(*)(size_t);
-
-// An allocating function which returns null on failure.
-using FudAllocMany = void(*)(size_t, size_t);
-
/** \brief Copies from source to destination count bytes.
*
* \retcode FudStatus::Success
diff --git a/include/fud_result.hpp b/include/fud_result.hpp
index 3acf776..5dabaf5 100644
--- a/include/fud_result.hpp
+++ b/include/fud_result.hpp
@@ -27,6 +27,7 @@ template <typename T, typename E>
class [[nodiscard]] Result {
public:
using ResultType = Result<T, E>;
+
static ResultType okay(const T& okay)
{
return ResultType{okay};
diff --git a/include/fud_status.hpp b/include/fud_status.hpp
index f8f7687..5ebf229 100644
--- a/include/fud_status.hpp
+++ b/include/fud_status.hpp
@@ -38,6 +38,7 @@ enum class [[nodiscard]] FudStatus
Full,
RangeError,
VariantInvalid,
+ BadArrayLength,
NotImplemented,
NotSupported
};
@@ -77,6 +78,8 @@ constexpr const char* FudStatusToString(FudStatus status)
return "RangeError";
case FudStatus::VariantInvalid:
return "VariantInvalid";
+ case FudStatus::BadArrayLength:
+ return "BadArrayLength";
case FudStatus::NotImplemented:
return "NotImplemented";
case FudStatus::NotSupported:
diff --git a/include/fud_string.hpp b/include/fud_string.hpp
index 6880cb7..4367aae 100644
--- a/include/fud_string.hpp
+++ b/include/fud_string.hpp
@@ -18,6 +18,7 @@
#ifndef FUD_STRING_HPP
#define FUD_STRING_HPP
+#include "fud_allocator.hpp"
#include "fud_assert.hpp"
#include "fud_result.hpp"
#include "fud_status.hpp"
@@ -40,18 +41,25 @@ class String {
public:
static StringResult makeFromCString(const char* cString);
- static StringResult makeFromUtf8(const utf8* utf8String);
+ static StringResult makeFromCString(const char* cString, Allocator* allocator);
- template <typename... Strings>
- static StringResult makeFromCString(Strings... cStrings)
+ template <typename... CStrings>
+ static StringResult makeFromCStrings(CStrings... cStrings)
{
+ return makeFromCStringsAlloc(&globalFudAllocator, cStrings...);
+ }
+
+ template <typename... CStrings>
+ static StringResult makeFromCStringsAlloc(Allocator* allocator, CStrings... cStrings)
+ {
+ if (allocator == nullptr) {
+ return StringResult::error(FudStatus::NullPointer);
+ }
size_t totalLength = 0;
Array<size_t, sizeof...(cStrings)> lengths{};
Array<const char*, sizeof...(cStrings)> strPointers{};
size_t index = 0;
for (const auto* cStringItem: {cStrings...}) {
- // for (size_t index = 0; index < strPointers.size(); ++index) {
- // const auto* cString = strPointers[index];
const char* cString = nullptr;
if constexpr (std::is_same_v<decltype(cStringItem), const char*>) {
cString = cStringItem;
@@ -78,13 +86,14 @@ class String {
String output{};
auto* data = output.m_buffer.data();
output.m_length = totalLength;
+ output.m_allocator = allocator;
if (output.m_length >= output.m_capacity) {
output.m_capacity = output.m_length + 1;
- data = static_cast<utf8*>(fudAlloc(output.m_capacity));
- if (data == nullptr) {
- return StringResult::error(FudStatus::AllocFailure);
+ auto dataResult = output.m_allocator->allocate(output.m_capacity);
+ if (dataResult.isError()) {
+ return StringResult::error(dataResult.getError());
}
- output.m_data = data;
+ output.m_data = static_cast<utf8*>(dataResult.getOkay());
}
size_t cumulativeLength = 0;
@@ -102,14 +111,21 @@ class String {
}
String() noexcept = default;
- String(const String& rhs);
+
+ String(const String& rhs) = delete;
+
String(String&& rhs) noexcept;
~String();
- String& operator=(const String& rhs);
+ String& operator=(const String& rhs) = delete;
+
String& operator=(String&& rhs) noexcept;
+ static StringResult from(const String& rhs);
+
+ FudStatus copy(const String& rhs);
+
[[nodiscard]] constexpr size_t length() const
{
return m_length;
@@ -206,6 +222,7 @@ class String {
private:
void cleanup();
+
FudStatus resize(size_t newCapacity);
using BufType = Array<utf8, SSO_BUF_SIZE>;
@@ -213,13 +230,17 @@ class String {
BufType m_buffer{BufType::constFill(0)};
utf8* m_data;
};
+
size_t m_length{0};
+
size_t m_capacity{SSO_BUF_SIZE};
[[nodiscard]] constexpr bool isLarge() const
{
return m_capacity > SSO_BUF_SIZE;
}
+
+ Allocator* m_allocator{&globalFudAllocator};
};
} // namespace fud
diff --git a/source/fud_allocator.cpp b/source/fud_allocator.cpp
new file mode 100644
index 0000000..b5af593
--- /dev/null
+++ b/source/fud_allocator.cpp
@@ -0,0 +1,48 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fud_allocator.hpp"
+
+namespace fud {
+
+Result<void*, FudStatus> FudAllocator::allocate(size_t bytes, size_t alignment)
+{
+ using RetType = Result<void*, FudStatus>;
+ static_cast<void>(alignment);
+ auto* pointer = static_cast<std::byte*>(fudAlloc(bytes));
+ if (pointer == nullptr) {
+ return RetType::error(FudStatus::AllocFailure);
+ }
+ return RetType::okay(pointer);
+}
+
+void FudAllocator::deallocate(void* pointer, size_t bytes, size_t alignment)
+{
+ static_cast<void>(bytes);
+ static_cast<void>(alignment);
+ fudFree(pointer);
+}
+
+bool FudAllocator::isEqual(const Allocator& rhs) const
+{
+ /* Is this legit? Or is this a bogus check? */
+ return &rhs == static_cast<const Allocator*>(this);
+}
+
+FudAllocator globalFudAllocator{};
+
+} // namespace fud
diff --git a/source/fud_c_file.cpp b/source/fud_c_file.cpp
index a63923a..15c57ab 100644
--- a/source/fud_c_file.cpp
+++ b/source/fud_c_file.cpp
@@ -30,7 +30,10 @@ CBinaryFileResult CBinaryFile::make(const String& filename, CFileMode mode)
}
CBinaryFile binaryFile{};
- binaryFile.m_filename = filename;
+ auto copyStatus = binaryFile.m_filename.copy(filename);
+ if (copyStatus != FudStatus::Success) {
+ return CBinaryFileResult::error(copyStatus);
+ }
binaryFile.m_mode = modeResult.takeOkay();
binaryFile.m_modeFlags = mode;
return CBinaryFileResult::okay(std::move(binaryFile));
@@ -41,13 +44,16 @@ CBinaryFileResult CBinaryFile::make(const String& filename, CFileMode mode, cons
if (!filename.valid()) {
return CBinaryFileResult::error(FudStatus::InvalidInput);
}
- auto modeResult{String::makeFromCString(CBinaryFileModeFromFlags(mode), extraFlags)};
+ auto modeResult{String::makeFromCStrings(CBinaryFileModeFromFlags(mode), extraFlags)};
if (modeResult.isError()) {
return CBinaryFileResult::error(modeResult);
}
CBinaryFile binaryFile{};
- binaryFile.m_filename = filename;
+ auto copyStatus = binaryFile.m_filename.copy(filename);
+ if (copyStatus != FudStatus::Success) {
+ return CBinaryFileResult::error(copyStatus);
+ }
binaryFile.m_mode = modeResult.takeOkay();
binaryFile.m_modeFlags = mode;
return CBinaryFileResult::okay(std::move(binaryFile));
@@ -92,7 +98,10 @@ CTextFileResult CTextFile::make(const String& filename, CFileMode mode)
}
CTextFile textFile{};
- textFile.m_filename = filename;
+ auto copyStatus = textFile.m_filename.copy(filename);
+ if (copyStatus != FudStatus::Success) {
+ return CTextFileResult::error(copyStatus);
+ }
textFile.m_mode = modeResult.takeOkay();
textFile.m_modeFlags = mode;
return CTextFileResult::okay(std::move(textFile));
@@ -103,13 +112,16 @@ CTextFileResult CTextFile::make(const String& filename, CFileMode mode, const ch
if (!filename.valid()) {
return CTextFileResult::error(FudStatus::InvalidInput);
}
- auto modeResult{String::makeFromCString(CTextFileModeFromFlags(mode), extraFlags)};
+ auto modeResult{String::makeFromCStrings(CTextFileModeFromFlags(mode), extraFlags)};
if (modeResult.isError()) {
return CTextFileResult::error(modeResult);
}
CTextFile textFile{};
- textFile.m_filename = filename;
+ auto copyStatus = textFile.m_filename.copy(filename);
+ if (copyStatus != FudStatus::Success) {
+ return CTextFileResult::error(copyStatus);
+ }
textFile.m_mode = modeResult.takeOkay();
textFile.m_modeFlags = mode;
return CTextFileResult::okay(std::move(textFile));
diff --git a/source/fud_directory.cpp b/source/fud_directory.cpp
index 1697692..318d7e6 100644
--- a/source/fud_directory.cpp
+++ b/source/fud_directory.cpp
@@ -72,48 +72,53 @@ Result<DirectoryEntry, FudStatus> DirectoryEntry::fromStat(const String& name, c
break;
}
- return RetType::okay(DirectoryEntry{
- name,
- statBuffer.st_ino,
- size,
- static_cast<size_t>(statBuffer.st_nlink),
- statBuffer.st_mtime,
- entryType});
+ DirectoryEntry entry{};
+ auto copyStatus = entry.name.copy(name);
+ if (copyStatus != FudStatus::Success) {
+ return RetType::error(copyStatus);
+ }
+ entry.inode = statBuffer.st_ino;
+ entry.size = size;
+ entry.links = static_cast<size_t>(statBuffer.st_nlink);
+ entry.modificationTime = statBuffer.st_mtime;
+ entry.entryType = entryType;
+ return RetType::okay(std::move(entry));
}
-Directory::Directory(const String& name) : m_name{name}
+Result<Directory, FudStatus> Directory::make(const String& name)
{
- if (!m_name.valid()) {
- return;
+ using RetType = Result<Directory, FudStatus>;
+ Directory directory{};
+ if (!name.valid()) {
+ return RetType::error(FudStatus::InvalidInput);
}
- if (!m_name.utf8Valid()) {
- m_status = FudStatus::Utf8Invalid;
- return;
+ if (!name.utf8Valid()) {
+ return RetType::error(FudStatus::Utf8Invalid);
}
- m_directory = opendir(m_name.c_str());
- if (m_directory == nullptr) {
- m_status = FudStatus::Failure;
- m_errorCode = errno;
- return;
+ auto copyResult = directory.m_name.copy(name);
+ if (copyResult != FudStatus::Success) {
+ return RetType::error(copyResult);
}
- m_dirFd = dirfd(m_directory);
- if (m_dirFd == -1) {
- m_status = FudStatus::Failure;
- m_errorCode = errno;
- closedir(m_directory);
- m_directory = nullptr;
- return;
+ directory.m_directory = opendir(name.c_str());
+ if (directory.m_directory == nullptr) {
+ return RetType::error(FudStatus::Failure);
}
- m_errorCode = 0;
- m_status = FudStatus::Success;
+ directory.m_dirFd = dirfd(directory.m_directory);
+ if (directory.m_dirFd == -1) {
+ closedir(directory.m_directory);
+ return RetType::error(FudStatus::Failure);
+ }
+
+ directory.m_errorCode = 0;
+ return RetType::okay(std::move(directory));
}
Directory::Directory(Directory&& rhs) noexcept :
- m_name{std::move(rhs.m_name)}, m_directory{rhs.m_directory}, m_dirFd{rhs.m_dirFd}
+ m_name{std::move(rhs.m_name)}, m_directory{rhs.m_directory}, m_errorCode{rhs.m_errorCode}, m_dirFd{rhs.m_dirFd}
{
rhs.m_directory = nullptr;
rhs.m_dirFd = -1;
@@ -127,35 +132,21 @@ Directory::~Directory()
}
}
-bool Directory::valid() const
-{
- return m_directory != nullptr && m_dirFd != -1;
-}
-
Result<DirectoryEntry, FudStatus> Directory::info()
{
using RetType = Result<DirectoryEntry, FudStatus>;
- if (!valid()) {
- m_status = FudStatus::ObjectInvalid;
- return RetType::error(m_status);
- }
-
Stat sBuffer{};
auto fStatus = fstat(m_dirFd, &sBuffer);
if (fStatus == -1) {
m_errorCode = errno;
- m_status = FudStatus::Failure;
- return RetType::error(m_status);
+ return RetType::error(FudStatus::Failure);
}
auto retValue = DirectoryEntry::fromStat(m_name, sBuffer);
if (retValue.isOkay()) {
m_errorCode = 0;
- m_status = FudStatus::Success;
- } else {
- m_status = retValue.getError();
}
return retValue;
@@ -165,18 +156,12 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
{
using RetType = Result<std::optional<DirectoryEntry>, FudStatus>;
- if (!valid()) {
- m_status = FudStatus::ObjectInvalid;
- return RetType::error(m_status);
- }
-
errno = 0;
auto* dirEntry = readdir(m_directory);
if (dirEntry == nullptr) {
if (errno != 0) {
m_errorCode = errno;
- m_status = FudStatus::Failure;
- return RetType::error(m_status);
+ return RetType::error(FudStatus::Failure);
}
return RetType::okay(std::nullopt);
}
@@ -184,8 +169,7 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
const char* entryNameCString = dirEntry->d_name;
if (entryNameCString == nullptr) {
m_errorCode = -1;
- m_status = FudStatus::NullPointer;
- return RetType::error(m_status);
+ return RetType::error(FudStatus::NullPointer);
}
m_errorCode = 0;
@@ -195,8 +179,7 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
auto fStatus = fstatat(m_dirFd, entryNameCString, &sBuffer, flags);
if (fStatus == -1) {
m_errorCode = errno;
- m_status = FudStatus::Failure;
- return RetType::error(m_status);
+ return RetType::error(FudStatus::Failure);
}
auto entryNameResult = String::makeFromCString(entryNameCString);
@@ -207,23 +190,18 @@ Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
if (retValue.isOkay()) {
m_errorCode = 0;
- m_status = FudStatus::Success;
return RetType::okay(retValue.takeOkay());
}
- m_status = retValue.getError();
return RetType::error(retValue.getError());
}
FudStatus Directory::reset()
{
- if (!valid()) {
- }
if (m_directory != nullptr) {
rewinddir(m_directory);
} else {
- m_status = FudStatus::ObjectInvalid;
- return m_status;
+ return FudStatus::ObjectInvalid;
}
return FudStatus::Success;
}
diff --git a/source/fud_sqlite.cpp b/source/fud_sqlite.cpp
index 449be8b..e13feee 100644
--- a/source/fud_sqlite.cpp
+++ b/source/fud_sqlite.cpp
@@ -22,7 +22,10 @@ namespace fud {
SqliteDbResult SqliteDb::make(const String& name, SqliteOpenMode mode, int extraFlags)
{
SqliteDb sqlDb{};
- sqlDb.m_name = name;
+ auto copyResult = sqlDb.m_name.copy(name);
+ if (copyResult != FudStatus::Success) {
+ return SqliteDbResult::error(copyResult);
+ }
sqlDb.m_mode = mode;
sqlDb.m_extraFlags = extraFlags;
auto status = sqlDb.initialize();
diff --git a/source/fud_string.cpp b/source/fud_string.cpp
index 82a9fe5..f33224a 100644
--- a/source/fud_string.cpp
+++ b/source/fud_string.cpp
@@ -48,22 +48,40 @@ ssize_t cStringLength(const char* str, size_t maxLength)
StringResult String::makeFromCString(const char* cString)
{
+ return makeFromCString(cString, &globalFudAllocator);
+}
+
+StringResult String::makeFromCString(const char* cString, Allocator* allocator)
+{
+ if (allocator == nullptr) {
+ return StringResult::error(FudStatus::NullPointer);
+ }
+
auto lenResult = cStringLength(cString);
if (lenResult < 0 || lenResult >= SSIZE_MAX) {
return StringResult::error(FudStatus::InvalidInput);
}
String output{};
+ output.m_allocator = allocator;
auto* data = output.m_buffer.data();
output.m_length = static_cast<size_t>(lenResult);
+
if (output.m_length >= output.m_capacity) {
output.m_capacity = output.m_length + 1;
- data = static_cast<utf8*>(fudAlloc(output.m_capacity));
+ auto dataResult{output.m_allocator->allocate(output.m_capacity)};
+ if (dataResult.isError()) {
+ return StringResult::error(dataResult);
+ }
+
+ data = static_cast<utf8*>(dataResult.takeOkay());
+
if (data == nullptr) {
return StringResult::error(FudStatus::AllocFailure);
}
output.m_data = data;
}
+
auto copyStatus = copyMem(data, output.m_capacity, cString, output.m_length);
fudAssert(copyStatus == FudStatus::Success);
auto terminateStatus = output.nullTerminate();
@@ -72,36 +90,42 @@ StringResult String::makeFromCString(const char* cString)
return StringResult::okay(std::move(output));
}
-StringResult String::makeFromUtf8(const utf8* utf8String)
+StringResult String::from(const String& rhs)
{
- // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
- return makeFromCString(reinterpret_cast<const char*>(utf8String));
- // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
-}
+ if (!rhs.valid()) {
+ return StringResult::error(FudStatus::InvalidInput);
+ }
-String::String(const String& rhs) : m_length{rhs.m_length}, m_capacity{rhs.m_capacity}
-{
- if (rhs.valid()) {
- if (isLarge()) {
- m_data = static_cast<utf8*>(fudAlloc(m_capacity));
- fudAssert(m_data != nullptr);
+ String output{};
+ output.m_length = rhs.m_length;
+ output.m_capacity = rhs.m_capacity;
+ output.m_allocator = rhs.m_allocator;
+
+ if (rhs.isLarge()) {
+ auto dataResult = output.m_allocator->allocate(output.m_capacity);
+ if (dataResult.isError()) {
+ return StringResult::error(dataResult.getError());
}
- fudAssert(copyMem(data(), m_capacity, rhs.data(), m_length) == FudStatus::Success);
- fudAssert(nullTerminate() == FudStatus::Success);
+ output.m_data = static_cast<utf8*>(dataResult.getOkay());
+ fudAssert(output.m_data != nullptr);
}
+
+ auto copyResult = copyMem(output.data(), output.m_capacity, rhs.data(), output.m_length);
+ fudAssert(copyResult == FudStatus::Success);
+ auto nullTerminateStatus = output.nullTerminate();
+ fudAssert(nullTerminateStatus == FudStatus::Success);
+ return StringResult::okay(std::move(output));
}
-String::String(String&& rhs) noexcept : m_length{rhs.m_length}, m_capacity{rhs.m_capacity}
+String::String(String&& rhs) noexcept : m_length{rhs.m_length}, m_capacity{rhs.m_capacity}, m_allocator{rhs.m_allocator}
{
- if (isLarge()) {
- cleanup();
- }
if (rhs.isLarge()) {
m_data = rhs.m_data;
rhs.m_data = nullptr;
} else {
m_buffer = rhs.m_buffer;
- fudAssert(nullTerminate() == FudStatus::Success);
+ auto terminateStatus = nullTerminate();
+ fudAssert(terminateStatus == FudStatus::Success);
}
}
@@ -110,25 +134,37 @@ String::~String()
cleanup();
}
-String& String::operator=(const String& rhs)
+FudStatus String::copy(const String& rhs)
{
if (this == &rhs) {
- return *this;
+ return FudStatus::Success;
+ }
+
+ if (!rhs.valid()) {
+ return FudStatus::InvalidInput;
}
cleanup();
m_length = rhs.m_length;
m_capacity = rhs.m_capacity;
- if (rhs.valid()) {
- if (isLarge()) {
- m_data = static_cast<utf8*>(fudAlloc(m_capacity));
- fudAssert(m_data != nullptr);
+ m_allocator = rhs.m_allocator;
+
+ if (isLarge()) {
+ auto dataResult = m_allocator->allocate(m_capacity);
+ if (dataResult.isError()) {
+ return dataResult.getError();
}
- fudAssert(copyMem(data(), m_capacity, rhs.data(), m_length) == FudStatus::Success);
- fudAssert(nullTerminate() == FudStatus::Success);
+ m_data = static_cast<utf8*>(dataResult.getOkay());
+ fudAssert(m_data != nullptr);
}
- return *this;
+
+ auto copyResult = copyMem(data(), m_capacity, rhs.data(), m_length);
+ fudAssert(copyResult == FudStatus::Success);
+ auto nullTerminateStatus = nullTerminate();
+ fudAssert(nullTerminateStatus == FudStatus::Success);
+
+ return FudStatus::Success;
}
String& String::operator=(String&& rhs) noexcept
@@ -137,6 +173,7 @@ String& String::operator=(String&& rhs) noexcept
m_length = rhs.m_length;
m_capacity = rhs.m_capacity;
+ m_allocator = rhs.m_allocator;
if (rhs.isLarge()) {
m_data = rhs.m_data;
rhs.m_data = nullptr;
@@ -149,8 +186,8 @@ String& String::operator=(String&& rhs) noexcept
void String::cleanup()
{
- if (isLarge() && m_data != nullptr) {
- fudFree(m_data);
+ if (isLarge() && m_data != nullptr && m_allocator != nullptr) {
+ m_allocator->deallocate(m_data, m_capacity);
m_data = nullptr;
}
}
@@ -209,7 +246,7 @@ bool String::nullTerminated() const
bool String::valid() const
{
- return nullTerminated();
+ return m_allocator != nullptr && nullTerminated();
}
bool String::utf8Valid() const
@@ -416,7 +453,11 @@ StringResult String::catenate(const char* rhs) const
auto* destPtr = output.m_buffer.data();
if (output.m_length >= output.m_capacity) {
output.m_capacity = output.m_length + 1;
- destPtr = static_cast<utf8*>(fudAlloc(output.m_capacity));
+ auto ptrResult = m_allocator->allocate(output.m_capacity);
+ if (ptrResult.isError()) {
+ return StringResult::error(ptrResult.getError());
+ }
+ destPtr = static_cast<utf8*>(ptrResult.getOkay());
if (destPtr == nullptr) {
return StringResult::error(FudStatus::AllocFailure);
}
diff --git a/source/libfud.cpp b/source/libfud.cpp
index cec544d..538d3a9 100644
--- a/source/libfud.cpp
+++ b/source/libfud.cpp
@@ -55,7 +55,7 @@ Result<String, FudStatus> getEnv(const char* name)
return RetType::error(envVarResult);
}
- return RetType::okay(envVarResult);
+ return RetType::okay(std::move(envVarResult));
}
} // namespace fud
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a79bc40..a20e991 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,11 +1,15 @@
include(FetchContent)
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
- set(CVG_FLAGS -Wno-long-long -fsanitize=address -fsanitize=undefined -fprofile-arcs -ftest-coverage)
+ set(CVG_FLAGS -Wno-long-long -fprofile-arcs -ftest-coverage)
else()
endif()
+if(FUD_SAN)
+set(CVG_FLAGS ${CVG_FLAGS} -fsanitize=address -fsanitize=undefined)
+endif()
+
set(gtest_URL https://github.com/google/googletest.git)
set(gtest_TAG v1.14.0)
diff --git a/test/test_common.cpp b/test/test_common.cpp
index fc37566..5a26e09 100644
--- a/test/test_common.cpp
+++ b/test/test_common.cpp
@@ -16,7 +16,7 @@
*/
#include "test_common.hpp"
-#include "fud_memory.hpp"
+#include "fud_allocator.hpp"
#include <cstdlib>
namespace fud {
diff --git a/test/test_directory.cpp b/test/test_directory.cpp
index 6597195..c2af281 100644
--- a/test/test_directory.cpp
+++ b/test/test_directory.cpp
@@ -109,26 +109,27 @@ TEST(FudDirectory, Basic)
ASSERT_EQ(writeResult.status, expected.status);
}
- Directory directory{testDirName};
- ASSERT_EQ(directory.status(), FudStatus::Success);
+ auto directoryResult{Directory::make(testDirName)};
+ ASSERT_TRUE(directoryResult.isOkay());
+ Directory directory{directoryResult.takeOkay()};
ASSERT_EQ(directory.errorCode(), 0);
const Array<DirectoryEntry, 4> expectedFiles{
DirectoryEntry{String::makeFromCString(".").takeOkay(), 0, 0, 2, 0, DirectoryEntryType::Directory},
DirectoryEntry{String::makeFromCString("..").takeOkay(), 0, 0, 1, 0, DirectoryEntryType::Directory},
- DirectoryEntry{files[0], 0, files[0].size(), 1, 0, DirectoryEntryType::RegularFile},
- DirectoryEntry{files[1], 0, files[1].size(), 1, 0, DirectoryEntryType::RegularFile},
+ DirectoryEntry{String::from(files[0]).takeOkay(), 0, files[0].size(), 1, 0, DirectoryEntryType::RegularFile},
+ DirectoryEntry{String::from(files[1]).takeOkay(), 0, files[1].size(), 1, 0, DirectoryEntryType::RegularFile},
};
ASSERT_TRUE(expectedFiles[0].name.compare(expectedFiles[0].name));
for (auto idx = 0; idx < expectedFiles.size(); ++idx) {
auto dirEntryResult = directory.getNextEntry();
EXPECT_TRUE(dirEntryResult.isOkay());
- const auto dirEntryOpt = dirEntryResult.getOkay();
+ auto dirEntryOpt = dirEntryResult.takeOkay();
if (dirEntryOpt == std::nullopt) {
break;
}
- const auto dirEntry = *dirEntryOpt;
+ auto dirEntry{std::move(dirEntryOpt.value())};
const auto* expected = std::find_if(
expectedFiles.begin(),
expectedFiles.end(),
diff --git a/test/test_string.cpp b/test/test_string.cpp
index 6d963c4..61052ef 100644
--- a/test/test_string.cpp
+++ b/test/test_string.cpp
@@ -38,10 +38,10 @@ TEST(FudString, BasicStringOps)
ASSERT_FALSE(Ascii::valid(invalid[0]));
const Array<utf8, 2> invalid2{0xFF, 0x00};
- auto stringResult = String::makeFromCString(invalid2.data());
+ auto stringResult = String::makeFromCString(reinterpret_cast<const char*>(invalid2.data()));
ASSERT_TRUE(stringResult.isOkay());
- String fudString{stringResult.getOkay()};
+ String fudString{stringResult.takeOkay()};
ASSERT_EQ(fudString.length(), 1);
ASSERT_EQ(fudString.data()[0], invalid[0]);
ASSERT_FALSE(Ascii::valid(fudString.data()[0]));
@@ -49,7 +49,7 @@ TEST(FudString, BasicStringOps)
stringResult = String::makeFromCString("TEST");
ASSERT_TRUE(stringResult.isOkay());
- fudString = stringResult.getOkay();
+ fudString = stringResult.takeOkay();
ASSERT_TRUE(fudString.utf8Valid());
@@ -65,7 +65,7 @@ TEST(FudString, HeapAlloc)
constexpr const char filenameLiteral[] = "Amazing Saga Volume 01/000.jpg";
auto filenameResult{String::makeFromCString(filenameLiteral)};
ASSERT_TRUE(filenameResult.isOkay());
- auto filename{filenameResult.getOkay()};
+ auto filename{filenameResult.takeOkay()};
ASSERT_EQ(filename.length(), sizeof(filenameLiteral) - 1);
}