summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-10-29 21:02:25 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-10-29 21:02:25 -0500
commit8ce397e8c0a83e49e390de9deb73d588e4931ecf (patch)
tree31f4f4facf0cb75535aaec130d606c54fe97b2d8
parentf281050ddb3b9d658cff67a254eedc3b79de5c5d (diff)
Reworking of Result.
-rw-r--r--CMakeLists.txt7
-rw-r--r--include/fud_drain.hpp35
-rw-r--r--include/fud_format.hpp43
-rw-r--r--include/fud_result.hpp214
-rw-r--r--include/fud_string.hpp64
-rw-r--r--include/fud_string_convert.hpp51
-rw-r--r--include/fud_utf8.hpp1
-rw-r--r--include/fud_vector.hpp66
-rw-r--r--source/fud_directory.cpp2
-rw-r--r--source/fud_file.cpp59
-rw-r--r--source/fud_format.cpp59
-rw-r--r--source/fud_string.cpp54
-rw-r--r--source/fud_string_convert.cpp25
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/test_file.cpp2
-rw-r--r--test/test_fud.cpp2
-rw-r--r--test/test_result.cpp7
-rw-r--r--test/test_utf8.cpp5
-rw-r--r--test/test_vector.cpp3
19 files changed, 459 insertions, 242 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6b2d05a..e40d7b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,10 +52,14 @@ else()
set(FUD_BOUNDS_CHECKING true)
endif()
+if(FUD_SAN)
+set(CVG_FLAGS ${CVG_FLAGS} -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr)
+endif()
+
if (FUD_TEST)
add_subdirectory(test)
# set(CVG_FLAGS -fsanitize=address -fsanitize=undefined --coverage)
- set(CVG_FLAGS --coverage)
+ set(CVG_FLAGS ${CVG_FLAGS} --coverage)
target_compile_options(fud PUBLIC ${CVG_FLAGS})
target_link_options(fud PUBLIC ${CVG_FLAGS})
endif ()
@@ -102,6 +106,7 @@ set(FUD_HEADERS
"include/fud_c_file.hpp"
"include/fud_c_string.hpp"
"include/fud_directory.hpp"
+ "include/fud_drain.hpp"
"include/fud_file.hpp"
"include/fud_fixed_vector.hpp"
"include/fud_fud_type_traits.hpp"
diff --git a/include/fud_drain.hpp b/include/fud_drain.hpp
new file mode 100644
index 0000000..5b78b10
--- /dev/null
+++ b/include/fud_drain.hpp
@@ -0,0 +1,35 @@
+/*
+ * 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_DRAIN_HPP
+#define FUD_DRAIN_HPP
+
+#include "fud_status.hpp"
+
+#include <concepts>
+#include <cstddef>
+
+namespace fud {
+
+struct DrainResult {
+ size_t bytesWritten;
+ FudStatus status;
+};
+
+} // namespace fud
+
+#endif
diff --git a/include/fud_format.hpp b/include/fud_format.hpp
index e156f43..c06643d 100644
--- a/include/fud_format.hpp
+++ b/include/fud_format.hpp
@@ -125,10 +125,10 @@ struct FormatFill {
length = 2;
auto fill = data[0];
if (not Ascii::valid(fill)) {
- return FudStatus::Utf8Invalid;
+ return RetType::error(FudStatus::Utf8Invalid);
}
if (fill == '{' || fill == '}') {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
return RetType::okay(FormatFill{std::move(align2).value(), data[0]});
}
@@ -465,45 +465,46 @@ FormatResult vFormat(Sink& sink, FormatCharMode formatMode, FormatString fmt, co
template <size_t Size>
Result<uint32_t, FudStatus> getSpecField(FormatSpec& formatSpec, uint32_t index, const FormatArguments<Size>& args)
{
+ using RetType = Result<uint32_t, FudStatus>;
static_assert(not std::is_signed_v<utf8>);
if (not formatSpec.takesPosition() || not formatSpec.takesWidth) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
if (index >= Size) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
if (std::holds_alternative<utf8>(args[index])) {
- return std::get<utf8>(args[index]);
+ return RetType::okay(std::get<utf8>(args[index]));
}
if (std::holds_alternative<int32_t>(args[index])) {
auto value = std::get<int32_t>(args[index]);
if (value < 0) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
- return static_cast<uint32_t>(value);
+ return RetType::okay(static_cast<uint32_t>(value));
}
if (std::holds_alternative<int64_t>(args[index])) {
auto value = std::get<int64_t>(args[index]);
if (value < 0 || value > std::numeric_limits<uint32_t>::max()) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
- return static_cast<uint32_t>(value);
+ return RetType::okay(static_cast<uint32_t>(value));
}
if (std::holds_alternative<uint32_t>(args[index])) {
- return std::get<uint32_t>(args[index]);
+ return RetType::okay(std::get<uint32_t>(args[index]));
}
if (std::holds_alternative<uint32_t>(args[index])) {
auto value = std::get<uint64_t>(args[index]);
if (value > std::numeric_limits<uint32_t>::max()) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
- return static_cast<uint32_t>(value);
+ return RetType::okay(static_cast<uint32_t>(value));
}
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
template <size_t Size>
@@ -514,6 +515,7 @@ Result<FormatSpec, FudStatus> vFormatPrepareSpec(
bool& firstSpec,
bool& takesPosition)
{
+ using RetType = Result<FormatSpec, FudStatus>;
if (firstSpec) {
firstSpec = false;
return vFormatPrepareFirstSpec(scanView, args, argIndex, takesPosition);
@@ -528,24 +530,24 @@ Result<FormatSpec, FudStatus> vFormatPrepareSpec(
auto formatSpec{formatSpecResult.getOkay()};
if (takesPosition != formatSpec.takesPosition() || (takesPosition && formatSpec.position >= Size)) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
if (takesPosition) {
auto status = vFormatPreparePositionalSpec(formatSpec, args);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
} else {
auto status = vFormatPrepareNonPositionalSpec(formatSpec, args, argIndex);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
}
scanView.advanceUnsafe(specLength);
- return formatSpec;
+ return RetType::okay(formatSpec);
}
template <size_t Size>
@@ -555,6 +557,7 @@ Result<FormatSpec, FudStatus> vFormatPrepareFirstSpec(
const uint32_t& argIndex,
bool& takesPosition)
{
+ using RetType = Result<FormatSpec, FudStatus>;
size_t specLength{0};
auto formatSpecResult{FormatSpec::parse(scanView, specLength)};
if (formatSpecResult.isError()) {
@@ -567,18 +570,18 @@ Result<FormatSpec, FudStatus> vFormatPrepareFirstSpec(
if (takesPosition) {
auto status = vFormatPreparePositionalSpec(formatSpec, args);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
} else {
auto status = vFormatPrepareNonPositionalSpec(formatSpec, args, argIndex);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
}
scanView.advanceUnsafe(specLength);
- return formatSpec;
+ return RetType::okay(formatSpec);
}
template <size_t Size>
diff --git a/include/fud_result.hpp b/include/fud_result.hpp
index 497b007..b91a31a 100644
--- a/include/fud_result.hpp
+++ b/include/fud_result.hpp
@@ -18,31 +18,127 @@
#ifndef FUD_RESULT_HPP
#define FUD_RESULT_HPP
+#include "fud_assert.hpp"
+#include "fud_option.hpp"
+#include "fud_status.hpp"
+
+#include <cstdint>
+#include <new> // IWYU pragma: keep (placement new)
+#include <type_traits>
#include <utility>
-#include <variant>
namespace fud {
+template <typename T>
+struct Okay {
+ T value;
+};
+
+template <typename E>
+struct Error {
+ E value;
+};
+
+using FudError = Error<FudStatus>;
+
/** \brief A result type which contains either a T on success or an E on error. */
template <typename T, typename E>
class [[nodiscard]] Result {
public:
using ResultType = Result<T, E>;
- constexpr Result(const T& value) : m_value{value}
+ constexpr ~Result() noexcept
{
+ destroy();
}
- constexpr Result(const E& value) : m_value{value}
+ constexpr Result(const Okay<T>& value) : m_data{}, m_discriminant{Discriminant::Okay}
{
+ auto ptrValue = new (m_data.data()) T(value.value);
+ fudAssert(ptrValue != nullptr);
}
- constexpr Result(T&& value) : m_value{std::move(value)}
+ constexpr Result(Okay<T>&& value) : m_data{}, m_discriminant{Discriminant::Okay}
{
+ auto ptrValue = new (m_data.data()) T(std::move(value.value));
+ fudAssert(ptrValue != nullptr);
}
- constexpr Result(E&& value) : m_value{std::move(value)}
+ constexpr Result(const Error<E>& value) : m_data{}, m_discriminant{Discriminant::Error}
{
+ auto ptrValue = new (m_data.data()) E(value.value);
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr Result(E&& value) : m_data{}, m_discriminant{Discriminant::Error}
+ {
+ auto ptrValue = new (m_data.data()) E(std::move(value.value));
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr Result(const Result<T, E>& rhs) : m_data{}, m_discriminant{rhs.m_discriminant}
+ {
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ if (isOkay()) {
+ auto ptrValue = new (m_data.data()) T(rhs.getOkay());
+ fudAssert(ptrValue != nullptr);
+ } else {
+ auto ptrValue = new (m_data.data()) E(rhs.getError());
+ fudAssert(ptrValue != nullptr);
+ }
+ }
+
+ constexpr Result(Result<T, E>&& rhs) : m_data{}, m_discriminant{rhs.m_discriminant}
+ {
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ if (isOkay()) {
+ auto ptrValue = new (m_data.data()) T(rhs.takeOkay());
+ fudAssert(ptrValue != nullptr);
+ } else {
+ auto ptrValue = new (m_data.data()) E(rhs.takeError());
+ fudAssert(ptrValue != nullptr);
+ }
+ rhs.m_discriminant = Discriminant::Invalid;
+ }
+
+ constexpr Result& operator=(const Result<T, E>& rhs)
+ {
+ if (&rhs == this) {
+ return *this;
+ }
+ destroy();
+
+ m_discriminant = rhs.m_discriminant;
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ if (isOkay()) {
+ auto ptrValue = new (m_data.data()) T(rhs.getOkay());
+ fudAssert(ptrValue != nullptr);
+ } else {
+ auto ptrValue = new (m_data.data()) E(rhs.getError());
+ fudAssert(ptrValue != nullptr);
+ }
+
+ return *this;
+ }
+
+ constexpr Result& operator=(Result<T, E>&& rhs)
+ {
+ if (&rhs == this) {
+ return *this;
+ }
+ destroy();
+
+ m_discriminant = rhs.m_discriminant;
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ if (isOkay()) {
+ auto ptrValue = new (m_data.data()) T(rhs.takeOkay());
+ fudAssert(ptrValue != nullptr);
+ } else {
+ auto ptrValue = new (m_data.data()) E(rhs.takeError());
+ fudAssert(ptrValue != nullptr);
+ }
+
+ return *this;
}
static constexpr ResultType okay(const T& okay)
@@ -68,40 +164,43 @@ class [[nodiscard]] Result {
template <typename F>
static constexpr ResultType okay(const Result<T, F>& okayRes)
{
- return ResultType{okayRes.getOkay()};
+ return ResultType::okay(okayRes.getOkay());
}
template <typename F>
static constexpr ResultType okay(Result<T, F>&& okayRes)
{
- return ResultType{okayRes.takeOkay()};
+ return ResultType::okay(okayRes.takeOkay());
}
template <typename U>
static constexpr ResultType error(const Result<U, E>& errorRes)
{
- return ResultType{errorRes.getError()};
+ return ResultType::error(errorRes.getError());
}
template <typename U>
static constexpr ResultType error(Result<U, E>&& errorRes)
{
- return ResultType{errorRes.takeError()};
+ return ResultType::error(errorRes.takeError());
}
[[nodiscard]] constexpr bool isOkay() const
{
- return (m_value.index() == 0);
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ return (m_discriminant == Discriminant::Okay);
}
[[nodiscard]] constexpr bool isError() const
{
- return (m_value.index() == 1);
+ fudAssert(m_discriminant != Discriminant::Invalid);
+ return (m_discriminant == Discriminant::Error);
}
[[nodiscard]] constexpr const T& getOkay() const&
{
- return std::get<T>(m_value);
+ fudAssert(isOkay());
+ return *reinterpret_cast<const T*>(m_data.data());
}
[[nodiscard]] constexpr const T& getOkayOr(const T& alternative) const&
@@ -109,12 +208,13 @@ class [[nodiscard]] Result {
if (!isOkay()) {
return alternative;
}
- return std::get<T>(m_value);
+ return *reinterpret_cast<const T*>(m_data.data());
}
[[nodiscard]] constexpr const E& getError() const&
{
- return std::get<E>(m_value);
+ fudAssert(isError());
+ return *reinterpret_cast<const E*>(m_data.data());
}
[[nodiscard]] constexpr const E& getErrorOr(const E& alternative) const&
@@ -122,12 +222,13 @@ class [[nodiscard]] Result {
if (!isError()) {
return alternative;
}
- return std::get<E>(m_value);
+ return *reinterpret_cast<const E*>(m_data.data());
}
[[nodiscard]] constexpr T&& takeOkay()
{
- return std::move(std::get<T>(m_value));
+ fudAssert(isOkay());
+ return std::move(*reinterpret_cast<T*>(m_data.data()));
}
[[nodiscard]] constexpr T&& takeOkayOr(T&& alternative)
@@ -135,12 +236,13 @@ class [[nodiscard]] Result {
if (!isOkay()) {
return std::move(alternative);
}
- return std::move(std::get<T>(m_value));
+ return std::move(*reinterpret_cast<T*>(m_data.data()));
}
[[nodiscard]] constexpr E&& takeError()
{
- return std::move(std::get<E>(m_value));
+ fudAssert(isError());
+ return std::move(*reinterpret_cast<E*>(m_data.data()));
}
[[nodiscard]] constexpr E&& takeErrorOr(E&& alternative)
@@ -148,24 +250,80 @@ class [[nodiscard]] Result {
if (!isError()) {
return std::move(alternative);
}
- return std::move(std::get<E>(m_value));
+ return std::move(*reinterpret_cast<E*>(m_data.data()));
}
private:
- constexpr Result() : m_value()
+ constexpr Result()
+ requires(std::is_default_constructible_v<T>)
+ : m_data{}, m_discriminant{Discriminant::Okay}
+ {
+ auto ptrValue = new (m_data.data()) T();
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr Result(const T& value)
+ requires(not std::is_convertible_v<T, E> and not std::is_convertible_v<E, T>)
+ : m_data{}, m_discriminant{Discriminant::Okay}
+ {
+ auto ptrValue = new (m_data.data()) T(value);
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr Result(T&& value)
+ requires(not std::is_convertible_v<T, E> and not std::is_convertible_v<E, T>)
+ : m_data{}, m_discriminant{Discriminant::Okay}
{
+ auto ptrValue = new (m_data.data()) T(std::move(value));
+ fudAssert(ptrValue != nullptr);
}
- std::variant<T, E> m_value;
+ constexpr Result(const E& value)
+ requires(not std::is_convertible_v<T, E> and not std::is_convertible_v<E, T>)
+ : m_data{}, m_discriminant{Discriminant::Error}
+ {
+ auto ptrValue = new (m_data.data()) E(value);
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr Result(E&& value)
+ requires(not std::is_convertible_v<T, E> and not std::is_convertible_v<E, T>)
+ : m_data{}, m_discriminant{Discriminant::Error}
+ {
+ auto ptrValue = new (m_data.data()) E(std::move(value));
+ fudAssert(ptrValue != nullptr);
+ }
+
+ constexpr void destroy() noexcept
+ {
+ if (m_discriminant == Discriminant::Okay) {
+ reinterpret_cast<T*>(m_data.data())->~T();
+ m_discriminant = Discriminant::Invalid;
+ } else if (m_discriminant == Discriminant::Error) {
+ reinterpret_cast<E*>(m_data.data())->~E();
+ m_discriminant = Discriminant::Invalid;
+ }
+ }
+
+ static constexpr auto Size = std::max(sizeof(T), sizeof(E));
+ static constexpr auto Align = std::max(alignof(T), alignof(E));
+ option_detail::DataArray<Size> m_data{};
+
+ enum class Discriminant : uint8_t
+ {
+ Invalid,
+ Okay,
+ Error,
+ } m_discriminant{Discriminant::Invalid};
};
-#define M_TakeOrReturn(HYGIENE_EXPRESSION) \
- ({ \
- auto HYGIENE_RESULT{(HYGIENE_EXPRESSION)}; \
- if (HYGIENE_RESULT.isError()) { \
- return HYGIENE_RESULT.takeError(); \
- } \
- HYGIENE_RESULT.takeOkay(); \
+#define M_TakeOrReturn(HYGIENE_RESULT_TYPE, HYGIENE_EXPRESSION) \
+ ({ \
+ auto HYGIENE_RESULT{(HYGIENE_EXPRESSION)}; \
+ if (HYGIENE_RESULT.isError()) { \
+ return HYGIENE_RESULT_TYPE::error(HYGIENE_RESULT.takeError()); \
+ } \
+ HYGIENE_RESULT.takeOkay(); \
})
} // namespace fud
diff --git a/include/fud_string.hpp b/include/fud_string.hpp
index 0020c67..cdc6b91 100644
--- a/include/fud_string.hpp
+++ b/include/fud_string.hpp
@@ -21,6 +21,7 @@
#include "fud_allocator.hpp"
#include "fud_assert.hpp"
#include "fud_c_string.hpp"
+#include "fud_drain.hpp"
#include "fud_option.hpp"
#include "fud_result.hpp"
#include "fud_status.hpp"
@@ -36,22 +37,7 @@ static_assert(CHAR_BIT == 8);
namespace fud {
-struct DrainResult {
- size_t bytesWritten;
- FudStatus status;
-};
-
-/* TODO: make SSO_BUF_LENGTH user configurable. */
-
-/** \brief The maximum length of a string using the small string optimization
- * buffer. */
-constexpr size_t SSO_BUF_LENGTH = 15;
-
-/** \brief The size of the small string optimization buffer, to include space
- * for the null terminator. */
-constexpr size_t SSO_BUF_SIZE = SSO_BUF_LENGTH + 1;
-
-static constexpr size_t SsoBufSize = 23;
+constexpr size_t SsoBufSize = 23;
class String;
@@ -163,26 +149,26 @@ class String {
fudAssert(totalLength < maxStringLength);
String output{};
- output.m_allocator = allocator;
+ output.m_allocator = reinterpret_cast<uintptr_t>(allocator);
utf8* data{nullptr};
size_t capacity = totalLength + 1;
bool isLarge = capacity > SsoBufSize;
if (isLarge) {
- output.m_repr.large.capacity = capacity & largeStringCapacitymask;
+ output.m_repr.large.capacity = capacity;
output.m_repr.large.length = totalLength;
auto dataResult = output.allocator()->allocate(output.m_repr.large.capacity);
if (dataResult.isError()) {
return StringResult::error(dataResult.getError());
}
output.m_repr.large.data = static_cast<utf8*>(dataResult.getOkay());
- output.m_repr.large.isLarge = 1;
data = output.m_repr.large.data;
+ output.setLarge();
} else {
capacity = SsoBufSize;
static_assert(SsoBufSize < std::numeric_limits<int8_t>::max());
- output.m_repr.small.isLarge = 0;
output.m_repr.small.length = static_cast<uint8_t>(totalLength) & smallStringLengthMask;
data = output.m_repr.small.buffer.data();
+ output.setSmall();
}
fudAssert(data != nullptr);
@@ -317,18 +303,19 @@ class String {
private:
static constexpr size_t maxStringLength = (static_cast<size_t>(1) << 63) - 1;
- static constexpr size_t largeStringCapacitymask = (static_cast<size_t>(1) << 63) - 1;
static constexpr uint8_t maxSmallStringLength = SsoBufSize;
- static constexpr uint8_t smallStringLengthMask = 0x7F;
+ static constexpr uint8_t smallStringLengthMask = 0xFF;
+ static constexpr auto isLargeMask = static_cast<uintptr_t>(0x01);
+ static constexpr auto allocatorMask = ~isLargeMask;
[[nodiscard]] static bool allocatorValid(Allocator* allocator)
{
- return allocator != nullptr;
+ return (reinterpret_cast<uintptr_t>(allocator) & isLargeMask) == 0;
}
Allocator* allocator() const
{
- return m_allocator;
+ return reinterpret_cast<Allocator*>(m_allocator & allocatorMask);
}
[[nodiscard]] bool nullTerminated() const;
@@ -350,19 +337,17 @@ class String {
/** \brief The allocator used to get storage for characters when the string
* is large. */
- Allocator* m_allocator{&globalFudAllocator};
+ uintptr_t m_allocator{reinterpret_cast<uintptr_t>(&globalFudAllocator)};
using BufType = Array<utf8, SsoBufSize>;
union {
struct {
- uint8_t isLarge : 1;
- size_t capacity : 63;
+ size_t capacity;
size_t length;
utf8* data;
} large;
struct {
- uint8_t isLarge : 1 = 0;
- uint8_t length : 7 = 0;
+ uint8_t length = 0;
BufType buffer{};
} small{};
} m_repr{};
@@ -370,22 +355,17 @@ class String {
/** \brief Whether or not the string must use its allocator for storage. */
[[nodiscard]] bool isLarge() const
{
- struct {
- uint8_t isLarge : 1;
- uint8_t length : 7;
- } determinant;
- copyMem<1>(determinant, m_repr);
- return determinant.isLarge;
+ return (m_allocator & isLargeMask) != 0;
}
- [[nodiscard]] size_t smallLength() const
+ void setLarge()
{
- struct {
- uint8_t isLarge : 1;
- uint8_t length : 7;
- } determinant;
- copyMem<1>(determinant, m_repr);
- return determinant.isLarge;
+ m_allocator |= isLargeMask;
+ }
+
+ void setSmall()
+ {
+ m_allocator &= allocatorMask;
}
void addToLength(size_t augend)
diff --git a/include/fud_string_convert.hpp b/include/fud_string_convert.hpp
index 597c6a9..d7a62f0 100644
--- a/include/fud_string_convert.hpp
+++ b/include/fud_string_convert.hpp
@@ -111,12 +111,12 @@ StringConvertResult<T> unsignedFromString(StringView nextView, size_t skipIndex,
static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>);
auto status = checkPlusSigned(nextView, skipIndex);
if (status != FudStatus::Success) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
auto radixResult = impl::getRadix(nextView, skipIndex, specifiedRadixOption);
if (radixResult.isError()) {
- return radixResult.takeError();
+ return FudError{radixResult.takeError()};
}
auto radix = radixResult.takeOkay();
@@ -131,20 +131,20 @@ StringConvertResult<T> unsignedFromString(StringView nextView, size_t skipIndex,
auto digit = static_cast<uint8_t>(digitResult);
if (std::numeric_limits<T>::max() / radix < num) {
- return FudStatus::RangeError;
+ return FudError{FudStatus::RangeError};
}
num *= radix;
if (std::numeric_limits<T>::max() - digit < num) {
- return FudStatus::RangeError;
+ return FudError{FudStatus::RangeError};
}
num += digit;
digitIndex++;
}
if (digitIndex < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
- return ConvertValue{skipIndex + digitIndex, num};
+ return Okay{ConvertValue{skipIndex + digitIndex, num}};
}
template <typename T>
@@ -203,12 +203,12 @@ StringConvertResult<T> signedFromString(StringView nextView, size_t skipIndex, O
static_assert(std::is_signed_v<T> && std::is_integral_v<T>);
auto status = impl::checkPlusSigned(nextView, skipIndex);
if (status != FudStatus::Success) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
auto radixResult = impl::getRadix(nextView, skipIndex, specifiedRadixOption);
if (radixResult.isError()) {
- return radixResult.takeError();
+ return FudError{radixResult.takeError()};
}
auto radix = radixResult.takeOkay();
@@ -217,7 +217,7 @@ StringConvertResult<T> signedFromString(StringView nextView, size_t skipIndex, O
auto isNegativeResult = checkNegative(nextView, skipIndex);
if (isNegativeResult.isError()) {
- return isNegativeResult.takeError();
+ return FudError{isNegativeResult.takeError()};
}
const auto isNegative = isNegativeResult.takeOkay();
@@ -228,14 +228,14 @@ StringConvertResult<T> signedFromString(StringView nextView, size_t skipIndex, O
}
if (status != FudStatus::Success) {
- return status;
+ return FudError{status};
}
if (digitIndex < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
- return ConvertValue{skipIndex + digitIndex, num};
+ return Okay{ConvertValue{skipIndex + digitIndex, num}};
}
template <typename T>
@@ -343,21 +343,22 @@ FudStatus getFraction(const StringView view, size_t& digitIndex, T& num, T sign,
template <typename T>
StringConvertResult<T> floatFromString(StringView nextView, size_t skipIndex, Option<uint8_t> specifiedRadixOption)
{
+ using RetType = StringConvertResult<T>;
static_assert(std::is_floating_point_v<T>);
if (nextView.length() < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
auto isNegativeResult = checkNegative(nextView, skipIndex);
if (isNegativeResult.isError()) {
- return isNegativeResult.takeError();
+ return FudError{isNegativeResult.takeError()};
}
const auto isNegative = isNegativeResult.takeOkay();
if (!isNegative) {
auto status = checkPlusSigned(nextView, skipIndex);
if (status != FudStatus::Success) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
}
T sign = isNegative ? -1.0 : 1.0;
@@ -365,7 +366,7 @@ StringConvertResult<T> floatFromString(StringView nextView, size_t skipIndex, Op
T num = 0;
size_t digitIndex = 0;
- auto retSuccess = [&]() { return ConvertValue{skipIndex + digitIndex, num}; };
+ auto retSuccess = [&]() { return RetType::okay(ConvertValue{skipIndex + digitIndex, num}); };
if (impl::isNanOrInf(num, nextView, sign, digitIndex)) {
return retSuccess();
@@ -373,7 +374,7 @@ StringConvertResult<T> floatFromString(StringView nextView, size_t skipIndex, Op
auto radixResult = impl::getRadix(nextView, skipIndex, specifiedRadixOption);
if (radixResult.isError()) {
- return radixResult.takeError();
+ return FudError{radixResult.takeError()};
}
auto radix = radixResult.takeOkay();
@@ -386,12 +387,12 @@ StringConvertResult<T> floatFromString(StringView nextView, size_t skipIndex, Op
}
if (status != FudStatus::Success) {
- return status;
+ return FudError{status};
}
if (!foundDecimal) {
if (digitIndex < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
return retSuccess();
@@ -402,17 +403,17 @@ StringConvertResult<T> floatFromString(StringView nextView, size_t skipIndex, Op
if (foundExponent) {
status = getExponent(nextView, digitIndex, num, radix);
if (status != FudStatus::Success) {
- return status;
+ return FudError{status};
}
}
if (digitIndex < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
if (std::isinf(num) || std::isnan(num)) // isnan is dubious here - likely unreachable
{
- return FudStatus::RangeError;
+ return FudError{FudStatus::RangeError};
}
return retSuccess();
@@ -430,13 +431,13 @@ template <typename T>
StringConvertResult<T> fromString(StringView inputView, Option<uint8_t> specifiedRadixOption)
{
if (inputView.data() == nullptr) {
- return FudStatus::NullPointer;
+ return FudError{FudStatus::NullPointer};
}
StringView nextView{inputView};
auto skipResult = nextView.skipWhitespace();
if (skipResult.isError()) {
- return skipResult.takeError();
+ return FudError{skipResult.takeError()};
}
size_t skipIndex = skipResult.takeOkay();
@@ -447,7 +448,7 @@ StringConvertResult<T> fromString(StringView inputView, Option<uint8_t> specifie
} else if constexpr (std::is_floating_point_v<T>) {
return impl::floatFromString<T>(nextView, skipIndex, specifiedRadixOption);
} else {
- return FudStatus::NotImplemented;
+ return FudError{FudStatus::NotImplemented};
}
}
diff --git a/include/fud_utf8.hpp b/include/fud_utf8.hpp
index 31c215a..3d53feb 100644
--- a/include/fud_utf8.hpp
+++ b/include/fud_utf8.hpp
@@ -25,6 +25,7 @@
#include <cstdint>
#include <type_traits>
+#include <variant>
namespace fud {
diff --git a/include/fud_vector.hpp b/include/fud_vector.hpp
index f90819a..2b5de9a 100644
--- a/include/fud_vector.hpp
+++ b/include/fud_vector.hpp
@@ -257,62 +257,68 @@ class Vector {
Result<Span<const T>, FudStatus> span() const
{
+ using RetType = Result<Span<const T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
- return Span{m_data, m_length};
+ return RetType::okay(Span{m_data, m_length});
}
Result<Span<T>, FudStatus> span()
{
+ using RetType = Result<Span<T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
- return Span{m_data, m_length};
+ return RetType::okay(Span{m_data, m_length});
}
Result<Span<const T>, FudStatus> span(size_t count) const
{
+ using RetType = Result<Span<const T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (count > m_length) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
- return Span{m_data, count};
+ return RetType::okay(Span{m_data, count});
}
Result<Span<T>, FudStatus> span(size_t count)
{
+ using RetType = Result<Span<T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (count > m_length) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
- return Span{m_data, count};
+ return RetType::okay(Span{m_data, count});
}
Result<Span<const T>, FudStatus> span(size_t start, size_t count) const
{
+ using RetType = Result<Span<const T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (SIZE_MAX - start < m_length || start + count > m_length) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
- return Span{m_data + start, count};
+ return RetType::okay(Span{m_data + start, count});
}
Result<Span<T>, FudStatus> span(size_t start, size_t count)
{
+ using RetType = Result<Span<T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (SIZE_MAX - start < m_length || start + count > m_length) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
- return Span{m_data + start, count};
+ return RetType::okay(Span{m_data + start, count});
}
FudStatus reserve(size_t count)
@@ -342,10 +348,15 @@ class Vector {
m_data[index].~T();
}
+ auto status = FudStatus::Success;
+ if (m_capacity > 0) {
+ status = m_allocator->deallocate(m_data, m_capacity);
+ }
+
m_data = dataPtr;
m_capacity = count;
- return FudStatus::Success;
+ return status;
}
FudStatus resize(size_t count)
@@ -394,24 +405,26 @@ class Vector {
Result<std::reference_wrapper<T>, FudStatus> get(size_t index)
{
+ using RetType = Result<std::reference_wrapper<T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (index >= m_length) {
- return FudStatus::IndexInvalid;
+ return RetType::error(FudStatus::IndexInvalid);
}
- return std::ref(m_data[index]);
+ return RetType::okay(std::ref(m_data[index]));
}
Result<const std::reference_wrapper<const T>, FudStatus> ref(size_t index) const
{
+ using RetType = Result<const std::reference_wrapper<const T>, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (index >= m_length) {
- return FudStatus::IndexInvalid;
+ return RetType::error(FudStatus::IndexInvalid);
}
- return std::cref(m_data[index]);
+ return RetType::okay(std::cref(m_data[index]));
}
constexpr Option<T&> front()
@@ -527,13 +540,14 @@ class Vector {
Result<T, FudStatus> popBack()
{
+ using RetType = Result<T, FudStatus>;
if (m_data == nullptr) {
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
}
if (m_length == 0) {
- return FudStatus::Empty;
+ return RetType::error(FudStatus::Empty);
}
- auto result{std::move(m_data[m_length - 1])};
+ auto result{RetType::okay({std::move(m_data[m_length - 1])})};
m_length--;
m_data[m_length].~T();
return result;
diff --git a/source/fud_directory.cpp b/source/fud_directory.cpp
index 1dc1aba..7dcf911 100644
--- a/source/fud_directory.cpp
+++ b/source/fud_directory.cpp
@@ -146,7 +146,7 @@ Result<DirectoryEntry, FudStatus> Directory::info()
m_errorCode = 0;
}
- return retValue;
+ return RetType::okay(std::move(retValue));
}
Result<Option<DirectoryEntry>, FudStatus> Directory::getNextEntry()
diff --git a/source/fud_file.cpp b/source/fud_file.cpp
index 8dab031..8f84648 100644
--- a/source/fud_file.cpp
+++ b/source/fud_file.cpp
@@ -34,11 +34,11 @@ FileResult RegularFile::open(
Allocator* allocator)
{
if (allocator == nullptr) {
- return FudStatus::NullPointer;
+ return FileResult::error(FudStatus::NullPointer);
}
if (!filename.nullTerminated()) {
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
}
int dirFd = dirFdOption.valueOr(AT_FDCWD);
@@ -57,11 +57,11 @@ FileResult RegularFile::open(
openFlags = O_RDWR;
break;
default:
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
}
if (flags.hasFlag(OpenFlagEnum::Append) && flags.hasFlag(OpenFlagEnum::Truncate)) {
- return FudStatus::OperationInvalid;
+ return FileResult::error(FudStatus::OperationInvalid);
}
openFlags |= flags.flags();
@@ -74,31 +74,31 @@ FileResult RegularFile::open(
auto status = syscall(SYS_openat2, dirFd, filename.data(), &openHow, sizeof(openHow));
if (status == -1) {
if constexpr (EAGAIN != EWOULDBLOCK && status == EWOULDBLOCK) {
- return FudStatus::Partial;
+ return FileResult::error(FudStatus::Partial);
}
switch (errno) {
case ETXTBSY:
case EAGAIN:
- return FudStatus::Partial;
+ return FileResult::error(FudStatus::Partial);
case ENOENT:
- return FudStatus::NotFound;
+ return FileResult::error(FudStatus::NotFound);
case EBADF:
case EFBIG:
case EOVERFLOW:
case EINVAL:
case EISDIR:
case ENAMETOOLONG:
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
case EROFS:
case EACCES:
case EPERM:
- return FudStatus::PermissionDenied;
+ return FileResult::error(FudStatus::PermissionDenied);
case ELOOP:
case EXDEV:
case ENFILE:
case E2BIG:
default:
- return FudStatus::Failure;
+ return FileResult::error(FudStatus::Failure);
}
}
fudAssert(status <= std::numeric_limits<decltype(file.m_fd)>::max());
@@ -108,14 +108,14 @@ FileResult RegularFile::open(
Stat sBuffer{};
auto fStatus = fstat(file.m_fd, &sBuffer);
if (fStatus == -1) {
- return FudStatus::Failure;
+ return FileResult::error(FudStatus::Failure);
}
if ((sBuffer.st_mode & S_IFMT) != S_IFREG) {
- return FudStatus::ObjectInvalid;
+ return FileResult::error(FudStatus::ObjectInvalid);
}
- return file;
+ return FileResult::okay(std::move(file));
}
FileResult RegularFile::create(
@@ -128,11 +128,11 @@ FileResult RegularFile::create(
Allocator* allocator)
{
if (allocator == nullptr) {
- return FudStatus::NullPointer;
+ return FileResult::error(FudStatus::NullPointer);
}
if (!filename.nullTerminated()) {
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
}
int dirFd = dirFdOption.valueOr(AT_FDCWD);
@@ -151,11 +151,11 @@ FileResult RegularFile::create(
openFlags = O_RDWR;
break;
default:
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
}
if (flags.hasFlag(OpenFlagEnum::Append) && flags.hasFlag(OpenFlagEnum::Truncate)) {
- return FudStatus::OperationInvalid;
+ return FileResult::error(FudStatus::OperationInvalid);
}
openFlags |= flags.flags() | O_CREAT | (O_EXCL * static_cast<uint8_t>(exclusive));
@@ -169,23 +169,23 @@ FileResult RegularFile::create(
auto status = syscall(SYS_openat2, dirFd, filename.data(), &openHow, sizeof(openHow));
if (status == -1) {
if constexpr (EAGAIN != EWOULDBLOCK && status == EWOULDBLOCK) {
- return FudStatus::Partial;
+ return FileResult::error(FudStatus::Partial);
}
switch (errno) {
case ETXTBSY:
case EAGAIN:
- return FudStatus::Partial;
+ return FileResult::error(FudStatus::Partial);
case EBADF:
case EFBIG:
case EOVERFLOW:
case EINVAL:
case EISDIR:
case ENAMETOOLONG:
- return FudStatus::ArgumentInvalid;
+ return FileResult::error(FudStatus::ArgumentInvalid);
case EROFS:
case EACCES:
case EPERM:
- return FudStatus::PermissionDenied;
+ return FileResult::error(FudStatus::PermissionDenied);
case EDQUOT:
case ENOENT:
case ELOOP:
@@ -193,7 +193,7 @@ FileResult RegularFile::create(
case ENFILE:
case E2BIG:
default:
- return FudStatus::Failure;
+ return FileResult::error(FudStatus::Failure);
}
}
fudAssert(status <= std::numeric_limits<decltype(file.m_fd)>::max());
@@ -203,14 +203,14 @@ FileResult RegularFile::create(
Stat sBuffer{};
auto fStatus = fstat(file.m_fd, &sBuffer);
if (fStatus == -1) {
- return FudStatus::Failure;
+ return FileResult::error(FudStatus::Failure);
}
if ((sBuffer.st_mode & S_IFMT) != S_IFREG) {
- return FudStatus::ObjectInvalid;
+ return FileResult::error(FudStatus::ObjectInvalid);
}
- return file;
+ return FileResult::okay(std::move(file));
}
RegularFile::~RegularFile()
@@ -284,23 +284,24 @@ FudStatus RegularFile::close()
Result<size_t, FudStatus> RegularFile::size() const
{
+ using RetType = Result<size_t, FudStatus>;
auto fileSize = lseek(m_fd, 0, SEEK_END);
if (fileSize == -1) {
switch (errno) {
case EBADF:
case ESPIPE:
- return FudStatus::ObjectInvalid;
+ return RetType::error(FudStatus::ObjectInvalid);
default:
- return FudStatus::Failure;
+ return RetType::error(FudStatus::Failure);
}
}
auto seekBegin = lseek(m_fd, 0, SEEK_SET);
if (seekBegin == -1) {
- return FudStatus::Failure;
+ return RetType::error(FudStatus::Failure);
}
- return static_cast<size_t>(fileSize);
+ return RetType::okay(static_cast<size_t>(fileSize));
}
} // namespace fud
diff --git a/source/fud_format.cpp b/source/fud_format.cpp
index 960a146..f1fc3cf 100644
--- a/source/fud_format.cpp
+++ b/source/fud_format.cpp
@@ -25,8 +25,9 @@ FudStatus getFormatSign(StringView& formatView, FormatSpec& spec);
Result<FormatSpec, FudStatus> FormatSpec::parse(StringView formatView, size_t& specLength)
{
+ using RetType = Result<FormatSpec, FudStatus>;
if (formatView.length() < 2 || formatView[0] != FormatSpec::openBracket) {
- return FudStatus::ArgumentInvalid;
+ return RetType::error(FudStatus::ArgumentInvalid);
}
auto hasEnded = [](StringView& view) {
@@ -43,82 +44,82 @@ Result<FormatSpec, FudStatus> FormatSpec::parse(StringView formatView, size_t& s
bool hasColon{false};
auto lengthResult = impl::preScanSpec(formatView, spec, hasPosition, hasColon);
if (lengthResult.isError()) {
- return lengthResult.takeError();
+ return RetType::error(lengthResult.takeError());
}
length += lengthResult.takeOkay();
if (length < 1) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
specLength = length;
auto status = impl::getPosition(formatView, spec, hasPosition);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
// check early ending
if (!hasColon) {
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
// check validity for being non-default spec and advance
if (formatView[0] != ':') {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
formatView.advanceUnsafe();
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// Spec
status = impl::getFill(formatView, spec);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// sign, alternate, leading zero
status = impl::getSpecialOpts(formatView, spec);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// Width
status = impl::getWidth(formatView, spec);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// Precision
status = impl::getPrecision(formatView, spec);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// Locale
@@ -129,26 +130,27 @@ Result<FormatSpec, FudStatus> FormatSpec::parse(StringView formatView, size_t& s
}
if (hasEnded(formatView)) {
- return spec;
+ return RetType::okay(spec);
}
// Format Sign
status = impl::getFormatSign(formatView, spec);
if (status != FudStatus::Success) {
- return status;
+ return RetType::error(status);
}
if (!hasEnded(formatView)) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
- return spec;
+ return RetType::okay(spec);
}
namespace impl {
Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, bool& hasPosition, bool& hasColon)
{
+ using RetType = Result<size_t, FudStatus>;
int nesting = 0;
uint32_t captureGroups = 0;
size_t index = 0;
@@ -162,14 +164,14 @@ Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, b
switch (letter) {
case FormatSpec::openBracket:
if (not hasColon) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
if (takesWidth) {
spec.takesWidth = true;
} else if (takesPrecision) {
spec.takesPrecision = true;
} else {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
nesting++;
captureGroups++;
@@ -193,7 +195,7 @@ Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, b
}
if (nesting > 1) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
index++;
@@ -201,10 +203,10 @@ Result<size_t, FudStatus> preScanSpec(StringView formatView, FormatSpec& spec, b
if (nesting != 0 || captureGroups > 2 || index >= formatView.length() ||
formatView[index] != FormatSpec::closeBracket) {
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
}
- return index + 1U;
+ return RetType::okay(index + 1U);
}
FudStatus getPosition(StringView& formatView, FormatSpec& spec, bool& hasPosition)
@@ -570,6 +572,7 @@ FudStatus fillUnsignedBuffer(
[[nodiscard]] Result<bool, FudStatus> validateFloatFormatType(FormatType formatType)
{
+ using RetType = Result<bool, FudStatus>;
auto uppercase = false;
switch (formatType) {
@@ -604,13 +607,13 @@ FudStatus fillUnsignedBuffer(
case FormatType::BinaryUpper:
case FormatType::String:
case FormatType::Escaped:
- return FudStatus::FormatInvalid;
+ return RetType::error(FudStatus::FormatInvalid);
break;
default:
- return FudStatus::Failure;
+ return RetType::error(FudStatus::Failure);
}
- return uppercase;
+ return RetType::okay(uppercase);
}
ExponentBuffer getScientificExponent(int exponent, uint8_t& exponentLength, bool uppercase)
diff --git a/source/fud_string.cpp b/source/fud_string.cpp
index 4943dac..edb25da 100644
--- a/source/fud_string.cpp
+++ b/source/fud_string.cpp
@@ -51,27 +51,27 @@ StringResult String::makeFromCString(const char* cString, Allocator* allocator)
}
String output{};
- output.m_allocator = allocator;
+ output.m_allocator = reinterpret_cast<uintptr_t>(allocator);
utf8* data{nullptr};
size_t capacity = length + 1;
bool isLarge = capacity > SsoBufSize;
if (isLarge) {
- output.m_repr.large.capacity = capacity & largeStringCapacitymask;
+ output.m_repr.large.capacity = capacity;
output.m_repr.large.length = length;
auto dataResult = output.allocator()->allocate(output.m_repr.large.capacity);
if (dataResult.isError()) {
return StringResult::error(dataResult.getError());
}
output.m_repr.large.data = static_cast<utf8*>(dataResult.getOkay());
- output.m_repr.large.isLarge = 1;
data = output.m_repr.large.data;
+ output.setLarge();
} else {
capacity = SsoBufSize;
static_assert(SsoBufSize < std::numeric_limits<int8_t>::max());
- output.m_repr.small.isLarge = 0;
output.m_repr.small.length = static_cast<uint8_t>(length) & smallStringLengthMask;
data = output.m_repr.small.buffer.data();
+ output.setSmall();
}
fudAssert(data != nullptr);
@@ -99,7 +99,7 @@ StringResult String::from(const String& rhs)
if (rhs.isLarge()) {
output.m_repr.large = rhs.m_repr.large;
output.m_repr.large.data = static_cast<utf8*>(
- M_TakeOrReturn(output.allocator()->allocate(output.m_repr.large.capacity)));
+ M_TakeOrReturn(StringResult, output.allocator()->allocate(output.m_repr.large.capacity)));
data = output.m_repr.large.data;
capacity = output.m_repr.large.capacity;
length = output.m_repr.large.length;
@@ -135,22 +135,22 @@ StringResult String::from(StringView view, Allocator* allocator)
}
String output{};
- output.m_allocator = allocator;
+ output.m_allocator = reinterpret_cast<uintptr_t>(allocator);
size_t capacity = view.length() + 1U;
bool isLarge = capacity > SsoBufSize;
utf8* data{nullptr};
if (isLarge) {
- output.m_repr.large.capacity = capacity & largeStringCapacitymask;
+ output.m_repr.large.capacity = capacity;
output.m_repr.large.length = view.length();
- output.m_repr.large.data = static_cast<utf8*>(M_TakeOrReturn(output.allocator()->allocate(capacity)));
- output.m_repr.large.isLarge = 1;
+ output.m_repr.large.data = static_cast<utf8*>(M_TakeOrReturn(StringResult, output.allocator()->allocate(capacity)));
data = output.m_repr.large.data;
+ output.setLarge();
} else {
capacity = SsoBufSize;
static_assert(SsoBufSize < std::numeric_limits<int8_t>::max());
- output.m_repr.small.isLarge = 0;
output.m_repr.small.length = static_cast<uint8_t>(view.length()) & smallStringLengthMask;
data = output.m_repr.small.buffer.data();
+ output.setSmall();
}
fudAssert(data != nullptr);
auto copyStatus = copyMem(data, capacity, view.m_data, view.length());
@@ -194,7 +194,11 @@ FudStatus String::copy(const String& rhs)
size_t length{};
if (isLarge()) {
- m_repr.large.data = static_cast<utf8*>(M_TakeOrReturn(allocator()->allocate(m_repr.large.capacity)));
+ auto allocResult = allocator()->allocate(m_repr.large.capacity);
+ if (allocResult.isError()) {
+ return allocResult.takeError();
+ }
+ m_repr.large.data = static_cast<utf8*>(allocResult.takeOkay());
capacity = m_repr.large.capacity;
length = m_repr.large.length;
data = m_repr.large.data;
@@ -251,11 +255,11 @@ FudStatus String::resize(size_t newCapacity)
return FudStatus::OperationInvalid;
}
- if (!isLarge() && newCapacity <= SSO_BUF_SIZE) {
+ if (!isLarge() && newCapacity <= SsoBufSize) {
return FudStatus::Success;
}
- if (newCapacity <= SSO_BUF_SIZE) {
+ if (newCapacity <= SsoBufSize) {
fudAssert(isLarge());
auto len = static_cast<uint8_t>(length());
@@ -264,7 +268,7 @@ FudStatus String::resize(size_t newCapacity)
fudAssert(copyResult == FudStatus::Success);
auto deallocStatus = allocator()->deallocate(m_repr.large.data, m_repr.large.capacity);
- m_repr.small.isLarge = 0;
+ setSmall();
m_repr.small.length = len & smallStringLengthMask;
copyMem(m_repr.small.buffer, temp);
m_repr.small.buffer[len] = '\0';
@@ -272,7 +276,11 @@ FudStatus String::resize(size_t newCapacity)
return deallocStatus != FudStatus::Success ? FudStatus::DeallocFailure : FudStatus::Success;
}
- auto* newData = static_cast<utf8*>(M_TakeOrReturn(allocator()->allocate(newCapacity)));
+ auto allocResult = allocator()->allocate(newCapacity);
+ if (allocResult.isError()) {
+ return allocResult.takeError();
+ }
+ auto* newData = static_cast<utf8*>(allocResult.takeOkay());
fudAssert(newData != nullptr);
auto copyResult = copyMem(newData, newCapacity, data(), length());
@@ -285,8 +293,8 @@ FudStatus String::resize(size_t newCapacity)
size_t len = length();
- m_repr.large.isLarge = 1;
- m_repr.large.capacity = newCapacity & largeStringCapacitymask;
+ setLarge();
+ m_repr.large.capacity = newCapacity;
m_repr.large.data = newData;
m_repr.large.length = len;
m_repr.large.data[m_repr.large.length] = '\0';
@@ -622,19 +630,19 @@ StringResult String::catenate(const char* rhs) const
size_t outputCapacity = outputLength + 1;
utf8* outputData{nullptr};
if (outputCapacity > SsoBufSize) {
- output.m_repr.large.capacity = outputCapacity & largeStringCapacitymask;
+ output.m_repr.large.capacity = outputCapacity;
output.m_repr.large.length = outputLength;
auto dataResult = output.allocator()->allocate(output.m_repr.large.capacity);
if (dataResult.isError()) {
return StringResult::error(dataResult.getError());
}
output.m_repr.large.data = static_cast<utf8*>(dataResult.getOkay());
- output.m_repr.large.isLarge = 1;
+ output.setLarge();
outputData = output.m_repr.large.data;
} else {
outputCapacity = SsoBufSize;
static_assert(SsoBufSize < std::numeric_limits<int8_t>::max());
- output.m_repr.small.isLarge = 0;
+ output.setSmall();
output.m_repr.small.length = static_cast<uint8_t>(outputLength) & smallStringLengthMask;
outputData = output.m_repr.small.buffer.data();
}
@@ -669,19 +677,19 @@ StringResult String::catenate(const String& rhs) const
size_t outputCapacity = outputLength + 1;
utf8* outputData{nullptr};
if (outputCapacity > SsoBufSize) {
- output.m_repr.large.capacity = outputCapacity & largeStringCapacitymask;
+ output.m_repr.large.capacity = outputCapacity;
output.m_repr.large.length = outputLength;
auto dataResult = output.allocator()->allocate(output.m_repr.large.capacity);
if (dataResult.isError()) {
return StringResult::error(dataResult.getError());
}
output.m_repr.large.data = static_cast<utf8*>(dataResult.getOkay());
- output.m_repr.large.isLarge = 1;
+ output.setLarge();
outputData = output.m_repr.large.data;
} else {
outputCapacity = SsoBufSize;
static_assert(SsoBufSize < std::numeric_limits<int8_t>::max());
- output.m_repr.small.isLarge = 0;
+ output.setSmall();
output.m_repr.small.length = static_cast<uint8_t>(outputLength) & smallStringLengthMask;
outputData = output.m_repr.small.buffer.data();
}
diff --git a/source/fud_string_convert.cpp b/source/fud_string_convert.cpp
index 428ab36..fdf3436 100644
--- a/source/fud_string_convert.cpp
+++ b/source/fud_string_convert.cpp
@@ -36,59 +36,60 @@ Result<bool, FudStatus> checkNegative(StringView& view, size_t& skipIndex)
{
bool isNegative = view.data()[0] == '-';
if (isNegative && view.length() == 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
if (isNegative) {
skipIndex += 1;
view.advanceUnsafe();
}
- return isNegative;
+ return Okay<bool>{isNegative};
}
Result<Radix, FudStatus> determineRadix(StringView input, size_t& index)
{
if (input.length() < 1) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
if (input.length() == 1 && input.data()[0] == '0') {
- return Radix::Octal;
+ return Okay<Radix>{Radix::Octal};
}
if (input.length() == 1) {
- return Radix::Decimal;
+ return Okay<Radix>{Radix::Decimal};
}
if (input.data()[0] == '0' && (input.data()[1] == 'x' || input.data()[1] == 'X')) {
index += 2;
- return Radix::Hexadecimal;
+ return Okay<Radix>{Radix::Hexadecimal};
}
if (input.data()[0] == '0') {
auto nextChar = input.data()[1];
auto nextVal = AsciiLookup[nextChar];
if (nextVal >= 0 && nextVal < static_cast<uint8_t>(Radix::Octal)) {
- return Radix::Octal;
+ return Okay<Radix>{Radix::Octal};
}
if (nextVal >= static_cast<uint8_t>(Radix::Octal)) {
- return FudStatus::ArgumentInvalid;
+ return FudError{FudStatus::ArgumentInvalid};
}
}
- return Radix::Decimal;
+ return Okay<Radix>{Radix::Decimal};
}
Result<uint8_t, FudStatus> getRadix(StringView& view, size_t& skipIndex, Option<uint8_t> specifiedRadixOption)
{
+ using RetType = Result<uint8_t, FudStatus>;
if (specifiedRadixOption.isNone()) {
size_t radixIndex = 0;
auto status = determineRadix(view, radixIndex);
if (status.isOkay()) {
skipIndex += radixIndex;
view.advanceUnsafe(radixIndex);
- return static_cast<uint8_t>(status.takeOkay());
+ return RetType::okay(static_cast<uint8_t>(status.takeOkay()));
}
- return status.takeError();
+ return RetType::error(status);
}
auto radix = specifiedRadixOption.value();
@@ -104,7 +105,7 @@ Result<uint8_t, FudStatus> getRadix(StringView& view, size_t& skipIndex, Option<
view.advanceUnsafe(2);
}
- return radix;
+ return RetType::okay(radix);
}
} // namespace fud::impl
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index aef8052..1ceca71 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -7,7 +7,7 @@ else()
endif()
if(FUD_SAN)
-set(CVG_FLAGS ${CVG_FLAGS} -fsanitize=address -fsanitize=undefined)
+set(CVG_FLAGS ${CVG_FLAGS} -fsanitize=address -fsanitize=undefined -fno-sanitize=vptr)
endif()
set(gtest_URL https://github.com/google/googletest.git)
diff --git a/test/test_file.cpp b/test/test_file.cpp
index 06e6bcc..27844d8 100644
--- a/test/test_file.cpp
+++ b/test/test_file.cpp
@@ -75,7 +75,7 @@ TEST(FudFile, Basic)
};
ASSERT_GE(createFile(testName1), 0);
- fileResult = RegularFile::open(testName1.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt);
+ fileResult = std::move(RegularFile::open(testName1.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt));
ASSERT_TRUE(fileResult.isOkay());
auto file{fileResult.takeOkay()};
ASSERT_EQ(file.close(), FudStatus::Success);
diff --git a/test/test_fud.cpp b/test/test_fud.cpp
index 72d569a..f84ad20 100644
--- a/test/test_fud.cpp
+++ b/test/test_fud.cpp
@@ -51,7 +51,7 @@ TEST(FudTest, GetEnv)
ASSERT_TRUE(fudVarResult.isError());
ASSERT_EQ(fudVarResult.getError(), FudStatus::NullPointer);
- fudVarResult = getEnv(testVarName);
+ fudVarResult = std::move(getEnv(testVarName));
ASSERT_TRUE(fudVarResult.isError());
ASSERT_EQ(fudVarResult.getError(), FudStatus::NotFound);
diff --git a/test/test_result.cpp b/test/test_result.cpp
index 5eadd8c..414941a 100644
--- a/test/test_result.cpp
+++ b/test/test_result.cpp
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-#include "fud_status.hpp"
#include "fud_result.hpp"
+#include "fud_status.hpp"
#include "gtest/gtest.h"
@@ -49,4 +49,9 @@ TEST(ResultTest, ErrResult)
ASSERT_EQ(err2.getError(), FudStatus::ArgumentInvalid);
}
+TEST(ResultTest, ImplicitConversion)
+{
+ // Result<int, int16_t> foo = Result<int, int16_t>::okay(-1);
+}
+
} // namespace fud
diff --git a/test/test_utf8.cpp b/test/test_utf8.cpp
index 5447954..8c3cad2 100644
--- a/test/test_utf8.cpp
+++ b/test/test_utf8.cpp
@@ -137,13 +137,14 @@ TEST(Utf8Test, Utf8MultiByte)
virtual Result<void*, FudStatus> allocate(size_t bytes, size_t alignment) override final
{
+ using RetType = Result<void*, FudStatus>;
static_cast<void>(alignment);
if (bytes > m_memory.size() - m_allocated) {
- return FudStatus::AllocFailure;
+ return RetType::error(FudStatus::AllocFailure);
}
auto* data = m_memory.data() + m_allocated;
m_allocated += bytes;
- return data;
+ return RetType::okay(data);
}
virtual FudStatus deallocate(void* pointer, size_t bytes) override final
diff --git a/test/test_vector.cpp b/test/test_vector.cpp
index b4fd83c..cadeaa6 100644
--- a/test/test_vector.cpp
+++ b/test/test_vector.cpp
@@ -98,7 +98,8 @@ TEST(VectorTest, NonTrivialVector)
ASSERT_GE(nonTrivialVector.capacity(), 11);
ASSERT_EQ(counter, 11);
auto capacity = nonTrivialVector.capacity();
- ASSERT_EQ(nonTrivialVector.reserve(SIZE_MAX / sizeof(NonTrivial)), FudStatus::AllocFailure);
+ constexpr auto FAIL_RESERVE_SIZE = 0x10000000000 / sizeof(NonTrivial);
+ ASSERT_EQ(nonTrivialVector.reserve(FAIL_RESERVE_SIZE), FudStatus::AllocFailure);
ASSERT_EQ(nonTrivialVector.capacity(), capacity);
{