From 8ce397e8c0a83e49e390de9deb73d588e4931ecf Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Tue, 29 Oct 2024 21:02:25 -0500 Subject: Reworking of Result. --- include/fud_drain.hpp | 35 +++++++ include/fud_format.hpp | 43 +++++---- include/fud_result.hpp | 214 +++++++++++++++++++++++++++++++++++------ include/fud_string.hpp | 64 +++++------- include/fud_string_convert.hpp | 51 +++++----- include/fud_utf8.hpp | 1 + include/fud_vector.hpp | 66 ++++++++----- 7 files changed, 333 insertions(+), 141 deletions(-) create mode 100644 include/fud_drain.hpp (limited to 'include') 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 +#include + +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 Result getSpecField(FormatSpec& formatSpec, uint32_t index, const FormatArguments& args) { + using RetType = Result; static_assert(not std::is_signed_v); 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(args[index])) { - return std::get(args[index]); + return RetType::okay(std::get(args[index])); } if (std::holds_alternative(args[index])) { auto value = std::get(args[index]); if (value < 0) { - return FudStatus::FormatInvalid; + return RetType::error(FudStatus::FormatInvalid); } - return static_cast(value); + return RetType::okay(static_cast(value)); } if (std::holds_alternative(args[index])) { auto value = std::get(args[index]); if (value < 0 || value > std::numeric_limits::max()) { - return FudStatus::FormatInvalid; + return RetType::error(FudStatus::FormatInvalid); } - return static_cast(value); + return RetType::okay(static_cast(value)); } if (std::holds_alternative(args[index])) { - return std::get(args[index]); + return RetType::okay(std::get(args[index])); } if (std::holds_alternative(args[index])) { auto value = std::get(args[index]); if (value > std::numeric_limits::max()) { - return FudStatus::FormatInvalid; + return RetType::error(FudStatus::FormatInvalid); } - return static_cast(value); + return RetType::okay(static_cast(value)); } - return FudStatus::FormatInvalid; + return RetType::error(FudStatus::FormatInvalid); } template @@ -514,6 +515,7 @@ Result vFormatPrepareSpec( bool& firstSpec, bool& takesPosition) { + using RetType = Result; if (firstSpec) { firstSpec = false; return vFormatPrepareFirstSpec(scanView, args, argIndex, takesPosition); @@ -528,24 +530,24 @@ Result 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 @@ -555,6 +557,7 @@ Result vFormatPrepareFirstSpec( const uint32_t& argIndex, bool& takesPosition) { + using RetType = Result; size_t specLength{0}; auto formatSpecResult{FormatSpec::parse(scanView, specLength)}; if (formatSpecResult.isError()) { @@ -567,18 +570,18 @@ Result 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 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 +#include // IWYU pragma: keep (placement new) +#include #include -#include namespace fud { +template +struct Okay { + T value; +}; + +template +struct Error { + E value; +}; + +using FudError = Error; + /** \brief A result type which contains either a T on success or an E on error. */ template class [[nodiscard]] Result { public: using ResultType = Result; - constexpr Result(const T& value) : m_value{value} + constexpr ~Result() noexcept { + destroy(); } - constexpr Result(const E& value) : m_value{value} + constexpr Result(const Okay& 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&& 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& 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& 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&& 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& 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&& 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 static constexpr ResultType okay(const Result& okayRes) { - return ResultType{okayRes.getOkay()}; + return ResultType::okay(okayRes.getOkay()); } template static constexpr ResultType okay(Result&& okayRes) { - return ResultType{okayRes.takeOkay()}; + return ResultType::okay(okayRes.takeOkay()); } template static constexpr ResultType error(const Result& errorRes) { - return ResultType{errorRes.getError()}; + return ResultType::error(errorRes.getError()); } template static constexpr ResultType error(Result&& 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(m_value); + fudAssert(isOkay()); + return *reinterpret_cast(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(m_value); + return *reinterpret_cast(m_data.data()); } [[nodiscard]] constexpr const E& getError() const& { - return std::get(m_value); + fudAssert(isError()); + return *reinterpret_cast(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(m_value); + return *reinterpret_cast(m_data.data()); } [[nodiscard]] constexpr T&& takeOkay() { - return std::move(std::get(m_value)); + fudAssert(isOkay()); + return std::move(*reinterpret_cast(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(m_value)); + return std::move(*reinterpret_cast(m_data.data())); } [[nodiscard]] constexpr E&& takeError() { - return std::move(std::get(m_value)); + fudAssert(isError()); + return std::move(*reinterpret_cast(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(m_value)); + return std::move(*reinterpret_cast(m_data.data())); } private: - constexpr Result() : m_value() + constexpr Result() + requires(std::is_default_constructible_v) + : 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 and not std::is_convertible_v) + : 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 and not std::is_convertible_v) + : m_data{}, m_discriminant{Discriminant::Okay} { + auto ptrValue = new (m_data.data()) T(std::move(value)); + fudAssert(ptrValue != nullptr); } - std::variant m_value; + constexpr Result(const E& value) + requires(not std::is_convertible_v and not std::is_convertible_v) + : 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 and not std::is_convertible_v) + : 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(m_data.data())->~T(); + m_discriminant = Discriminant::Invalid; + } else if (m_discriminant == Discriminant::Error) { + reinterpret_cast(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 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(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(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::max()); - output.m_repr.small.isLarge = 0; output.m_repr.small.length = static_cast(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(1) << 63) - 1; - static constexpr size_t largeStringCapacitymask = (static_cast(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(0x01); + static constexpr auto allocatorMask = ~isLargeMask; [[nodiscard]] static bool allocatorValid(Allocator* allocator) { - return allocator != nullptr; + return (reinterpret_cast(allocator) & isLargeMask) == 0; } Allocator* allocator() const { - return m_allocator; + return reinterpret_cast(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(&globalFudAllocator)}; using BufType = Array; 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 unsignedFromString(StringView nextView, size_t skipIndex, static_assert(std::is_unsigned_v && std::is_integral_v); 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 unsignedFromString(StringView nextView, size_t skipIndex, auto digit = static_cast(digitResult); if (std::numeric_limits::max() / radix < num) { - return FudStatus::RangeError; + return FudError{FudStatus::RangeError}; } num *= radix; if (std::numeric_limits::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 @@ -203,12 +203,12 @@ StringConvertResult signedFromString(StringView nextView, size_t skipIndex, O static_assert(std::is_signed_v && std::is_integral_v); 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 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 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 @@ -343,21 +343,22 @@ FudStatus getFraction(const StringView view, size_t& digitIndex, T& num, T sign, template StringConvertResult floatFromString(StringView nextView, size_t skipIndex, Option specifiedRadixOption) { + using RetType = StringConvertResult; static_assert(std::is_floating_point_v); 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 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 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 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 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 StringConvertResult fromString(StringView inputView, Option 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 fromString(StringView inputView, Option specifie } else if constexpr (std::is_floating_point_v) { return impl::floatFromString(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 #include +#include 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, FudStatus> span() const { + using RetType = Result, 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, FudStatus> span() { + using RetType = Result, 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, FudStatus> span(size_t count) const { + using RetType = Result, 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, FudStatus> span(size_t count) { + using RetType = Result, 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, FudStatus> span(size_t start, size_t count) const { + using RetType = Result, 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, FudStatus> span(size_t start, size_t count) { + using RetType = Result, 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, FudStatus> get(size_t index) { + using RetType = Result, 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, FudStatus> ref(size_t index) const { + using RetType = Result, 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 front() @@ -527,13 +540,14 @@ class Vector { Result popBack() { + using RetType = Result; 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; -- cgit v1.2.3