From 53c4dcf374c66f1e9190f5a62a52d02fe11a69e6 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Wed, 16 Oct 2024 22:25:08 -0500 Subject: First crack at allocators. --- CMakeLists.txt | 8 ++-- include/fud_allocator.hpp | 70 +++++++++++++++++++++++++++++++ include/fud_directory.hpp | 11 ++--- include/fud_memory.hpp | 10 ----- include/fud_result.hpp | 1 + include/fud_status.hpp | 3 ++ include/fud_string.hpp | 43 ++++++++++++++----- source/fud_allocator.cpp | 48 +++++++++++++++++++++ source/fud_c_file.cpp | 24 ++++++++--- source/fud_directory.cpp | 98 +++++++++++++++++-------------------------- source/fud_sqlite.cpp | 5 ++- source/fud_string.cpp | 105 ++++++++++++++++++++++++++++++++-------------- source/libfud.cpp | 2 +- test/CMakeLists.txt | 6 ++- test/test_common.cpp | 2 +- test/test_directory.cpp | 13 +++--- test/test_string.cpp | 8 ++-- 17 files changed, 313 insertions(+), 144 deletions(-) create mode 100644 include/fud_allocator.hpp create mode 100644 source/fud_allocator.cpp 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 +#include + +namespace fud { + +class Allocator { + public: + virtual ~Allocator() = default; + + virtual Result 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 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 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 class [[nodiscard]] Result { public: using ResultType = Result; + 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 - static StringResult makeFromCString(Strings... cStrings) + template + static StringResult makeFromCStrings(CStrings... cStrings) { + return makeFromCStringsAlloc(&globalFudAllocator, cStrings...); + } + + template + static StringResult makeFromCStringsAlloc(Allocator* allocator, CStrings... cStrings) + { + if (allocator == nullptr) { + return StringResult::error(FudStatus::NullPointer); + } size_t totalLength = 0; Array lengths{}; Array 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) { 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(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(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; @@ -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 FudAllocator::allocate(size_t bytes, size_t alignment) +{ + using RetType = Result; + static_cast(alignment); + auto* pointer = static_cast(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(bytes); + static_cast(alignment); + fudFree(pointer); +} + +bool FudAllocator::isEqual(const Allocator& rhs) const +{ + /* Is this legit? Or is this a bogus check? */ + return &rhs == static_cast(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::fromStat(const String& name, c break; } - return RetType::okay(DirectoryEntry{ - name, - statBuffer.st_ino, - size, - static_cast(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(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::make(const String& name) { - if (!m_name.valid()) { - return; + using RetType = Result; + 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 Directory::info() { using RetType = Result; - 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, FudStatus> Directory::getNextEntry() { using RetType = Result, 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, 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, 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, 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(lenResult); + if (output.m_length >= output.m_capacity) { output.m_capacity = output.m_length + 1; - data = static_cast(fudAlloc(output.m_capacity)); + auto dataResult{output.m_allocator->allocate(output.m_capacity)}; + if (dataResult.isError()) { + return StringResult::error(dataResult); + } + + data = static_cast(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(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(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(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(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(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(fudAlloc(output.m_capacity)); + auto ptrResult = m_allocator->allocate(output.m_capacity); + if (ptrResult.isError()) { + return StringResult::error(ptrResult.getError()); + } + destPtr = static_cast(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 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 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 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 invalid2{0xFF, 0x00}; - auto stringResult = String::makeFromCString(invalid2.data()); + auto stringResult = String::makeFromCString(reinterpret_cast(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); } -- cgit v1.2.3