summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-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
7 files changed, 333 insertions, 141 deletions
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;