summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--cmake/CheckGit.cmake14
-rw-r--r--cmake/fud_config.hpp.in (renamed from cmake/fud_version.hpp.in)3
-rw-r--r--include/fud_algorithm.hpp36
-rw-r--r--include/fud_array.hpp10
-rw-r--r--include/fud_memory.hpp16
-rw-r--r--include/fud_option.hpp229
-rw-r--r--include/fud_span.hpp10
-rw-r--r--include/fud_status.hpp66
-rw-r--r--include/fud_vector.hpp628
-rw-r--r--source/fud_string_view.cpp2
-rw-r--r--source/libfud.cpp8
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/test_common.hpp6
-rw-r--r--test/test_fud.cpp27
-rw-r--r--test/test_option.cpp54
-rw-r--r--test/test_utf8.cpp1125
-rw-r--r--test/test_vector.cpp138
18 files changed, 1488 insertions, 897 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f0e9aff..5a41872 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,12 +40,17 @@ target_link_libraries(fud ${SQLite3_LIBRARIES})
set_target_properties(
fud PROPERTIES
- CXX_STANDARD 23
+ CXX_STANDARD 20
C_STANDARD 23
CXX_EXTENSIONS OFF
C_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON)
+if (DEFINED FUD_BOUNDS_CHECKING)
+else()
+ set(FUD_BOUNDS_CHECKING true)
+endif()
+
if (FUD_TEST)
add_subdirectory(test)
# set(CVG_FLAGS -fsanitize=address -fsanitize=undefined --coverage)
@@ -98,6 +103,7 @@ set(FUD_HEADERS
"include/fud_directory.hpp"
"include/fud_fud_type_traits.hpp"
"include/fud_memory.hpp"
+ "include/fud_option.hpp"
"include/fud_permissions.hpp"
"include/fud_result.hpp"
"include/fud_span.hpp"
@@ -109,6 +115,7 @@ set(FUD_HEADERS
"include/fud_utf8.hpp"
"include/fud_utf8_iterator.hpp"
"include/fud_vector.hpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/fud_config.hpp"
)
set_target_properties(fud PROPERTIES PUBLIC_HEADER "${FUD_HEADERS}")
@@ -121,5 +128,5 @@ install(TARGETS fud
include(cmake/CheckGit.cmake)
CheckGitSetup(GIT_HASH)
-configure_file(cmake/fud_version.hpp.in include/fud_version.hpp @ONLY)
+configure_file(cmake/fud_config.hpp.in include/fud_config.hpp @ONLY)
add_dependencies(fud AlwaysCheckGit)
diff --git a/cmake/CheckGit.cmake b/cmake/CheckGit.cmake
index f7d8bce..46736e7 100644
--- a/cmake/CheckGit.cmake
+++ b/cmake/CheckGit.cmake
@@ -7,8 +7,8 @@ if (NOT DEFINED post_configure_dir)
set(post_configure_dir ${CMAKE_BINARY_DIR}/include)
endif ()
-set(pre_configure_file ${pre_configure_dir}/fud_version.hpp.in)
-set(post_configure_file ${post_configure_dir}/fud_version.hpp)
+set(pre_configure_file ${pre_configure_dir}/fud_config.hpp.in)
+set(post_configure_file ${post_configure_dir}/fud_config.hpp)
function(CheckGitWrite git_hash)
file(WRITE ${CMAKE_BINARY_DIR}/git-state.txt ${git_hash})
@@ -37,15 +37,15 @@ function(CheckGitVersion git_hash)
file(MAKE_DIRECTORY ${post_configure_dir})
endif ()
- # if (NOT EXISTS ${post_configure_dir}/fud_version.h)
- # file(COPY ${pre_configure_dir}/fud_version.h DESTINATION ${post_configure_dir})
+ # if (NOT EXISTS ${post_configure_dir}/fud_config.h)
+ # file(COPY ${pre_configure_dir}/fud_config.h DESTINATION ${post_configure_dir})
# endif()
if (NOT DEFINED GIT_HASH_CACHE)
set(GIT_HASH_CACHE "INVALID")
endif ()
- # Only update the fud_version.cpp if the hash has changed. This will
+ # Only update the fud_config.cpp if the hash has changed. This will
# prevent us from rebuilding the project more than we need to.
if (NOT ${GIT_HASH} STREQUAL ${GIT_HASH_CACHE} OR NOT EXISTS ${post_configure_file})
# Set che GIT_HASH_CACHE variable the next build won't have
@@ -70,8 +70,8 @@ function(CheckGitSetup top_git_hash)
BYPRODUCTS ${post_configure_file}
)
- add_library(fud_version INTERFACE ${CMAKE_BINARY_DIR}/include/fud_version.hpp)
- add_dependencies(fud_version AlwaysCheckGit)
+ add_library(fud_config INTERFACE ${CMAKE_BINARY_DIR}/include/fud_config.hpp)
+ add_dependencies(fud_config AlwaysCheckGit)
CheckGitVersion(git_hash)
set(${top_git_hash} ${git_hash} PARENT_SCOPE)
diff --git a/cmake/fud_version.hpp.in b/cmake/fud_config.hpp.in
index 5cce0e4..e83e9c3 100644
--- a/cmake/fud_version.hpp.in
+++ b/cmake/fud_config.hpp.in
@@ -8,7 +8,8 @@ namespace fud {
constexpr uint8_t FudVersionMajor = @PROJECT_VERSION_MAJOR@;
constexpr uint8_t FudVersionMinor = @PROJECT_VERSION_MINOR@;
constexpr uint8_t FudVersionPatch = @PROJECT_VERSION_PATCH@;
-constexpr const char GitHash[] = "@GIT_HASH@";
+constexpr const char FudGitHash[] = "@GIT_HASH@";
+static constexpr bool fudBoundsChecking = @FUD_BOUNDS_CHECKING@;
} // namespace fud
diff --git a/include/fud_algorithm.hpp b/include/fud_algorithm.hpp
index e3d5d3b..0ad71d5 100644
--- a/include/fud_algorithm.hpp
+++ b/include/fud_algorithm.hpp
@@ -18,11 +18,11 @@
#ifndef FUD_ALGORITHM_HPP
#define FUD_ALGORITHM_HPP
+#include "fud_option.hpp"
#include "fud_span.hpp"
#include <concepts>
#include <limits>
-#include <optional>
#include <type_traits>
namespace fud {
@@ -48,30 +48,41 @@ class Iota {
{
}
- constexpr std::optional<T> operator()() noexcept
+ constexpr Iota(const Iota& rhs) noexcept = default;
+
+ constexpr Iota(Iota&& rhs) noexcept = default;
+
+ ~Iota() noexcept = default;
+
+ Iota& operator=(const Iota& rhs) = default;
+
+ Iota& operator=(Iota&& rhs) = default;
+
+ constexpr Option<T> operator()() noexcept
{
auto value = m_value;
if (m_increment > 0) {
if (m_limit - m_increment < m_value) {
- return std::nullopt;
+ return NullOpt;
}
} else {
if (m_limit + m_increment + 1 >= m_value) {
- return std::nullopt;
+ return NullOpt;
}
}
m_value += m_increment;
return value;
}
- void set(T value) {
+ void set(T value)
+ {
m_value = value;
}
private:
T m_value;
- const T m_increment;
- const T m_limit;
+ T m_increment;
+ T m_limit;
};
template <typename T, size_t Size, typename Func>
@@ -91,18 +102,19 @@ Span<T, Size> mapTo(Span<T, Size> input, Span<U, Size> output, Func&& mapFunc)
output[idx] = std::forward<Func>(mapFunc)(input[idx]);
}
- return input;
+ return output;
}
-template <typename T, size_t Size, typename Func, typename Builder, typename Output>
+template <typename T, size_t Size, typename Func, typename Builder>
auto map(Span<T, Size> input, Func&& mapFunc, Builder&& builder) -> decltype(std::forward<Builder>(builder)())
{
+ using Output = decltype(std::forward<Builder>(builder)());
Output output{std::forward<Builder>(builder)()};
for (auto idx = 0; idx < input.size() && idx < output.size(); ++idx) {
output[idx] = std::forward<Func>(mapFunc)(input[idx]);
}
- return input;
+ return output;
}
template <typename Generator, typename Builder>
@@ -132,7 +144,7 @@ bool allOf(Generator&& generator, Func&& predicate)
{
bool result = true;
while (auto val = std::forward<Generator>(generator)()) {
- result = result && std::forward<Func>(predicate)(*val);
+ result = result && std::forward<Func>(predicate)(val.value());
}
return result;
}
@@ -152,7 +164,7 @@ bool anyOf(Generator&& generator, Func&& predicate)
{
bool result = false;
while (auto val = std::forward<Generator>(generator)()) {
- result = result || std::forward<Func>(predicate)(*val);
+ result = result || std::forward<Func>(predicate)(val.value());
}
return result;
}
diff --git a/include/fud_array.hpp b/include/fud_array.hpp
index 807621a..dcbd54a 100644
--- a/include/fud_array.hpp
+++ b/include/fud_array.hpp
@@ -18,9 +18,10 @@
#ifndef FUD_ARRAY_HPP
#define FUD_ARRAY_HPP
-#include <cstddef>
-
#include "fud_memory.hpp"
+#include "fud_span.hpp"
+
+#include <cstddef>
namespace fud {
@@ -106,6 +107,11 @@ struct Array {
constexpr bool operator==(const Array<T, Size>&) const noexcept = default;
constexpr auto operator<=>(const Array<T, Size>& other) const noexcept = default;
+
+ Span<T, Size> span()
+ {
+ return Span<T, Size>{data(), Size};
+ }
};
} // namespace fud
diff --git a/include/fud_memory.hpp b/include/fud_memory.hpp
index 97328a9..6ce6312 100644
--- a/include/fud_memory.hpp
+++ b/include/fud_memory.hpp
@@ -57,6 +57,22 @@ constexpr void setMemory(Container<T, Size>& container, const T& value)
}
}
+template <template <class, size_t> class Container, typename T, size_t Size>
+constexpr void setMemory(Container<T, Size>& container, T&& value)
+{
+ for (auto& elt : container) {
+ elt = value;
+ }
+}
+
+template <template <size_t> class Container, typename T, size_t Size>
+constexpr void setMemory(Container<Size>& container, T&& value)
+{
+ for (auto& elt : container) {
+ elt = value;
+ }
+}
+
template <size_t Count, typename T, typename U>
void copyMem(T& destination, const U& source)
{
diff --git a/include/fud_option.hpp b/include/fud_option.hpp
new file mode 100644
index 0000000..ca3954f
--- /dev/null
+++ b/include/fud_option.hpp
@@ -0,0 +1,229 @@
+/*
+ * 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_OPTION_HPP
+#define FUD_OPTION_HPP
+
+#include "fud_assert.hpp"
+
+#include <cstddef>
+#include <functional>
+#include <new> // IWYU pragma: keep (placement new)
+#include <type_traits>
+
+namespace fud {
+
+namespace option_detail {
+
+struct NullOptionType {
+ enum class NullOptConstructor : char
+ {
+ Monostate
+ };
+
+ constexpr explicit NullOptionType(NullOptConstructor /*unnamed*/)
+ {
+ }
+};
+
+template <size_t Size>
+struct DataArray {
+ // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
+ std::byte m_data[Size];
+ // NOLINTEND(cppcoreguidelines-avoid-c-arrays)
+
+ constexpr std::byte* data() noexcept
+ {
+ return m_data;
+ }
+
+ [[nodiscard]] constexpr const std::byte* data() const noexcept
+ {
+ return m_data;
+ }
+
+ constexpr bool operator==(const DataArray&) const noexcept = default;
+
+ constexpr void clear()
+ {
+ for (size_t idx = 0; idx < Size; ++idx) {
+ m_data[idx] = std::byte(0);
+ }
+ }
+};
+
+} // namespace option_detail
+
+inline constexpr option_detail::NullOptionType NullOpt{option_detail::NullOptionType::NullOptConstructor::Monostate};
+
+template <typename T>
+class Option {
+ private:
+ static_assert(!std::is_same_v<T, option_detail::NullOptionType>);
+ static constexpr bool IsRef = std::is_reference_v<T>;
+ using ValueType = typename std::remove_reference<T>::type;
+ static constexpr size_t Size = IsRef ? sizeof(std::reference_wrapper<ValueType>) : sizeof(ValueType);
+
+ public:
+ constexpr Option() noexcept : m_engaged{false}
+ {
+ }
+
+ constexpr Option(option_detail::NullOptionType nullOpt) noexcept : m_engaged{false}
+ {
+ static_cast<void>(nullOpt);
+ }
+
+ constexpr Option(T value) noexcept : m_engaged{true}
+ {
+ if constexpr (IsRef) {
+ new (m_data.data()) std::reference_wrapper<ValueType>(std::ref(value));
+ if (!m_engaged) {
+ std::abort();
+ }
+ } else {
+ new (m_data.data()) ValueType(value);
+ if (!m_engaged) {
+ std::abort();
+ }
+ }
+ }
+
+ constexpr Option(const Option& rhs) noexcept : m_engaged(rhs.m_engaged), m_data(rhs.m_data)
+ {
+ }
+
+ constexpr Option(Option&& rhs) noexcept : m_engaged(rhs.m_engaged), m_data(std::move(rhs.m_data))
+ {
+ rhs.cleanup();
+ }
+
+ ~Option() noexcept
+ {
+ destroy();
+ }
+
+ Option& operator=(const Option& rhs) noexcept
+ {
+ if (&rhs == this) {
+ return *this;
+ }
+ destroy();
+ m_engaged = rhs.m_engaged;
+ m_data = rhs.m_data;
+ return *this;
+ }
+
+ Option& operator=(Option&& rhs) noexcept
+ {
+ destroy();
+ m_engaged = rhs.m_engaged;
+ m_data = std::move(rhs.m_data);
+ rhs.cleanup();
+ return *this;
+ }
+
+ [[nodiscard]] bool hasValue() const
+ {
+ return m_engaged;
+ }
+
+ operator bool() const {
+ return hasValue();
+ }
+
+ [[nodiscard]] constexpr const ValueType& value() const&
+ {
+ fudAssert(m_engaged);
+ if constexpr (IsRef) {
+ return *reinterpret_cast<const std::reference_wrapper<ValueType>*>(m_data.data());
+ } else {
+ return *reinterpret_cast<const ValueType*>(m_data.data());
+ }
+ }
+
+ [[nodiscard]] constexpr ValueType& value() &
+ {
+ fudAssert(m_engaged);
+ if constexpr (IsRef) {
+ return *reinterpret_cast<std::reference_wrapper<ValueType>*>(m_data.data());
+ } else {
+ return *reinterpret_cast<ValueType*>(m_data.data());
+ }
+ }
+
+ [[nodiscard]] constexpr const ValueType&& value() const&&
+ {
+ fudAssert(m_engaged);
+ static_assert(!IsRef);
+ return *reinterpret_cast<const ValueType*>(m_data.data());
+ }
+
+ template <typename F>
+ constexpr auto map(F&& func) const & -> Option<decltype(std::forward<F>(func)(value()))>
+ {
+ using U = decltype(std::forward<F>(func)(value()));
+ // static_assert(std::is_same_v<decltype(std::forward<F>(func)(value())), Option<U>>());
+ if (hasValue()) {
+ return Option<U>{std::forward<F>(func)(value())};
+ }
+ return Option<U>{NullOpt};
+ }
+
+ private:
+ constexpr void destroy() noexcept
+ {
+ if (m_engaged) {
+ if constexpr (IsRef) {
+ // reinterpret_cast<std::reference_wrapper<ValueType>*>(m_data.data());
+ } else {
+ reinterpret_cast<ValueType*>(m_data.data())->~ValueType();
+ }
+ cleanup();
+ }
+ }
+
+ constexpr void cleanup() noexcept
+ {
+ m_engaged = false;
+ m_data.clear();
+ }
+
+ // alignas(maxAlign) Array<uint8_t, maxSize> priv_m_data;
+
+ alignas(alignof(T)) option_detail::DataArray<Size> m_data{};
+
+ bool m_engaged;
+};
+
+namespace test {
+
+void testOption()
+{
+ Option<int> intOpt;
+ static_cast<void>(intOpt);
+ Option<int&> intRefNull;
+ static_cast<void>(intRefNull);
+ int value;
+ Option<int&> intRefValue{value};
+}
+
+} // namespace test
+
+} // namespace fud
+
+#endif
diff --git a/include/fud_span.hpp b/include/fud_span.hpp
index 5b8497e..ed4bcc7 100644
--- a/include/fud_span.hpp
+++ b/include/fud_span.hpp
@@ -18,7 +18,6 @@
#ifndef FUD_SPAN_HPP
#define FUD_SPAN_HPP
-#include "fud_array.hpp"
#include "fud_result.hpp"
#include "fud_status.hpp"
@@ -27,11 +26,17 @@
namespace fud {
+template <typename T, size_t Size>
+struct Array;
+
template <typename T, size_t Size = SIZE_MAX>
struct Span {
static_assert(Size > 0);
using ValueType = T;
+ T* m_data;
+ const size_t m_size;
+
static Span make(Array<T, Size>& array)
{
Span<T, Size> output{array.data(), Size};
@@ -89,9 +94,6 @@ struct Span {
return output;
}
- T* m_data;
- const size_t m_size;
-
[[nodiscard]] constexpr size_t size() const
{
if constexpr (Size < SIZE_MAX) {
diff --git a/include/fud_status.hpp b/include/fud_status.hpp
index 91048ac..d57a9c5 100644
--- a/include/fud_status.hpp
+++ b/include/fud_status.hpp
@@ -23,24 +23,26 @@ namespace fud {
enum class [[nodiscard]] FudStatus
{
Success = 0,
+ Partial,
+ Failure,
NullPointer,
- StringInvalid,
- ObjectInvalid,
- OperationInvalid,
- AllocFailure,
- DeallocFailure,
ArgumentInvalid,
+ VariantInvalid,
+ ObjectInvalid,
Utf8Invalid,
- Failure,
+ StringInvalid,
+ OperationInvalid,
+ AlreadyInitialized,
+ FormatInvalid,
+ RangeError,
+ IndexInvalid,
+ Exists,
NotFound,
- Aliased,
Empty,
- Partial,
Full,
- RangeError,
- VariantInvalid,
- BadArrayLength,
- FormatInvalid,
+ Aliased,
+ AllocFailure,
+ DeallocFailure,
NotImplemented,
NotSupported
};
@@ -50,6 +52,10 @@ constexpr const char* FudStatusToString(FudStatus status)
switch (status) {
case FudStatus::Success:
return "Success";
+ case FudStatus::Partial:
+ return "Partial";
+ case FudStatus::Failure:
+ return "Failure";
case FudStatus::NullPointer:
return "NullPointer";
case FudStatus::StringInvalid:
@@ -58,34 +64,34 @@ constexpr const char* FudStatusToString(FudStatus status)
return "ObjectInvalid";
case FudStatus::OperationInvalid:
return "OperationInvalid";
- case FudStatus::AllocFailure:
- return "AllocFailure";
- case FudStatus::DeallocFailure:
- return "DeallocFailure";
case FudStatus::ArgumentInvalid:
return "ArgumentInvalid";
case FudStatus::Utf8Invalid:
return "Utf8Invalid";
- case FudStatus::Failure:
- return "Failure";
- case FudStatus::NotFound:
- return "NotFound";
- case FudStatus::Aliased:
- return "Aliased";
- case FudStatus::Empty:
- return "Empty";
- case FudStatus::Partial:
- return "Partial";
- case FudStatus::Full:
- return "Full";
case FudStatus::RangeError:
return "RangeError";
case FudStatus::VariantInvalid:
return "VariantInvalid";
- case FudStatus::BadArrayLength:
- return "BadArrayLength";
case FudStatus::FormatInvalid:
return "FormatInvalid";
+ case FudStatus::AlreadyInitialized:
+ return "AlreadyInitialized";
+ case FudStatus::IndexInvalid:
+ return "IndexInvalid";
+ case FudStatus::Exists:
+ return "Exists";
+ case FudStatus::NotFound:
+ return "NotFound";
+ case FudStatus::Empty:
+ return "Empty";
+ case FudStatus::Full:
+ return "Full";
+ case FudStatus::Aliased:
+ return "Aliased";
+ case FudStatus::AllocFailure:
+ return "AllocFailure";
+ case FudStatus::DeallocFailure:
+ return "DeallocFailure";
case FudStatus::NotImplemented:
return "NotImplemented";
case FudStatus::NotSupported:
diff --git a/include/fud_vector.hpp b/include/fud_vector.hpp
index 56e1659..f90819a 100644
--- a/include/fud_vector.hpp
+++ b/include/fud_vector.hpp
@@ -19,42 +19,654 @@
#define FUD_VECTOR_HPP
#include "fud_allocator.hpp"
+#include "fud_assert.hpp"
+#include "fud_config.hpp"
+#include "fud_option.hpp"
#include "fud_result.hpp"
+#include "fud_span.hpp"
#include "fud_status.hpp"
#include <cstddef>
+#include <functional>
+#include <new> // IWYU pragma: keep (placement new)
namespace fud {
template <typename T>
class Vector {
+ static constexpr size_t ElementSize = sizeof(T);
+ static constexpr size_t Alignment = alignof(T);
+
public:
- static Result<Vector<T>, FudStatus> from(const Vector<T>& rhs);
+ constexpr Vector() noexcept = default;
+ constexpr Vector(const Vector<T>& rhs) = delete;
+ constexpr Vector(Vector<T>&& rhs) noexcept :
+ m_allocator(rhs.m_allocator), m_data(rhs.m_data), m_length{rhs.m_length}, m_capacity{rhs.m_capacity}
+ {
+ rhs.m_allocator = nullptr;
+ rhs.m_data = nullptr;
+ rhs.m_length = 0;
+ rhs.m_capacity = 0;
+ }
+
+ ~Vector() noexcept
+ {
+ static_cast<void>(cleanup());
+ }
+
+ Vector& operator=(const Vector<T>& rhs) = delete;
+
+ Vector& operator=(Vector<T>&& rhs) noexcept
+ {
+ cleanup();
+ m_allocator = rhs.m_allocator;
+ m_data = rhs.m_data;
+ m_length = rhs.m_length;
+ m_capacity = rhs.m_length;
+
+ rhs.m_allocataor = nullptr;
+ rhs.m_data = nullptr;
+ rhs.m_length = 0;
+ rhs.m_capacity = 0;
+ }
+
+ static Result<Vector<T>, FudStatus> withCapacity(size_t capacity, Allocator* allocator = &globalFudAllocator)
+ {
+ Vector<T> output{};
+ auto status = initializeWithCapacity(output, capacity, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ return output;
+ }
+
+ static FudStatus initializeWithCapacity(
+ Vector<T>& output,
+ size_t capacity,
+ Allocator* allocator = &globalFudAllocator)
+ {
+ if (output.m_data != nullptr) {
+ return FudStatus::AlreadyInitialized;
+ }
+
+ if (allocator == nullptr) {
+ return FudStatus::NullPointer;
+ }
+
+ if (capacity > SIZE_MAX / ElementSize) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ size_t requestedSize = capacity * ElementSize;
+ auto dataPtrResult = allocator->allocate(requestedSize, Alignment);
+ if (dataPtrResult.isError()) {
+ return dataPtrResult.getError();
+ }
+
+ output.m_allocator = allocator;
+ output.m_data = static_cast<T*>(dataPtrResult.getOkay());
+ output.m_length = 0;
+ output.m_capacity = capacity;
+ return FudStatus::Success;
+ }
+
+ static Result<Vector<T>, FudStatus> withSize(size_t count, Allocator* allocator = &globalFudAllocator)
+ {
+ Vector<T> output{};
+ auto status = initializeWithCapacity(output, count, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ return output;
+ }
+
+ static Result<Vector<T>, FudStatus> initializeWithSize(
+ Vector<T>& output,
+ size_t count,
+ Allocator* allocator = &globalFudAllocator)
+ {
+ if (output.m_data != nullptr) {
+ return FudStatus::AlreadyInitialized;
+ }
+
+ auto status = Vector::initializeWithCapacity(output, count, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ output.m_length = count;
+ for (size_t index = 0; index < count; ++index) {
+ const auto* ptr = new (output.m_data + index) T();
+ fudAssert(ptr != nullptr);
+ }
+ return output;
+ }
+
+ template <typename Builder>
+ static Result<Vector<T>, FudStatus> withSizeFallible(
+ size_t count,
+ Builder&& builder,
+ Allocator* allocator = &globalFudAllocator)
+ {
+ Vector<T> output{};
+ auto status = initializeWithSizeFallible(output, count, std::forward<Builder>(builder), allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ return output;
+ }
+
+ template <typename Builder>
+ static Result<Vector<T>, FudStatus> initializeWithSizeFallible(
+ Vector<T>& output,
+ size_t count,
+ Builder&& builder,
+ Allocator* allocator = &globalFudAllocator)
+ {
+ using BuilderResult = decltype(std::forward<Builder>(builder)());
+ static_assert(std::is_same_v<BuilderResult, FudStatus>());
+
+ auto status = Vector::initializeWithCapacity(output, count, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+
+ output.m_length = count;
+
+ for (size_t index = 0; index < count; ++index) {
+ auto builderResult{std::forward<Builder>(builder)(output.m_data[index])};
+ if (builderResult.isError()) {
+ return builderResult.takeError();
+ }
+ }
+
+ return output;
+ }
- static Vector<T> move(Vector<T>&& rhs);
+ static Result<Vector<T>, FudStatus> from(const Vector<T>& rhs, Option<Allocator*> allocatorOption = NullOpt)
+ {
+ Allocator* allocator = nullptr;
+ if (allocatorOption.hasValue()) {
+ allocator = allocatorOption.value();
+ if (allocator == nullptr) {
+ return FudStatus::NullPointer;
+ }
+ } else {
+ allocator = rhs.allocator;
+ if (allocator == nullptr) {
+ return FudStatus::ArgumentInvalid;
+ }
+ }
+
+ fudAssert(rhs.m_length <= rhs.m_capacity);
+
+ auto spanResult = rhs.span();
+ if (spanResult.isError()) {
+ return spanResult.takeError();
+ }
+ Vector<T> output{};
+ auto status = Vector::initializeFromSpan(output, rhs.m_length, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ return output;
+ }
+
+ template <size_t Size>
+ static Result<Vector<T>, FudStatus> from(Span<const T, Size>& rhs, Allocator* allocator)
+ {
+ Vector<T> output{};
+ auto status = initializeFromSpan(output, rhs, allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ return output;
+ }
+
+ template <size_t Size>
+ static FudStatus initializeFromSpan(Vector<T>& output, Span<const T, Size>& rhs, Allocator* allocator)
+ {
+ auto status = Vector::initializeWithCapacity(output, rhs.size(), allocator);
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ output.m_length = rhs.m_length;
+ for (size_t index = 0; index < output.m_length; ++index) {
+ output.m_data[index] = rhs[index];
+ }
+ }
+
+ static Vector<T> move(Vector<T>&& rhs) noexcept
+ {
+ return Vector<T>{std::move(rhs)};
+ }
FudStatus copy(const Vector<T>& rhs);
FudStatus take(Vector<T>&& rhs);
- [[nodiscard]] size_t size() const {
+ [[nodiscard]] size_t size() const
+ {
return m_length;
}
- [[nodiscard]] size_t capacity() const {
+ [[nodiscard]] size_t capacity() const
+ {
return m_capacity;
}
- FudStatus reserve();
+ Result<Span<const T>, FudStatus> span() const
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ return Span{m_data, m_length};
+ }
+
+ Result<Span<T>, FudStatus> span()
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ return Span{m_data, m_length};
+ }
+
+ Result<Span<const T>, FudStatus> span(size_t count) const
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (count > m_length) {
+ return FudStatus::ArgumentInvalid;
+ }
+ return Span{m_data, count};
+ }
+
+ Result<Span<T>, FudStatus> span(size_t count)
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (count > m_length) {
+ return FudStatus::ArgumentInvalid;
+ }
+ return Span{m_data, count};
+ }
+
+ Result<Span<const T>, FudStatus> span(size_t start, size_t count) const
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (SIZE_MAX - start < m_length || start + count > m_length) {
+ return FudStatus::ArgumentInvalid;
+ }
+ return Span{m_data + start, count};
+ }
+
+ Result<Span<T>, FudStatus> span(size_t start, size_t count)
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (SIZE_MAX - start < m_length || start + count > m_length) {
+ return FudStatus::ArgumentInvalid;
+ }
+ return Span{m_data + start, count};
+ }
+
+ FudStatus reserve(size_t count)
+ {
+ if (count <= m_capacity) {
+ return FudStatus::Success;
+ }
+
+ if (m_allocator == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+
+ if (count > SIZE_MAX / ElementSize) {
+ return FudStatus::ArgumentInvalid;
+ }
+
+ size_t requestedSize = count * ElementSize;
+ auto dataPtrResult = m_allocator->allocate(requestedSize, Alignment);
+ if (dataPtrResult.isError()) {
+ return dataPtrResult.takeError();
+ }
+
+ auto* dataPtr = static_cast<T*>(dataPtrResult.takeOkay());
+ for (size_t index = 0; index < m_length; ++index) {
+ const auto* ptr = new (dataPtr + index) T(std::move(m_data[index]));
+ fudAssert(ptr != nullptr);
+ m_data[index].~T();
+ }
+
+ m_data = dataPtr;
+ m_capacity = count;
+
+ return FudStatus::Success;
+ }
+
+ FudStatus resize(size_t count)
+ {
+ if (count == m_length) {
+ return FudStatus::Success;
+ }
+
+ if (m_allocator == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
- FudStatus resize();
+ if (count < m_length) {
+ for (size_t index = count; index < m_length; ++index) {
+ m_data[index].~T();
+ }
+ m_length = count;
+ return FudStatus::Success;
+ }
- FudStatus clear();
+ auto reserveStatus = reserve(count);
+ if (reserveStatus != FudStatus::Success) {
+ return reserveStatus;
+ }
- // FudResult at();
+ for (size_t index = m_length; index < count; ++index) {
+ const auto* ptr = new (m_data + index) T();
+ fudAssert(ptr != nullptr);
+ }
+
+ m_length = count;
+ return FudStatus::Success;
+ }
+
+ FudStatus clear()
+ {
+ if (m_allocator == nullptr || m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ for (size_t index = 0; index < m_length; ++index) {
+ m_data[index].~T();
+ }
+ m_length = 0;
+ return FudStatus::Success;
+ }
+
+ Result<std::reference_wrapper<T>, FudStatus> get(size_t index)
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (index >= m_length) {
+ return FudStatus::IndexInvalid;
+ }
+ return std::ref(m_data[index]);
+ }
+
+ Result<const std::reference_wrapper<const T>, FudStatus> ref(size_t index) const
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (index >= m_length) {
+ return FudStatus::IndexInvalid;
+ }
+ return std::cref(m_data[index]);
+ }
+
+ constexpr Option<T&> front()
+ {
+ if (m_length > 0) {
+ fudAssert(m_data != nullptr);
+ return m_data[0];
+ }
+ return NullOpt;
+ }
+
+ constexpr Option<const T&> front() const
+ {
+ if (m_length > 0) {
+ fudAssert(m_data != nullptr);
+ return m_data[0];
+ }
+ return NullOpt;
+ }
+
+ constexpr Option<T&> back()
+ {
+ if (m_length > 0) {
+ fudAssert(m_data != nullptr);
+ return m_data[m_length - 1];
+ }
+ return NullOpt;
+ }
+
+ constexpr Option<const T&> back() const
+ {
+ if (m_length > 0) {
+ return m_data[m_length - 1];
+ }
+ return NullOpt;
+ }
+
+ constexpr T* data() noexcept
+ {
+ return m_data;
+ }
+
+ constexpr const T* data() const noexcept
+ {
+ return m_data;
+ }
+
+ constexpr T* begin() noexcept
+ {
+ return m_data;
+ }
+
+ constexpr const T* begin() const noexcept
+ {
+ return m_data;
+ }
+
+ constexpr T* end() noexcept
+ {
+ return m_data + m_length;
+ }
+
+ constexpr const T* end() const noexcept
+ {
+ return m_data + m_length;
+ }
+
+ constexpr T& operator[](size_t index)
+ {
+ if constexpr (fudBoundsChecking) {
+ fudAssert(m_data != nullptr);
+ fudAssert(index < m_length);
+ }
+ return m_data[index];
+ }
+
+ constexpr const T& operator[](size_t index) const
+ {
+ if constexpr (fudBoundsChecking) {
+ fudAssert(m_data != nullptr);
+ fudAssert(index < m_length);
+ }
+ return m_data[index];
+ }
+
+ FudStatus pushBack(const T& value)
+ {
+ if (m_length == m_capacity) {
+ auto status = grow();
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ }
+ const auto* ptr = new (m_data + m_length) T(value);
+ fudAssert(ptr != nullptr);
+ m_length++;
+ return FudStatus::Success;
+ }
+
+ FudStatus pushBack(T&& value)
+ {
+ if (m_length == m_capacity) {
+ auto status = grow();
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ }
+ const auto* ptr = new (m_data + m_length) T(std::move(value));
+ fudAssert(ptr != nullptr);
+ m_length++;
+ return FudStatus::Success;
+ }
+
+ Result<T, FudStatus> popBack()
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (m_length == 0) {
+ return FudStatus::Empty;
+ }
+ auto result{std::move(m_data[m_length - 1])};
+ m_length--;
+ m_data[m_length].~T();
+ return result;
+ }
+
+ FudStatus eraseBack()
+ {
+ if (m_data == nullptr) {
+ return FudStatus::ObjectInvalid;
+ }
+ if (m_length == 0) {
+ return FudStatus::Empty;
+ }
+ m_length--;
+ m_data[m_length].~T();
+ return FudStatus::Success;
+ }
+
+ FudStatus insert(size_t index, const T& value)
+ {
+ if (index > m_length) {
+ return FudStatus::IndexInvalid;
+ }
+ if (index == m_length) {
+ return pushBack(value);
+ }
+ if (m_length == m_capacity) {
+ auto status = grow();
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ }
+
+ const auto* ptr = new (m_data + m_length) T(std::move(m_data[m_length - 1]));
+ fudAssert(ptr != nullptr);
+
+ for (size_t backIndex = m_length - 1; backIndex > index; --backIndex) {
+ m_data[backIndex] = std::move(m_data[backIndex - 1]);
+ }
+ m_data[index] = value;
+ m_length++;
+ return FudStatus::Success;
+ }
+
+ FudStatus insert(size_t index, T&& value)
+ {
+ if (index > m_length) {
+ return FudStatus::IndexInvalid;
+ }
+ if (index == m_length) {
+ return pushBack(std::move(value));
+ }
+ if (m_length == m_capacity) {
+ auto status = grow();
+ if (status != FudStatus::Success) {
+ return status;
+ }
+ }
+
+ const auto* ptr = new (m_data + m_length) T(std::move(m_data[m_length - 1]));
+ fudAssert(ptr != nullptr);
+
+ for (size_t backIndex = m_length - 1; backIndex > index; --backIndex) {
+ m_data[backIndex] = std::move(m_data[backIndex - 1]);
+ }
+ m_data[index] = std::move(value);
+ m_length++;
+ return FudStatus::Success;
+ }
+
+ FudStatus erase(size_t index)
+ {
+ if (index >= m_length) {
+ return FudStatus::IndexInvalid;
+ }
+
+ m_data[index].~T();
+ for (size_t fwdIndex = index; fwdIndex + 1 < m_length; fwdIndex++)
+ {
+ m_data[fwdIndex] = std::move(m_data[fwdIndex + 1]);
+ }
+ m_data[m_length - 1].~T();
+ m_length--;
+ return FudStatus::Success;
+ }
private:
+ FudStatus grow()
+ {
+ // See https://github.com/facebook/folly/blob/main/folly/docs/FBVector.md
+ size_t additional = m_capacity < 2 ? 1 : m_capacity / 2;
+ if (SIZE_MAX - additional * ElementSize < m_capacity * ElementSize) {
+ additional = SIZE_MAX - m_capacity * ElementSize / 2;
+ }
+ while (additional > 0) {
+ auto reserveStatus = reserve(additional + m_capacity);
+ if (reserveStatus == FudStatus::Success) {
+ break;
+ }
+ if (reserveStatus == FudStatus::AllocFailure) {
+ additional /= 2;
+ } else {
+ return reserveStatus;
+ }
+ }
+
+ if (m_length == m_capacity) {
+ return FudStatus::AllocFailure;
+ }
+
+ return FudStatus::Success;
+ }
+
+ FudStatus cleanup() noexcept
+ {
+ auto status = clear();
+
+ if (m_data != nullptr && m_allocator != nullptr) {
+ auto deallocStatus = m_allocator->deallocate(m_data, m_capacity);
+ if (status == FudStatus::Success) {
+ status = deallocStatus;
+ }
+ }
+
+ m_allocator = nullptr;
+ m_data = nullptr;
+ m_length = 0;
+ m_capacity = 0;
+ return status;
+ }
+
Allocator* m_allocator{&globalFudAllocator};
+ T* m_data{nullptr};
size_t m_length{0};
size_t m_capacity{0};
};
diff --git a/source/fud_string_view.cpp b/source/fud_string_view.cpp
index fdb63b3..1cc73a6 100644
--- a/source/fud_string_view.cpp
+++ b/source/fud_string_view.cpp
@@ -1066,7 +1066,7 @@ FudStatus stringViewToFloat(StringView input, T& number, size_t& index)
if (std::isinf(num) || std::isnan(num)) // isnan is dubious here - likely unreachable
{
- return ExtRangeError;
+ return FudStatus::RangeError;
}
return retSuccess();
diff --git a/source/libfud.cpp b/source/libfud.cpp
index 802b2c7..be43490 100644
--- a/source/libfud.cpp
+++ b/source/libfud.cpp
@@ -17,8 +17,7 @@
#include "libfud.hpp"
-#include "fud_assert.hpp"
-#include "fud_version.hpp"
+#include "fud_config.hpp"
#include <cstdlib>
@@ -27,12 +26,11 @@ namespace fud {
FUD fud()
{
FUD fudInfo{};
- static_assert(sizeof(GitHash) >= sizeof(fudInfo.revision));
+ static_assert(sizeof(FudGitHash) >= sizeof(fudInfo.revision));
fudInfo.major = FudVersionMajor;
fudInfo.minor = FudVersionMinor;
fudInfo.patch = FudVersionPatch;
- auto copyResult = copyMem(fudInfo.revision.data(), fudInfo.revision.size(), GitHash, fudInfo.revision.size() - 1);
- fudAssert(copyResult == FudStatus::Success);
+ copyMem<sizeof(fudInfo.revision) - 1>(fudInfo.revision, FudGitHash);
fudInfo.revision[fudInfo.revision.size() - 1] = '\0';
return fudInfo;
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index c4d957b..515ae16 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -62,11 +62,13 @@ fud_add_test(test_assert SOURCES test_assert.cpp)
# fud_add_test(test_c_file SOURCES test_c_file.cpp)
fud_add_test(test_directory SOURCES test_directory.cpp)
fud_add_test(test_format SOURCES test_format.cpp)
+fud_add_test(test_option SOURCES test_option.cpp)
fud_add_test(test_result SOURCES test_result.cpp)
fud_add_test(test_span SOURCES test_span.cpp)
fud_add_test(test_sqlite SOURCES test_sqlite.cpp)
fud_add_test(test_string SOURCES test_string.cpp)
fud_add_test(test_utf8 SOURCES test_utf8.cpp)
+fud_add_test(test_vector SOURCES test_vector.cpp)
# fud_add_test(test_deserialize_number SOURCES test_deserialize_number.cpp)
# fud_add_test(test_ext_algorithm SOURCES test_algorithm.cpp)
diff --git a/test/test_common.hpp b/test/test_common.hpp
index 0ca8eb4..f049fed 100644
--- a/test/test_common.hpp
+++ b/test/test_common.hpp
@@ -38,10 +38,16 @@ static_assert(sizeof(FOUR_BYTE) == 4 + 1);
#define LOWERCASE_CHARS "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DECIMAL_CHARS "0123456789"
+#define HEX_LOWER "abcdef"
+#define HEX_UPPER "ABCDEF"
+#define HEX_CHARS HEX_LOWER HEX_UPPER DECIMAL_CHARS
#define ALPHA_CHARS LOWERCASE_CHARS UPPERCASE_CHARS
#define ALPHA_NUMERIC_CHARS ALPHA_CHARS DECIMAL_CHARS
#define PUNCTUATION_CHARS "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
#define GRAPHICAL_CHARS ALPHA_NUMERIC_CHARS PUNCTUATION_CHARS
+#define BLANK_CHARS " \t"
+#define SPACE_CHARS BLANK_CHARS "\v\r\n"
+#define PRINTABLE_CHARS " " LOWERCASE_CHARS UPPERCASE_CHARS DECIMAL_CHARS PUNCTUATION_CHARS
#define CHARACTER_SET LOWERCASE_CHARS " " UPPERCASE_CHARS
// NOLINTEND(cppcoreguidelines-macro-usage)
diff --git a/test/test_fud.cpp b/test/test_fud.cpp
index 0778f98..72d569a 100644
--- a/test/test_fud.cpp
+++ b/test/test_fud.cpp
@@ -15,10 +15,11 @@
* limitations under the License.
*/
-#include "fud_version.hpp"
+#include "fud_config.hpp"
#include "libfud.hpp"
#include "gtest/gtest.h"
+#include <cstdlib>
namespace fud {
@@ -32,11 +33,33 @@ TEST(FudTest, FudFud)
auto compareResult = compareMem(
fudInfo.revision.data(),
fudInfo.revision.size(),
- GitHash,
+ FudGitHash,
fudInfo.revision.size() - 1);
ASSERT_TRUE(compareResult.isOkay());
EXPECT_EQ(compareResult.getOkay(), 0);
EXPECT_EQ(fudInfo.revision[fudInfo.revision.size() - 1], '\0');
}
+TEST(FudTest, GetEnv)
+{
+ constexpr const char* testVarName = "FUD_TEST_VAR";
+ constexpr const char* testVarValue = "FUD_TEST_VALUE";
+
+ ASSERT_EQ(unsetenv(testVarName), 0);
+
+ auto fudVarResult = getEnv(nullptr);
+ ASSERT_TRUE(fudVarResult.isError());
+ ASSERT_EQ(fudVarResult.getError(), FudStatus::NullPointer);
+
+ fudVarResult = getEnv(testVarName);
+ ASSERT_TRUE(fudVarResult.isError());
+ ASSERT_EQ(fudVarResult.getError(), FudStatus::NotFound);
+
+ ASSERT_EQ(setenv(testVarName, testVarValue, 1), 0);
+ fudVarResult = getEnv(testVarName);
+ ASSERT_TRUE(fudVarResult.isOkay());
+ auto fudVar{fudVarResult.takeOkay()};
+ ASSERT_STREQ(fudVar.c_str(), testVarValue);
+}
+
} // namespace fud
diff --git a/test/test_option.cpp b/test/test_option.cpp
new file mode 100644
index 0000000..a503a5f
--- /dev/null
+++ b/test/test_option.cpp
@@ -0,0 +1,54 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fud_option.hpp"
+
+#include "gtest/gtest.h"
+
+namespace fud {
+
+TEST(OptionTest, OptionCreation)
+{
+ static_assert(sizeof(std::reference_wrapper<int>) == 8);
+ int value = 42;
+ Option<int> maybeValue{};
+ ASSERT_FALSE(maybeValue.hasValue());
+ maybeValue = value;
+ ASSERT_TRUE(maybeValue.hasValue());
+}
+
+TEST(OptionTest, OptionRef)
+{
+ int value = 42;
+ Option<int&> optionalValueRef{value};
+ ASSERT_TRUE(optionalValueRef.hasValue());
+ ASSERT_EQ(optionalValueRef.value(), 42);
+ optionalValueRef.value() = 7;
+ ASSERT_EQ(value, 7);
+
+ value = 42;
+ int otherValue = 13;
+ optionalValueRef = otherValue;
+ ASSERT_TRUE(optionalValueRef.hasValue());
+ ASSERT_EQ(optionalValueRef.value(), otherValue);
+ optionalValueRef.value() = 7;
+ ASSERT_EQ(optionalValueRef.value(), otherValue);
+ ASSERT_EQ(otherValue, 7);
+ ASSERT_EQ(value, 42);
+}
+
+} // namespace fud
diff --git a/test/test_utf8.cpp b/test/test_utf8.cpp
index 8f1d655..d1737f7 100644
--- a/test/test_utf8.cpp
+++ b/test/test_utf8.cpp
@@ -38,10 +38,21 @@ constexpr char printableCharOffset = 0x20;
constexpr auto invalidAscii = FudUtf8::invalidAsciiCode.character();
-auto generateInvalidAsciiChars()
+auto invalidAsciiGenerator()
{
- Iota<utf8> iota{};
- return generate([]() { return Array<utf8, invalidAsciiSize>{}; }, [&]() { return iota().value(); });
+ return Iota<uint16_t>{validAsciiSize, 1, invalidAsciiSize};
+}
+
+template <typename T>
+auto toUtf8(T letter)
+{
+ return FudUtf8::make(static_cast<utf8>(letter));
+}
+
+template <typename T>
+auto toLetter(T letter)
+{
+ return static_cast<char>(letter);
}
TEST(Utf8Test, Utf8Creation)
@@ -187,123 +198,80 @@ TEST(Utf8Test, Utf8IsAscii)
Iota<int16_t> charIota{0, 1, validAsciiSize};
- ASSERT_TRUE(allOf(
- [&]() -> std::optional<char> {
- auto value = charIota();
- return value ? std::optional<char>(static_cast<char>(*value)) : std::nullopt;
- },
- charIsAscii));
+ ASSERT_TRUE(allOf([&]() -> Option<char> { return charIota().map(toLetter<int16_t>); }, charIsAscii));
Iota<int16_t> invalidCharIota{validAsciiSize, 1, invalidAsciiSize};
- ASSERT_FALSE(anyOf(
- [&]() -> std::optional<char> {
- auto value = invalidCharIota();
- return value ? std::optional<char>(static_cast<char>(*value)) : std::nullopt;
- },
- charIsAscii));
+ ASSERT_FALSE(anyOf([&]() -> Option<char> { return invalidCharIota().map(toLetter<int16_t>); }, charIsAscii));
FudUtf8 unicode{FudUtf8::invalidAscii()};
ASSERT_FALSE(utf8IsAscii(unicode));
charIota.set(0);
- ASSERT_TRUE(allOf(
- [&]() -> std::optional<FudUtf8> {
- auto value = charIota();
- return value ? std::optional<FudUtf8>(FudUtf8::make(static_cast<utf8>(*value))) : std::nullopt;
- },
- utf8IsAscii));
+ ASSERT_TRUE(allOf([&]() -> Option<FudUtf8> { return charIota().map(toUtf8<int16_t>); }, utf8IsAscii));
invalidCharIota.set(invalidAsciiSize);
- ASSERT_FALSE(anyOf(
- [&]() -> std::optional<FudUtf8> {
- auto value = invalidCharIota();
- return value ? std::optional<FudUtf8>(FudUtf8::make(static_cast<utf8>(*value))) : std::nullopt;
- },
- utf8IsAscii));
+ ASSERT_FALSE(anyOf([&]() -> Option<FudUtf8> { return invalidCharIota().map(toUtf8<int16_t>); }, utf8IsAscii));
}
-TEST(Utf8Test, Utf8IsAlphaNumeric)
+template <typename T, size_t Size = SIZE_MAX>
+struct SpanGenerator {
+ Span<T, Size> span;
+ size_t index{0};
+
+ void reset()
+ {
+ index = 0;
+ }
+
+ Option<T> operator()()
+ {
+ if (index < span.size()) {
+ index++;
+ return span[index - 1];
+ }
+ return NullOpt;
+ }
+};
+
+TEST(Utf8Test, Utf8IsAlphanumeric)
{
- constexpr size_t numAlphaNumericChars = 26 * 2 + 10;
- Array<char, numAlphaNumericChars + 1> alphaNumericCharLiteral{ALPHA_NUMERIC_CHARS};
- Array<char, numAlphaNumericChars> alphaNumericChars{};
- copyMem<numAlphaNumericChars>(alphaNumericChars, alphaNumericCharLiteral);
-#if 0
- ASSERT_TRUE(allOf(alphaNumericChars, charIsAlphanumeric));
-
- auto alphaNumericSetResult{StaticSet<char, numAlphaNumericChars>::makeFromArray(alphaNumericChars)};
- ASSERT_TRUE(alphaNumericSetResult.isOkay());
- auto alphaNumericSet{std::move(alphaNumericSetResult.getOkay())};
-
- constexpr size_t numNonAlphaNumericChars = validAsciiSize - numAlphaNumericChars;
- FixedVector<char, numNonAlphaNumericChars> nonAlphaNumericChars{};
+ constexpr size_t numAlphanumericChars = 26 * 2 + 10;
+ Array<char, numAlphanumericChars + 1> alphanumericCharLiteral{ALPHA_NUMERIC_CHARS};
+ Array<char, numAlphanumericChars> alphanumericChars{};
+ copyMem<numAlphanumericChars>(alphanumericChars, alphanumericCharLiteral);
+
+ ASSERT_TRUE(allOf(alphanumericChars.span(), charIsAlphanumeric));
+
+ constexpr size_t numNonAlphanumericChars = validAsciiSize - numAlphanumericChars;
+ Vector<char> nonAlphanumericChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!alphaNumericSet.isKey(idx)) {
- ASSERT_TRUE(nonAlphaNumericChars.pushBack(idx));
+ if (!charIsAlphanumeric(idx)) {
+ ASSERT_EQ(nonAlphanumericChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonAlphaNumericChars, charIsAlphanumeric));
+ auto nonAlphanumericSpan{nonAlphanumericChars.span().takeOkay()};
+ ASSERT_FALSE(anyOf(nonAlphanumericSpan, charIsAlphanumeric));
- auto invalidAsciiChars = generateInvalidAsciiChars();
+ auto invalidAsciiChars = invalidAsciiGenerator();
ASSERT_FALSE(anyOf(invalidAsciiChars, charIsAlphanumeric));
- ASSERT_TRUE(allOf(
- map(alphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
- ASSERT_FALSE(anyOf(
- map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
-
- ASSERT_TRUE(allOf(
- map(alphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
- ASSERT_FALSE(anyOf(
- map(nonAlphaNumericChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alphanumeric));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_alphanumeric(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alphanumeric(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alphanumeric(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alphanumeric(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(alphaNumericChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonAlphaNumericChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonAlphaNumericChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alphanumeric(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
-#endif
+ ASSERT_FALSE(utf8IsAlphanumeric(FudUtf8{Ascii{invalidAscii}}));
+
+ auto iotaGenerator = invalidAsciiGenerator();
+ auto generator = generate(
+ []() { return Array<utf8, invalidAsciiSize>{}; },
+ [&]() { return iotaGenerator().map([](auto val) { return static_cast<utf8>(val); }); });
+
+ SpanGenerator<char, alphanumericChars.size()> alphanumericGenerator{alphanumericChars.span()};
+ auto utf8AlphanumericGenerator = [&]() { return alphanumericGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8AlphanumericGenerator, utf8IsAlphanumeric));
+
+ SpanGenerator<char> nonAlphanumericGenerator{nonAlphanumericChars.span().takeOkay()};
+ auto utf8NonAlphanumericGenerator = [&]() { return nonAlphanumericGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonAlphanumericGenerator, utf8IsAlphanumeric));
}
-#if 0
TEST(Utf8Test, Utf8IsAlpha)
{
constexpr size_t numAlphaChars = sizeof(ALPHA_CHARS) - 1;
@@ -311,75 +279,29 @@ TEST(Utf8Test, Utf8IsAlpha)
Array<char, numAlphaChars> alphaChars{};
copyMem<numAlphaChars>(alphaChars, alphaCharLiteral);
- ASSERT_TRUE(allOf(alphaChars, ext_lib_char_is_alpha));
-
- auto alphaSetResult{StaticSet<char, numAlphaChars>::makeFromArray(alphaChars)};
- ASSERT_TRUE(alphaSetResult.isOkay());
- auto alphaSet{std::move(alphaSetResult.getOkay())};
+ ASSERT_TRUE(allOf(alphaChars.span(), charIsAlpha));
- constexpr size_t numNonAlphaChars = validAsciiSize - numAlphaChars;
- FixedVector<char, numNonAlphaChars> nonAlphaChars{};
+ constexpr size_t numNonAlphanumericChars = validAsciiSize - numAlphaChars;
+ Vector<char> nonAlphaChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!alphaSet.isKey(idx)) {
- ASSERT_TRUE(nonAlphaChars.pushBack(idx));
+ if (!charIsAlphanumeric(idx)) {
+ ASSERT_EQ(nonAlphaChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonAlphaChars, ext_lib_char_is_alpha));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_alpha));
-
- ASSERT_TRUE(allOf(
- map(alphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
- ASSERT_FALSE(anyOf(
- map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
-
- ASSERT_TRUE(allOf(
- map(alphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
- ASSERT_FALSE(anyOf(
- map(nonAlphaChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_alpha));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_alpha(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alpha(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alpha(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_alpha(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(alphaChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonAlphaChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonAlphaChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_alpha(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonAlphaChars.span().takeOkay(), charIsAlpha));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsAlpha));
+
+ ASSERT_FALSE(utf8IsAlpha(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, alphaChars.size()> alphaGenerator{alphaChars.span()};
+ auto utf8AlphaGenerator = [&]() { return alphaGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8AlphaGenerator, utf8IsAlpha));
+
+ SpanGenerator<char> nonAlphaGenerator{nonAlphaChars.span().takeOkay()};
+ auto utf8NonAlphaGenerator = [&]() { return nonAlphaGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonAlphaGenerator, utf8IsAlpha));
}
TEST(Utf8Test, Utf8IsLower)
@@ -389,75 +311,29 @@ TEST(Utf8Test, Utf8IsLower)
Array<char, numLowerChars> lowerChars{};
copyMem<numLowerChars>(lowerChars, lowerCharLiteral);
- ASSERT_TRUE(allOf(lowerChars, ext_lib_char_is_lowercase));
-
- auto lowerSetResult{StaticSet<char, numLowerChars>::makeFromArray(lowerChars)};
- ASSERT_TRUE(lowerSetResult.isOkay());
- auto lowerSet{std::move(lowerSetResult.getOkay())};
+ ASSERT_TRUE(allOf(lowerChars.span(), charIsLowercase));
constexpr size_t numNonLowerChars = validAsciiSize - numLowerChars;
- FixedVector<char, numNonLowerChars> nonLowerChars{};
+ Vector<char> nonLowerChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!lowerSet.isKey(idx)) {
- ASSERT_TRUE(nonLowerChars.pushBack(idx));
+ if (!charIsLowercase(idx)) {
+ ASSERT_EQ(nonLowerChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonLowerChars, ext_lib_char_is_lowercase));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_lowercase));
-
- ASSERT_TRUE(allOf(
- map(lowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
- ASSERT_FALSE(anyOf(
- map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
-
- ASSERT_TRUE(allOf(
- map(lowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
- ASSERT_FALSE(anyOf(
- map(nonLowerChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_lowercase));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_lowercase(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_lowercase(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_lowercase(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_lowercase(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(lowerChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonLowerChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonLowerChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_lowercase(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonLowerChars.span().takeOkay(), charIsLowercase));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsLowercase));
+
+ ASSERT_FALSE(utf8IsLowercase(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, lowerChars.size()> lowerGenerator{lowerChars.span()};
+ auto utf8LowerGenerator = [&]() { return lowerGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8LowerGenerator, utf8IsLowercase));
+
+ SpanGenerator<char> nonLowerGenerator{nonLowerChars.span().takeOkay()};
+ auto utf8NonLowerGenerator = [&]() { return nonLowerGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonLowerGenerator, utf8IsLowercase));
}
TEST(Utf8Test, Utf8IsUpper)
@@ -467,153 +343,61 @@ TEST(Utf8Test, Utf8IsUpper)
Array<char, numUpperChars> upperChars{};
copyMem<numUpperChars>(upperChars, upperCharLiteral);
- ASSERT_TRUE(allOf(upperChars, ext_lib_char_is_uppercase));
-
- auto upperSetResult{StaticSet<char, numUpperChars>::makeFromArray(upperChars)};
- ASSERT_TRUE(upperSetResult.isOkay());
- auto upperSet{std::move(upperSetResult.getOkay())};
+ ASSERT_TRUE(allOf(upperChars.span(), charIsUppercase));
constexpr size_t numNonUpperChars = validAsciiSize - numUpperChars;
- FixedVector<char, numNonUpperChars> nonUpperChars{};
+ Vector<char> nonUpperChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!upperSet.isKey(idx)) {
- ASSERT_TRUE(nonUpperChars.pushBack(idx));
+ if (!charIsUppercase(idx)) {
+ ASSERT_EQ(nonUpperChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonUpperChars, ext_lib_char_is_uppercase));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_uppercase));
-
- ASSERT_TRUE(allOf(
- map(upperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
- ASSERT_FALSE(anyOf(
- map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
-
- ASSERT_TRUE(allOf(
- map(upperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
- ASSERT_FALSE(anyOf(
- map(nonUpperChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_uppercase));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_uppercase(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_uppercase(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_uppercase(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_uppercase(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(upperChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonUpperChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonUpperChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_uppercase(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonUpperChars.span().takeOkay(), charIsUppercase));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsUppercase));
+
+ ASSERT_FALSE(utf8IsUppercase(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, upperChars.size()> upperGenerator{upperChars.span()};
+ auto utf8UpperGenerator = [&]() { return upperGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8UpperGenerator, utf8IsUppercase));
+
+ SpanGenerator<char> nonUpperGenerator{nonUpperChars.span().takeOkay()};
+ auto utf8NonUpperGenerator = [&]() { return nonUpperGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonUpperGenerator, utf8IsUppercase));
}
TEST(Utf8Test, Utf8IsDigit)
{
constexpr size_t numDigitChars = 10;
- Array<char, numDigitChars + 1> digitCharLiteral{"0123456789"};
+ Array<char, numDigitChars + 1> digitCharLiteral{DECIMAL_CHARS};
Array<char, numDigitChars> digitChars{};
copyMem<numDigitChars>(digitChars, digitCharLiteral);
- ASSERT_TRUE(allOf(digitChars, ext_lib_char_is_digit));
-
- auto digitSetResult{StaticSet<char, numDigitChars>::makeFromArray(digitChars)};
- ASSERT_TRUE(digitSetResult.isOkay());
- auto digitSet{std::move(digitSetResult.getOkay())};
+ ASSERT_TRUE(allOf(digitChars.span(), charIsDigit));
constexpr size_t numNonDigitChars = validAsciiSize - numDigitChars;
- FixedVector<char, numNonDigitChars> nonDigitChars{};
+ Vector<char> nonDigitChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!digitSet.isKey(idx)) {
- ASSERT_TRUE(nonDigitChars.pushBack(idx));
+ if (!charIsDigit(idx)) {
+ ASSERT_EQ(nonDigitChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonDigitChars, ext_lib_char_is_digit));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_digit));
-
- ASSERT_TRUE(allOf(
- map(digitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
- ASSERT_FALSE(anyOf(
- map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
-
- ASSERT_TRUE(allOf(
- map(digitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
- ASSERT_FALSE(anyOf(
- map(nonDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_digit));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_digit(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_digit(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_digit(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_digit(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(digitChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonDigitChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonDigitChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_digit(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonDigitChars.span().takeOkay(), charIsDigit));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsDigit));
+
+ ASSERT_FALSE(utf8IsDigit(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, digitChars.size()> digitGenerator{digitChars.span()};
+ auto utf8DigitGenerator = [&]() { return digitGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8DigitGenerator, utf8IsDigit));
+
+ SpanGenerator<char> nonDigitGenerator{nonDigitChars.span().takeOkay()};
+ auto utf8NonDigitGenerator = [&]() { return nonDigitGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonDigitGenerator, utf8IsDigit));
}
TEST(Utf8Test, Utf8IsHexDigit)
@@ -623,147 +407,61 @@ TEST(Utf8Test, Utf8IsHexDigit)
Array<char, numHexDigitChars> hexDigitChars{};
copyMem<numHexDigitChars>(hexDigitChars, hexDigitCharLiteral);
- ASSERT_TRUE(allOf(hexDigitChars, ext_lib_char_is_hex_digit));
-
- auto hexDigitSetResult{StaticSet<char, numHexDigitChars>::makeFromArray(hexDigitChars)};
- ASSERT_TRUE(hexDigitSetResult.isOkay());
- auto hexDigitSet{std::move(hexDigitSetResult.getOkay())};
+ ASSERT_TRUE(allOf(hexDigitChars.span(), charIsHexDigit));
constexpr size_t numNonHexDigitChars = validAsciiSize - numHexDigitChars;
- FixedVector<char, numNonHexDigitChars> nonHexDigitChars{};
+ Vector<char> nonHexDigitChars{};
for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!hexDigitSet.isKey(idx)) {
- ASSERT_TRUE(nonHexDigitChars.pushBack(idx));
+ if (!charIsHexDigit(idx)) {
+ ASSERT_EQ(nonHexDigitChars.pushBack(idx), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonHexDigitChars, ext_lib_char_is_hex_digit));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_hex_digit));
-
- ASSERT_TRUE(allOf(
- map(hexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
- ASSERT_FALSE(anyOf(
- map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
-
- ASSERT_TRUE(allOf(
- map(hexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
- ASSERT_FALSE(anyOf(
- map(nonHexDigitChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_hex_digit));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_hex_digit(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_hex_digit(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_hex_digit(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_hex_digit(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(hexDigitChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonHexDigitChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonHexDigitChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_hex_digit(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonHexDigitChars.span().takeOkay(), charIsHexDigit));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsHexDigit));
+
+ ASSERT_FALSE(utf8IsHexDigit(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, hexDigitChars.size()> hexDigitGenerator{hexDigitChars.span()};
+ auto utf8HexDigitGenerator = [&]() { return hexDigitGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8HexDigitGenerator, utf8IsHexDigit));
+
+ SpanGenerator<char> nonHexDigitGenerator{nonHexDigitChars.span().takeOkay()};
+ auto utf8NonHexDigitGenerator = [&]() { return nonHexDigitGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonHexDigitGenerator, utf8IsHexDigit));
}
TEST(Utf8Test, Utf8IsControl)
{
- auto controlChars = generateIndexArray<Array, char, numControlChars>([](int idx) { return static_cast<char>(idx); });
+ Iota<char> controlArrayGenerator{0, 1, numControlChars};
+ auto controlChars = generate([]() { return Array<char, numControlChars>{}; }, controlArrayGenerator);
constexpr const char deleteChar = 0x7F;
controlChars.back() = deleteChar;
- ASSERT_TRUE(allOf(controlChars, ext_lib_char_is_control));
-
- constexpr size_t numNonControlChars = 256 - numControlChars;
- auto nonControlChars = generateIndexArray<Array, char, numControlChars>([](int idx) {
- return static_cast<char>(idx + printableCharOffset);
- });
- ASSERT_FALSE(anyOf(nonControlChars, ext_lib_char_is_control));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_control));
-
- ASSERT_TRUE(allOf(
- map(controlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
- ASSERT_FALSE(anyOf(
- map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
-
- ASSERT_TRUE(allOf(
- map(controlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
- ASSERT_FALSE(anyOf(
- map(nonControlChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_control));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_control(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_control(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_control(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_control(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(controlChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonControlChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonControlChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_control(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_TRUE(allOf(controlChars.span(), charIsControl));
+
+ constexpr size_t numNonControlChars = INT8_MAX + 1 - numControlChars;
+ Vector<char> nonControlChars{};
+ ASSERT_EQ(nonControlChars.reserve(numNonControlChars), FudStatus::Success);
+ for (auto idx = numControlChars - 1; idx < deleteChar; ++idx) {
+ ASSERT_EQ(nonControlChars.pushBack(idx), FudStatus::Success);
+ }
+ ASSERT_FALSE(anyOf(nonControlChars.span().takeOkay(), charIsControl));
+ ASSERT_TRUE(allOf(nonControlChars.span().takeOkay(), charIsAscii));
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsControl));
+
+ ASSERT_FALSE(utf8IsControl(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, controlChars.size()> controlGenerator{controlChars.span()};
+ auto utf8ControlGenerator = [&]() { return controlGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8ControlGenerator, utf8IsControl));
+
+ SpanGenerator<char> nonControlGenerator{nonControlChars.span().takeOkay()};
+ auto utf8NonControlGenerator = [&]() { return nonControlGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonControlGenerator, utf8IsControl));
}
TEST(Utf8Test, Utf8IsGraphical)
@@ -773,311 +471,137 @@ TEST(Utf8Test, Utf8IsGraphical)
Array<char, numGraphicalChars> graphicalChars{};
copyMem<numGraphicalChars>(graphicalChars, graphicalCharLiteral);
- ASSERT_TRUE(allOf(graphicalChars, ext_lib_char_is_graphical));
-
- auto graphicalSetResult{StaticSet<char, numGraphicalChars>::makeFromArray(graphicalChars)};
- ASSERT_TRUE(graphicalSetResult.isOkay());
- auto graphicalSet{std::move(graphicalSetResult.getOkay())};
+ ASSERT_TRUE(allOf(graphicalChars.span(), charIsGraphical));
constexpr size_t numNonGraphicalChars = validAsciiSize - numGraphicalChars;
- FixedVector<char, numNonGraphicalChars> nonGraphicalChars{};
- for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!graphicalSet.isKey(idx)) {
- ASSERT_TRUE(nonGraphicalChars.pushBack(idx));
+ Vector<char> nonGraphicalChars{};
+ ASSERT_EQ(nonGraphicalChars.reserve(numNonGraphicalChars), FudStatus::Success);
+ for (uint8_t idx = 0; idx < INT8_MAX + 1; ++idx) {
+ if (!charIsGraphical(static_cast<char>(idx))) {
+ ASSERT_EQ(nonGraphicalChars.pushBack(static_cast<char>(idx)), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonGraphicalChars, ext_lib_char_is_graphical));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_graphical));
-
- ASSERT_TRUE(allOf(
- map(graphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
- ASSERT_FALSE(anyOf(
- map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
-
- ASSERT_TRUE(allOf(
- map(graphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
- ASSERT_FALSE(anyOf(
- map(nonGraphicalChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_graphical));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_graphical(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_graphical(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_graphical(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_graphical(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(graphicalChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonGraphicalChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonGraphicalChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_graphical(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonGraphicalChars.span().takeOkay(), charIsGraphical));
+ ASSERT_TRUE(allOf(nonGraphicalChars.span().takeOkay(), charIsAscii));
+ ASSERT_EQ(nonGraphicalChars.size() + graphicalChars.size(), INT8_MAX + 1);
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsGraphical));
+
+ ASSERT_FALSE(utf8IsGraphical(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, graphicalChars.size()> graphicalGenerator{graphicalChars.span()};
+ auto utf8GraphicalGenerator = [&]() { return graphicalGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8GraphicalGenerator, utf8IsGraphical));
+
+ SpanGenerator<char> nonGraphicalGenerator{nonGraphicalChars.span().takeOkay()};
+ auto utf8NonGraphicalGenerator = [&]() { return nonGraphicalGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonGraphicalGenerator, utf8IsGraphical));
}
TEST(Utf8Test, Utf8IsSpace)
{
- constexpr size_t numSpaceChars = sizeof(" \t\v\r\n") - 1;
- Array<char, numSpaceChars + 1> spaceCharLiteral{" \t\v\r\n"};
+ constexpr size_t numSpaceChars = sizeof(SPACE_CHARS) - 1;
+ Array<char, numSpaceChars + 1> spaceCharLiteral{SPACE_CHARS};
Array<char, numSpaceChars> spaceChars{};
copyMem<numSpaceChars>(spaceChars, spaceCharLiteral);
- ASSERT_TRUE(allOf(spaceChars, ext_lib_char_is_space));
-
- auto spaceSetResult{StaticSet<char, numSpaceChars>::makeFromArray(spaceChars)};
- ASSERT_TRUE(spaceSetResult.isOkay());
- auto spaceSet{std::move(spaceSetResult.getOkay())};
+ ASSERT_TRUE(allOf(spaceChars.span(), charIsSpace));
constexpr size_t numNonSpaceChars = validAsciiSize - numSpaceChars;
- FixedVector<char, numNonSpaceChars> nonSpaceChars{};
- for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!spaceSet.isKey(idx)) {
- ASSERT_TRUE(nonSpaceChars.pushBack(idx));
+ Vector<char> nonSpaceChars{};
+ ASSERT_EQ(nonSpaceChars.reserve(numNonSpaceChars), FudStatus::Success);
+ for (uint8_t idx = 0; idx < INT8_MAX + 1; ++idx) {
+ if (!charIsSpace(static_cast<char>(idx))) {
+ ASSERT_EQ(nonSpaceChars.pushBack(static_cast<char>(idx)), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonSpaceChars, ext_lib_char_is_space));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_space));
-
- ASSERT_TRUE(allOf(
- map(spaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
- ASSERT_FALSE(anyOf(
- map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
-
- ASSERT_TRUE(allOf(
- map(spaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
- ASSERT_FALSE(anyOf(
- map(nonSpaceChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_space));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_space(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_space(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_space(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_space(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(spaceChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonSpaceChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonSpaceChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_space(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonSpaceChars.span().takeOkay(), charIsSpace));
+ ASSERT_TRUE(allOf(nonSpaceChars.span().takeOkay(), charIsAscii));
+ ASSERT_EQ(nonSpaceChars.size() + spaceChars.size(), INT8_MAX + 1);
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsSpace));
+
+ ASSERT_FALSE(utf8IsSpace(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, spaceChars.size()> spaceGenerator{spaceChars.span()};
+ auto utf8SpaceGenerator = [&]() { return spaceGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8SpaceGenerator, utf8IsSpace));
+
+ SpanGenerator<char> nonSpaceGenerator{nonSpaceChars.span().takeOkay()};
+ auto utf8NonSpaceGenerator = [&]() { return nonSpaceGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonSpaceGenerator, utf8IsSpace));
}
TEST(Utf8Test, Utf8IsBlank)
{
- constexpr size_t numBlankChars = sizeof(" \t") - 1;
- Array<char, numBlankChars + 1> blankCharLiteral{" \t"};
+ constexpr size_t numBlankChars = sizeof(BLANK_CHARS) - 1;
+ Array<char, numBlankChars + 1> blankCharLiteral{BLANK_CHARS};
Array<char, numBlankChars> blankChars{};
copyMem<numBlankChars>(blankChars, blankCharLiteral);
- ASSERT_TRUE(allOf(blankChars, ext_lib_char_is_blank));
-
- auto blankSetResult{StaticSet<char, numBlankChars>::makeFromArray(blankChars)};
- ASSERT_TRUE(blankSetResult.isOkay());
- auto blankSet{std::move(blankSetResult.getOkay())};
+ ASSERT_TRUE(allOf(blankChars.span(), charIsBlank));
constexpr size_t numNonBlankChars = validAsciiSize - numBlankChars;
- FixedVector<char, numNonBlankChars> nonBlankChars{};
- for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!blankSet.isKey(idx)) {
- ASSERT_TRUE(nonBlankChars.pushBack(idx));
+ Vector<char> nonBlankChars{};
+ ASSERT_EQ(nonBlankChars.reserve(numNonBlankChars), FudStatus::Success);
+ for (uint8_t idx = 0; idx < INT8_MAX + 1; ++idx) {
+ if (!charIsBlank(static_cast<char>(idx))) {
+ ASSERT_EQ(nonBlankChars.pushBack(static_cast<char>(idx)), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonBlankChars, ext_lib_char_is_blank));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_blank));
-
- ASSERT_TRUE(allOf(
- map(blankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
- ASSERT_FALSE(anyOf(
- map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
-
- ASSERT_TRUE(allOf(
- map(blankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
- ASSERT_FALSE(anyOf(
- map(nonBlankChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_blank));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_blank(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_blank(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_blank(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_blank(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(blankChars, [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonBlankChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonBlankChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_blank(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonBlankChars.span().takeOkay(), charIsBlank));
+ ASSERT_TRUE(allOf(nonBlankChars.span().takeOkay(), charIsAscii));
+ ASSERT_EQ(nonBlankChars.size() + blankChars.size(), INT8_MAX + 1);
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsBlank));
+
+ ASSERT_FALSE(utf8IsBlank(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, blankChars.size()> blankGenerator{blankChars.span()};
+ auto utf8BlankGenerator = [&]() { return blankGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8BlankGenerator, utf8IsBlank));
+
+ SpanGenerator<char> nonBlankGenerator{nonBlankChars.span().takeOkay()};
+ auto utf8NonBlankGenerator = [&]() { return nonBlankGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonBlankGenerator, utf8IsBlank));
}
TEST(Utf8Test, Utf8IsPrintable)
{
- constexpr size_t numPrintableChars = validAsciiSize - numControlChars;
- auto printableChars = generateIndexArray<Array, char, numPrintableChars>([](int idx) {
- return static_cast<char>(idx + printableCharOffset);
- });
-
- ASSERT_TRUE(allOf(printableChars, ext_lib_char_is_printable));
+ constexpr size_t numPrintableChars = sizeof(PRINTABLE_CHARS) - 1;
+ Array<char, numPrintableChars + 1> printableCharLiteral{PRINTABLE_CHARS};
+ Array<char, numPrintableChars> printableChars{};
+ copyMem<numPrintableChars>(printableChars, printableCharLiteral);
- auto printableSetResult{StaticSet<char, numPrintableChars>::makeFromArray(printableChars)};
- ASSERT_TRUE(printableSetResult.isOkay());
- auto printableSet{std::move(printableSetResult.getOkay())};
+ ASSERT_TRUE(allOf(printableChars.span(), charIsPrintable));
constexpr size_t numNonPrintableChars = validAsciiSize - numPrintableChars;
- FixedVector<char, numNonPrintableChars> nonPrintableChars{};
- for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!printableSet.isKey(idx)) {
- ASSERT_TRUE(nonPrintableChars.pushBack(idx));
+ Vector<char> nonPrintableChars{};
+ ASSERT_EQ(nonPrintableChars.reserve(numNonPrintableChars), FudStatus::Success);
+ for (uint8_t idx = 0; idx < INT8_MAX + 1; ++idx) {
+ if (!charIsPrintable(static_cast<char>(idx))) {
+ ASSERT_EQ(nonPrintableChars.pushBack(static_cast<char>(idx)), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonPrintableChars, ext_lib_char_is_printable));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_printable));
-
- ASSERT_TRUE(allOf(
- map(printableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
- ASSERT_FALSE(anyOf(
- map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
-
- ASSERT_TRUE(allOf(
- map(printableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
- ASSERT_FALSE(anyOf(
- map(nonPrintableChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_printable));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_printable(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_printable(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_printable(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_printable(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(printableChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonPrintableChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonPrintableChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_printable(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonPrintableChars.span().takeOkay(), charIsPrintable));
+ ASSERT_TRUE(allOf(nonPrintableChars.span().takeOkay(), charIsAscii));
+ ASSERT_EQ(nonPrintableChars.size() + printableChars.size(), INT8_MAX + 1);
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsPrintable));
+
+ ASSERT_FALSE(utf8IsPrintable(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, printableChars.size()> printableGenerator{printableChars.span()};
+ auto utf8PrintableGenerator = [&]() { return printableGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8PrintableGenerator, utf8IsPrintable));
+
+ SpanGenerator<char> nonPrintableGenerator{nonPrintableChars.span().takeOkay()};
+ auto utf8NonPrintableGenerator = [&]() { return nonPrintableGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonPrintableGenerator, utf8IsPrintable));
}
TEST(Utf8Test, Utf8IsPunctuation)
@@ -1087,77 +611,32 @@ TEST(Utf8Test, Utf8IsPunctuation)
Array<char, numPunctuationChars> punctuationChars{};
copyMem<numPunctuationChars>(punctuationChars, punctuationCharLiteral);
- ASSERT_TRUE(allOf(punctuationChars, ext_lib_char_is_punctuation));
-
- auto punctuationSetResult{StaticSet<char, numPunctuationChars>::makeFromArray(punctuationChars)};
- ASSERT_TRUE(punctuationSetResult.isOkay());
- auto punctuationSet{std::move(punctuationSetResult.getOkay())};
+ ASSERT_TRUE(allOf(punctuationChars.span(), charIsPunctuation));
constexpr size_t numNonPunctuationChars = validAsciiSize - numPunctuationChars;
- FixedVector<char, numNonPunctuationChars> nonPunctuationChars{};
- for (char idx = 0; idx < INT8_MAX; ++idx) {
- if (!punctuationSet.isKey(idx)) {
- ASSERT_TRUE(nonPunctuationChars.pushBack(idx));
+ Vector<char> nonPunctuationChars{};
+ ASSERT_EQ(nonPunctuationChars.reserve(numNonPunctuationChars), FudStatus::Success);
+ for (uint8_t idx = 0; idx < INT8_MAX + 1; ++idx) {
+ if (!charIsPunctuation(static_cast<char>(idx))) {
+ ASSERT_EQ(nonPunctuationChars.pushBack(static_cast<char>(idx)), FudStatus::Success);
}
}
- ASSERT_FALSE(anyOf(nonPunctuationChars, ext_lib_char_is_punctuation));
-
- auto invalidAsciiChars = generateInvalidAsciiChars();
- ASSERT_FALSE(anyOf(invalidAsciiChars, ext_lib_char_is_punctuation));
-
- ASSERT_TRUE(allOf(
- map(punctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
- ASSERT_FALSE(anyOf(
- map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
-
- ASSERT_TRUE(allOf(
- map(punctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
- ASSERT_FALSE(anyOf(
- map(nonPunctuationChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
- ASSERT_FALSE(anyOf(
- map(invalidAsciiChars, [](auto input) { return ExtUtf8Char4{static_cast<utf8>(input)}; }),
- ext_lib_char4_is_punctuation));
-
- Utf8 utf8{invalidAscii};
- bool isAscii = false;
- ASSERT_EQ(ext_lib_utf8_is_punctuation(nullptr, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_punctuation(&utf8, nullptr), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_punctuation(nullptr, &isAscii), ExtNullPointer);
- ASSERT_EQ(ext_lib_utf8_is_punctuation(&utf8, &isAscii), ExtInvalidInput);
- ASSERT_FALSE(isAscii);
-
- ASSERT_TRUE(allOf(
- map(punctuationChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate);
- return isPredicateStatus == ExtSuccess && predicate;
- }));
- ASSERT_FALSE(anyOf(
- map(nonPunctuationChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate);
- return isPredicateStatus != ExtSuccess || predicate;
- }));
- ASSERT_FALSE(allOf(
- map(nonPunctuationChars,
- [](char letter) { return FudUtf8::makeUtf8(ExtUtf8Char4{static_cast<utf8>(letter)}); }),
- [](auto& utf8Letter) {
- bool predicate = false;
- auto isPredicateStatus = ext_lib_utf8_is_punctuation(&utf8Letter, &predicate);
- return isPredicateStatus == ExtInvalidInput && !predicate;
- }));
+ ASSERT_FALSE(anyOf(nonPunctuationChars.span().takeOkay(), charIsPunctuation));
+ ASSERT_TRUE(allOf(nonPunctuationChars.span().takeOkay(), charIsAscii));
+ ASSERT_EQ(nonPunctuationChars.size() + punctuationChars.size(), INT8_MAX + 1);
+
+ auto invalidAsciiChars = invalidAsciiGenerator();
+ ASSERT_FALSE(anyOf(invalidAsciiChars, charIsPunctuation));
+
+ ASSERT_FALSE(utf8IsPunctuation(FudUtf8{Ascii{invalidAscii}}));
+
+ SpanGenerator<char, punctuationChars.size()> punctuationGenerator{punctuationChars.span()};
+ auto utf8PunctuationGenerator = [&]() { return punctuationGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_TRUE(allOf(utf8PunctuationGenerator, utf8IsPunctuation));
+
+ SpanGenerator<char> nonPunctuationGenerator{nonPunctuationChars.span().takeOkay()};
+ auto utf8NonPunctuationGenerator = [&]() { return nonPunctuationGenerator().map(toUtf8<uint16_t>); };
+ ASSERT_FALSE(anyOf(utf8NonPunctuationGenerator, utf8IsPunctuation));
}
-#endif
} // namespace fud
diff --git a/test/test_vector.cpp b/test/test_vector.cpp
new file mode 100644
index 0000000..b4fd83c
--- /dev/null
+++ b/test/test_vector.cpp
@@ -0,0 +1,138 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fud_vector.hpp"
+
+#include "gtest/gtest.h"
+
+namespace fud {
+
+TEST(VectorTest, TrivialVector)
+{
+ Vector<int> intVector{};
+ ASSERT_EQ(intVector.size(), 0);
+ ASSERT_EQ(intVector.capacity(), 0);
+ ASSERT_TRUE(intVector.ref(0).isError());
+
+ ASSERT_EQ(intVector.resize(10), FudStatus::Success);
+ ASSERT_EQ(intVector.size(), 10);
+ ASSERT_EQ(intVector.capacity(), 10);
+
+ ASSERT_TRUE(intVector.ref(0).isOkay());
+ ASSERT_EQ(intVector.ref(0).getOkay(), 0);
+ intVector.get(0).takeOkay().get() = 10;
+ ASSERT_EQ(intVector.ref(0).getOkay(), 10);
+}
+
+struct NonTrivial {
+ static thread_local int counter;
+ NonTrivial()
+ {
+ counter++;
+ }
+ explicit NonTrivial(int val) : value{val}
+ {
+ counter++;
+ }
+ NonTrivial(const NonTrivial&) = delete;
+ NonTrivial(NonTrivial&& rhs) : value{rhs.value}, destroyed{rhs.destroyed}
+ {
+ rhs.destroyed = true;
+ }
+ ~NonTrivial()
+ {
+ if (!destroyed) {
+ counter--;
+ destroyed = true;
+ }
+ }
+ NonTrivial& operator=(const NonTrivial& rhs) = delete;
+ NonTrivial& operator=(NonTrivial&& rhs) {
+ value = rhs.value;
+ destroyed = rhs.destroyed;
+ rhs.destroyed = true;
+ return *this;
+ }
+ int value{0};
+ bool destroyed{false};
+};
+
+int thread_local NonTrivial::counter = 0;
+
+TEST(VectorTest, NonTrivialVector)
+{
+ auto& counter = NonTrivial::counter;
+ counter = 0;
+ Vector<NonTrivial> nonTrivialVector{};
+ ASSERT_EQ(nonTrivialVector.size(), 0);
+ ASSERT_EQ(nonTrivialVector.capacity(), 0);
+ ASSERT_TRUE(nonTrivialVector.ref(0).isError());
+ ASSERT_EQ(counter, 0);
+
+ ASSERT_EQ(nonTrivialVector.resize(10), FudStatus::Success);
+ ASSERT_EQ(nonTrivialVector.size(), 10);
+ ASSERT_EQ(nonTrivialVector.capacity(), 10);
+ ASSERT_EQ(counter, 10);
+
+ ASSERT_TRUE(nonTrivialVector.ref(0).isOkay());
+ ASSERT_EQ(nonTrivialVector.ref(0).getOkay().get().value, 0);
+ nonTrivialVector.get(0).takeOkay().get().value = 10;
+ ASSERT_EQ(nonTrivialVector.ref(0).getOkay().get().value, 10);
+
+ ASSERT_EQ(nonTrivialVector.pushBack(NonTrivial{42}), FudStatus::Success);
+ ASSERT_EQ(nonTrivialVector.size(), 11);
+ ASSERT_GE(nonTrivialVector.capacity(), 11);
+ ASSERT_EQ(counter, 11);
+ auto capacity = nonTrivialVector.capacity();
+ ASSERT_EQ(nonTrivialVector.reserve(SIZE_MAX / sizeof(NonTrivial)), FudStatus::AllocFailure);
+ ASSERT_EQ(nonTrivialVector.capacity(), capacity);
+
+ {
+ auto popResult{nonTrivialVector.popBack()};
+ ASSERT_TRUE(popResult.isOkay());
+ auto value{popResult.takeOkay()};
+ ASSERT_EQ(value.value, 42);
+ ASSERT_EQ(counter, 11);
+ }
+ ASSERT_EQ(counter, 10);
+ ASSERT_EQ(nonTrivialVector.eraseBack(), FudStatus::Success);
+ ASSERT_EQ(counter, 9);
+
+ int val = 1;
+ for (auto& element: nonTrivialVector) {
+ element.value = val;
+ val++;
+ }
+ ASSERT_EQ(nonTrivialVector.insert(3, NonTrivial{13}), FudStatus::Success);
+ for (size_t idx = 0; idx < 3; ++idx) {
+ ASSERT_EQ(nonTrivialVector[idx].value, idx + 1);
+ }
+ ASSERT_EQ(counter, 10);
+ ASSERT_EQ(nonTrivialVector[3].value, 13);
+ for (size_t idx = 4; idx < nonTrivialVector.size(); ++idx) {
+ ASSERT_EQ(nonTrivialVector[idx].value, idx);
+ }
+ ASSERT_EQ(counter, nonTrivialVector.size());
+
+ ASSERT_EQ(nonTrivialVector.erase(3), FudStatus::Success);
+ for (size_t idx = 0; idx < nonTrivialVector.size(); ++idx) {
+ EXPECT_EQ(nonTrivialVector[idx].value, idx + 1);
+ }
+ ASSERT_EQ(counter, nonTrivialVector.size());
+}
+
+} // namespace fud