From b8345246dcc2121bcb6d1515a9341789de20199f Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Sun, 27 Oct 2024 09:04:05 -0500 Subject: First crack at file objects. --- include/fud_c_file.hpp | 11 +-- include/fud_file.hpp | 168 ++++++++++++++++++++++++++++++++++++++++++++ include/fud_memory.hpp | 26 +++++-- include/fud_status.hpp | 45 +++++++++--- include/fud_string.hpp | 6 +- include/fud_string_view.hpp | 7 ++ 6 files changed, 238 insertions(+), 25 deletions(-) create mode 100644 include/fud_file.hpp (limited to 'include') diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp index b54b044..197abd3 100644 --- a/include/fud_c_file.hpp +++ b/include/fud_c_file.hpp @@ -22,6 +22,7 @@ #include "fud_result.hpp" #include "fud_status.hpp" #include "fud_string.hpp" +#include "fud_file.hpp" #include #include @@ -82,16 +83,6 @@ constexpr const char* CTextFileModeFromFlags(CFileMode mode) } } -struct [[nodiscard]] ReadResult { - size_t bytesRead{0}; - FudStatus status{FudStatus::Success}; -}; - -struct [[nodiscard]] WriteResult { - size_t bytesWritten{0}; - FudStatus status{FudStatus::Success}; -}; - namespace detail { template diff --git a/include/fud_file.hpp b/include/fud_file.hpp new file mode 100644 index 0000000..b468b4b --- /dev/null +++ b/include/fud_file.hpp @@ -0,0 +1,168 @@ +/* + * 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_FILE_HPP +#define FUD_FILE_HPP + +#include "fud_allocator.hpp" +#include "fud_option.hpp" +#include "fud_result.hpp" +#include "fud_status.hpp" +#include "fud_string_view.hpp" + +#include + +namespace fud { + +/** \brief Access Modes for File */ +enum class FileAccessMode : uint8_t +{ + Read = 0x01, + Write = 0x02, + ReadWrite = Read | Write +}; + +enum class OpenFlagEnum : uint32_t +{ + Append = O_APPEND, + Truncate = O_TRUNC, + CloseOnExec = O_CLOEXEC, + DataSync = O_DSYNC, + Direct = O_DIRECT, + NoAtime = O_NOATIME, + NonBlock = O_NONBLOCK, + FileSync = O_SYNC +}; + +class OpenFlags { + public: + using FlagType = std::underlying_type_t; + + constexpr OpenFlags() noexcept = default; + constexpr OpenFlags(const OpenFlags& rhs) noexcept = default; + constexpr OpenFlags(OpenFlags&& rhs) noexcept = default; + constexpr ~OpenFlags() noexcept = default; + constexpr OpenFlags& operator=(const OpenFlags& rhs) noexcept = default; + constexpr OpenFlags& operator=(OpenFlags&& rhs) noexcept = default; + + constexpr OpenFlags(OpenFlagEnum mode) noexcept : m_mask{static_cast(mode)} + { + } + + constexpr OpenFlags operator|(OpenFlags rhs) const noexcept + { + OpenFlags mode{*this}; + mode.m_mask |= rhs.m_mask; + return mode; + } + + constexpr OpenFlags& operator|=(OpenFlags rhs) noexcept + { + m_mask |= rhs.m_mask; + return *this; + } + + constexpr OpenFlags& operator|=(OpenFlagEnum rhs) noexcept + { + m_mask |= static_cast(rhs); + return *this; + } + + constexpr OpenFlags operator|(OpenFlagEnum rhs) const noexcept + { + OpenFlags mode{*this}; + mode.m_mask |= static_cast(rhs); + return mode; + } + + constexpr FlagType flags() const noexcept + { + return m_mask; + } + + constexpr bool hasFlag(OpenFlagEnum flag) noexcept + { + return (m_mask & static_cast(flag)) != 0; + } + + private: + FlagType m_mask{0}; +}; + +constexpr OpenFlags operator|(OpenFlagEnum lhs, OpenFlagEnum rhs) +{ + OpenFlags mode{lhs}; + return mode | rhs; +} + +struct [[nodiscard]] ReadResult { + size_t bytesRead{0}; + FudStatus status{FudStatus::Success}; +}; + +struct [[nodiscard]] WriteResult { + size_t bytesWritten{0}; + FudStatus status{FudStatus::Success}; +}; + +class RegularFile; +using FileResult = Result; + +class RegularFile { + public: + static FileResult open( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + Option dirFdoption, + Allocator* allocator = &globalFudAllocator); + + static FileResult create( + StringView filename, + FileAccessMode mode, + OpenFlags flags, + bool exclusive, + Option dirFdOption, + Allocator* allocator = &globalFudAllocator); + + FudStatus close(); + + private: + RegularFile() = default; + + public: + RegularFile(const RegularFile& rhs) = delete; + + RegularFile(RegularFile&& rhs) noexcept; + + ~RegularFile(); + + RegularFile& operator=(const RegularFile& rhs) = delete; + + RegularFile& operator=(RegularFile&& rhs) noexcept; + + FudStatus take(RegularFile& rhs); + + private: + int m_fd{-1}; + FileAccessMode m_modeFlags{}; + OpenFlags m_openFlags{}; +}; + +} // namespace fud + +#endif diff --git a/include/fud_memory.hpp b/include/fud_memory.hpp index 6ce6312..6f6816f 100644 --- a/include/fud_memory.hpp +++ b/include/fud_memory.hpp @@ -73,6 +73,18 @@ constexpr void setMemory(Container& container, T&& value) } } +template +constexpr void zeroObject(T& object) +{ + static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + + auto* objPtr = reinterpret_cast(&object); + for (size_t idx = 0; idx < sizeof(object); ++idx) { + objPtr[idx] = 0; + } +} + template void copyMem(T& destination, const U& source) { @@ -80,11 +92,16 @@ void copyMem(T& destination, const U& source) static_assert(Count <= sizeof(T)); static_assert(std::is_standard_layout_v); static_assert(std::is_standard_layout_v); + static_assert(std::is_trivially_copyable_v); + static_assert(std::is_trivially_copyable_v); + + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) + auto* destPtr = reinterpret_cast(&destination); + const auto* srcPtr = reinterpret_cast(&source); + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) for (size_t idx = 0; idx < Count; ++idx) { - // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) - reinterpret_cast(&destination)[idx] = reinterpret_cast(&source)[idx]; - // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) + destPtr[idx] = srcPtr[idx]; } } @@ -126,8 +143,7 @@ int compareMem(const T& lhs, U&& rhs) int difference = 0; for (size_t idx = 0; idx < Count; ++idx) { // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) - difference = reinterpret_cast(&lhs)[idx] - - reinterpret_cast(&uRhs)[idx]; + difference = reinterpret_cast(&lhs)[idx] - reinterpret_cast(&uRhs)[idx]; // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) if (difference != 0) { break; diff --git a/include/fud_status.hpp b/include/fud_status.hpp index d57a9c5..f18c119 100644 --- a/include/fud_status.hpp +++ b/include/fud_status.hpp @@ -18,32 +18,59 @@ #ifndef FUD_STATUS_HPP #define FUD_STATUS_HPP +#include + namespace fud { -enum class [[nodiscard]] FudStatus +enum class [[nodiscard]] FudStatus : int32_t { + /** \brief Indisputable success. */ Success = 0, + /** \brief Either partially succeeding, or failing in a recoverable way. */ Partial, + /** \brief Typically a major failure in an underlying system call. */ Failure, + /** \brief An argument passed in was a null pointer and is invalid. */ NullPointer, + /** \brief An argument passed in is in an invalid state or mismatches with other arguments. */ ArgumentInvalid, - VariantInvalid, + /** \brief An handle to a managed object is not valid. */ + HandleInvalid, + /** \brief An object is uninitialized or no longer valid. */ ObjectInvalid, + /** \brief A utf sequence in a string is invalid. */ Utf8Invalid, + /** \brief A string is not terminated or has a length field exceeding its capacity. */ StringInvalid, + /** \brief The requested operation on the object is not valid for its current state. */ OperationInvalid, + /** \brief An object which is to be initialized has already been initialized. */ AlreadyInitialized, + /** \brief A format string is invalid. */ FormatInvalid, + /** \brief A string being parsed as a number is out of range for the requested type. */ RangeError, + /** \brief The given index is not in range of a randomly accessible container. */ IndexInvalid, + /** \brief An object in a container already exists in the requested slot for a new object. */ Exists, + /** \brief An object in a container does not exist in the requested slot for an existing object. */ NotFound, + /** \brief A container is empty when something was expected to be present. */ Empty, + /** \brief A container is full when attempting to add something to it. */ Full, + /** \brief An operation requiring elevated permissions failed. */ + PermissionDenied, + /** \brief Two or more objects overlap when they are expected to be distinct. */ Aliased, + /** \brief An requested allocation could not be completed. */ AllocFailure, + /** \brief An requested deallocation could not be completed. */ DeallocFailure, + /** \brief The function is not implemented, but is planned to be implemented. */ NotImplemented, + /** \brief The function or desired mode of action for a function is not supported. */ NotSupported }; @@ -58,20 +85,20 @@ constexpr const char* FudStatusToString(FudStatus status) return "Failure"; case FudStatus::NullPointer: return "NullPointer"; - case FudStatus::StringInvalid: - return "StringInvalid"; + case FudStatus::ArgumentInvalid: + return "ArgumentInvalid"; + case FudStatus::HandleInvalid: + return "HandleInvalid"; case FudStatus::ObjectInvalid: return "ObjectInvalid"; + case FudStatus::StringInvalid: + return "StringInvalid"; case FudStatus::OperationInvalid: return "OperationInvalid"; - case FudStatus::ArgumentInvalid: - return "ArgumentInvalid"; case FudStatus::Utf8Invalid: return "Utf8Invalid"; case FudStatus::RangeError: return "RangeError"; - case FudStatus::VariantInvalid: - return "VariantInvalid"; case FudStatus::FormatInvalid: return "FormatInvalid"; case FudStatus::AlreadyInitialized: @@ -86,6 +113,8 @@ constexpr const char* FudStatusToString(FudStatus status) return "Empty"; case FudStatus::Full: return "Full"; + case FudStatus::PermissionDenied: + return "PermissionDenied"; case FudStatus::Aliased: return "Aliased"; case FudStatus::AllocFailure: diff --git a/include/fud_string.hpp b/include/fud_string.hpp index 0213524..df03ad9 100644 --- a/include/fud_string.hpp +++ b/include/fud_string.hpp @@ -90,7 +90,6 @@ 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) { @@ -103,10 +102,11 @@ class String { output.m_data = static_cast(dataResult.getOkay()); } + auto* data = output.data(); size_t cumulativeLength = 0; for (size_t idx = 0; idx < strPointers.size(); ++idx) { const auto* cString = strPointers[idx]; - auto copyStatus = copyMem(data, output.m_capacity - cumulativeLength, cString, lengths[idx]); + auto copyStatus = copyMem(data + cumulativeLength, output.m_capacity - cumulativeLength, cString, lengths[idx]); fudAssert(copyStatus == FudStatus::Success); cumulativeLength += lengths[idx]; } @@ -131,6 +131,8 @@ class String { static StringResult from(const String& rhs); + static StringResult from(StringView view, Allocator* allocator = &globalFudAllocator); + FudStatus copy(const String& rhs); [[nodiscard]] constexpr size_t length() const diff --git a/include/fud_string_view.hpp b/include/fud_string_view.hpp index 718b3d7..972630a 100644 --- a/include/fud_string_view.hpp +++ b/include/fud_string_view.hpp @@ -61,6 +61,13 @@ struct StringView { explicit StringView(const String& fudString) noexcept; + template + constexpr static StringView cStringView(const char (&input)[N]) + { + static_assert(N > 0); + return StringView{N, reinterpret_cast(input)}; + } + [[nodiscard]] constexpr size_t length() const { return m_length; -- cgit v1.2.3