aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-14 19:30:03 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-14 19:30:03 +0200
commitd6735726d9cc6e98142e94001250076592279d36 (patch)
tree95d308a027495790af57479cacb064badea334d0 /libs/kstd
parentcdb8a0928ddfe626a1ac0acd1ae63bc8e5b77355 (diff)
parent9558074af8ceef4dc2c3b168a0263775f8a377e0 (diff)
downloadkernel-d6735726d9cc6e98142e94001250076592279d36.tar.xz
kernel-d6735726d9cc6e98142e94001250076592279d36.zip
Merge branch 'fmorgner/develop/kstd-system-error' into 'develop'
kstd: implement system_error infrastructure See merge request teachos/kernel!54
Diffstat (limited to 'libs/kstd')
-rw-r--r--libs/kstd/CMakeLists.txt30
-rw-r--r--libs/kstd/kstd/allocator.hpp (renamed from libs/kstd/kstd/allocator)0
-rw-r--r--libs/kstd/kstd/asm_ptr.hpp (renamed from libs/kstd/kstd/asm_ptr)0
-rw-r--r--libs/kstd/kstd/bits/basic_string.hpp4
-rw-r--r--libs/kstd/kstd/bits/format/arg.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/args.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/context.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/formatter.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/formatter/cstring.hpp6
-rw-r--r--libs/kstd/kstd/bits/format/output_buffer.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/parse_context.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/string.hpp2
-rw-r--r--libs/kstd/kstd/bits/format/vformat.cpp24
-rw-r--r--libs/kstd/kstd/bits/format/vformat.hpp46
-rw-r--r--libs/kstd/kstd/bits/observer_ptr.hpp2
-rw-r--r--libs/kstd/kstd/bits/observer_ptr.tests.cpp (renamed from libs/kstd/kstd/bits/observer_ptr.test.cpp)2
-rw-r--r--libs/kstd/kstd/bits/print_sink.hpp2
-rw-r--r--libs/kstd/kstd/bits/shared_ptr.hpp2
-rw-r--r--libs/kstd/kstd/bits/unique_ptr.hpp2
-rw-r--r--libs/kstd/kstd/cstring.hpp (renamed from libs/kstd/kstd/cstring)0
-rw-r--r--libs/kstd/kstd/ext/bitfield_enum.hpp (renamed from libs/kstd/kstd/ext/bitfield_enum)0
-rw-r--r--libs/kstd/kstd/flat_map.hpp (renamed from libs/kstd/kstd/flat_map)2
-rw-r--r--libs/kstd/kstd/flat_map.tests.cpp (renamed from libs/kstd/kstd/flat_map.test.cpp)2
-rw-r--r--libs/kstd/kstd/format.hpp (renamed from libs/kstd/kstd/format)1
-rw-r--r--libs/kstd/kstd/format.tests.cpp (renamed from libs/kstd/kstd/format.test.cpp)92
-rw-r--r--libs/kstd/kstd/libc/string.cpp2
-rw-r--r--libs/kstd/kstd/memory.hpp (renamed from libs/kstd/kstd/memory)0
-rw-r--r--libs/kstd/kstd/mutex.cpp2
-rw-r--r--libs/kstd/kstd/mutex.hpp (renamed from libs/kstd/kstd/mutex)0
-rw-r--r--libs/kstd/kstd/posix.hpp85
-rw-r--r--libs/kstd/kstd/print.hpp (renamed from libs/kstd/kstd/print)4
-rw-r--r--libs/kstd/kstd/ranges.hpp (renamed from libs/kstd/kstd/ranges)0
-rw-r--r--libs/kstd/kstd/result.hpp35
-rw-r--r--libs/kstd/kstd/stack.hpp (renamed from libs/kstd/kstd/stack)2
-rw-r--r--libs/kstd/kstd/string.hpp (renamed from libs/kstd/kstd/string)4
-rw-r--r--libs/kstd/kstd/string.tests.cpp (renamed from libs/kstd/kstd/string.test.cpp)4
-rw-r--r--libs/kstd/kstd/system_error.hpp636
-rw-r--r--libs/kstd/kstd/system_error.tests.cpp100
-rw-r--r--libs/kstd/kstd/test_support/os_panic.tests.cpp (renamed from libs/kstd/kstd/test_support/os_panic.test.cpp)0
-rw-r--r--libs/kstd/kstd/unikstd.h12
-rw-r--r--libs/kstd/kstd/units.hpp (renamed from libs/kstd/kstd/units)0
-rw-r--r--libs/kstd/kstd/vector.hpp (renamed from libs/kstd/kstd/vector)8
-rw-r--r--libs/kstd/kstd/vector.tests.cpp (renamed from libs/kstd/kstd/vector.test.cpp)4
43 files changed, 1053 insertions, 76 deletions
diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt
index 002fb548..9c68feed 100644
--- a/libs/kstd/CMakeLists.txt
+++ b/libs/kstd/CMakeLists.txt
@@ -69,38 +69,12 @@ endif()
if(BUILD_TESTING)
find_package("Catch2")
include("Catch")
+ include("BuildHostTests")
- add_executable("kstd_tests")
- add_executable("kstd::tests" ALIAS "kstd_tests")
-
- target_sources("kstd_tests" PRIVATE
- "kstd/flat_map.test.cpp"
- "kstd/format.test.cpp"
- "kstd/vector.test.cpp"
- "kstd/bits/observer_ptr.test.cpp"
- "kstd/test_support/os_panic.test.cpp"
- "kstd/string.test.cpp"
- )
-
- target_link_libraries("kstd_tests" PRIVATE
- "Catch2::Catch2WithMain"
- "kstd::lib"
- )
-
- set_target_properties("kstd_tests" PROPERTIES
- EXCLUDE_FROM_ALL NO
- )
+ teachos_add_tests("kstd")
if(COMMAND "enable_coverage")
enable_coverage("kstd")
enable_coverage("kstd_tests")
endif()
-
- file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bht_results")
-
- catch_discover_tests("kstd::tests"
- REPORTER junit
- OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bht_results"
- OUTPUT_SUFFIX ".xml"
- )
endif() \ No newline at end of file
diff --git a/libs/kstd/kstd/allocator b/libs/kstd/kstd/allocator.hpp
index 0de0e10d..0de0e10d 100644
--- a/libs/kstd/kstd/allocator
+++ b/libs/kstd/kstd/allocator.hpp
diff --git a/libs/kstd/kstd/asm_ptr b/libs/kstd/kstd/asm_ptr.hpp
index c06a8b52..c06a8b52 100644
--- a/libs/kstd/kstd/asm_ptr
+++ b/libs/kstd/kstd/asm_ptr.hpp
diff --git a/libs/kstd/kstd/bits/basic_string.hpp b/libs/kstd/kstd/bits/basic_string.hpp
index 1675434c..a718bccc 100644
--- a/libs/kstd/kstd/bits/basic_string.hpp
+++ b/libs/kstd/kstd/bits/basic_string.hpp
@@ -1,10 +1,10 @@
#ifndef KSTD_BITS_BASIC_STRING_HPP
#define KSTD_BITS_BASIC_STRING_HPP
-#include <kstd/allocator>
+#include <kstd/allocator.hpp>
#include <kstd/bits/concepts.hpp>
#include <kstd/os/error.hpp>
-#include <kstd/ranges>
+#include <kstd/ranges.hpp>
#include <algorithm>
#include <array>
diff --git a/libs/kstd/kstd/bits/format/arg.hpp b/libs/kstd/kstd/bits/format/arg.hpp
index e65b26fa..8271ca3d 100644
--- a/libs/kstd/kstd/bits/format/arg.hpp
+++ b/libs/kstd/kstd/bits/format/arg.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_ARG_HPP
#define KSTD_BITS_FORMAT_ARG_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/error.hpp>
#include <kstd/bits/format/fwd.hpp>
diff --git a/libs/kstd/kstd/bits/format/args.hpp b/libs/kstd/kstd/bits/format/args.hpp
index e8e31145..01735011 100644
--- a/libs/kstd/kstd/bits/format/args.hpp
+++ b/libs/kstd/kstd/bits/format/args.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_ARGS_HPP
#define KSTD_BITS_FORMAT_ARGS_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/arg.hpp>
#include <kstd/bits/format/context.hpp>
diff --git a/libs/kstd/kstd/bits/format/context.hpp b/libs/kstd/kstd/bits/format/context.hpp
index c166ba9c..d5f2f4d9 100644
--- a/libs/kstd/kstd/bits/format/context.hpp
+++ b/libs/kstd/kstd/bits/format/context.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_CONTEXT_HPP
#define KSTD_BITS_FORMAT_CONTEXT_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/arg.hpp>
#include <kstd/bits/format/output_buffer.hpp>
diff --git a/libs/kstd/kstd/bits/format/formatter.hpp b/libs/kstd/kstd/bits/format/formatter.hpp
index eb288294..c26907b2 100644
--- a/libs/kstd/kstd/bits/format/formatter.hpp
+++ b/libs/kstd/kstd/bits/format/formatter.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMATTER_HPP
#define KSTD_BITS_FORMATTER_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/context.hpp>
#include <kstd/bits/format/error.hpp>
diff --git a/libs/kstd/kstd/bits/format/formatter/cstring.hpp b/libs/kstd/kstd/bits/format/formatter/cstring.hpp
index 553c8caf..12cb9c6f 100644
--- a/libs/kstd/kstd/bits/format/formatter/cstring.hpp
+++ b/libs/kstd/kstd/bits/format/formatter/cstring.hpp
@@ -5,6 +5,7 @@
#include <kstd/bits/format/formatter.hpp>
#include <kstd/bits/format/formatter/string_view.hpp>
+#include <cstddef>
#include <string_view>
namespace kstd
@@ -24,6 +25,11 @@ namespace kstd
{
};
+ template<std::size_t Size>
+ struct formatter<char[Size]> : formatter<char const *> // NOLINT
+ {
+ };
+
} // namespace kstd
#endif \ No newline at end of file
diff --git a/libs/kstd/kstd/bits/format/output_buffer.hpp b/libs/kstd/kstd/bits/format/output_buffer.hpp
index fd7a2b4c..7e6f0575 100644
--- a/libs/kstd/kstd/bits/format/output_buffer.hpp
+++ b/libs/kstd/kstd/bits/format/output_buffer.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_OUTPUT_BUFFER_HPP
#define KSTD_BITS_FORMAT_OUTPUT_BUFFER_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <string_view>
diff --git a/libs/kstd/kstd/bits/format/parse_context.hpp b/libs/kstd/kstd/bits/format/parse_context.hpp
index cab8d726..81ed52cf 100644
--- a/libs/kstd/kstd/bits/format/parse_context.hpp
+++ b/libs/kstd/kstd/bits/format/parse_context.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_PARSE_CONTEXT_HPP
#define KSTD_BITS_FORMAT_PARSE_CONTEXT_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/error.hpp>
diff --git a/libs/kstd/kstd/bits/format/string.hpp b/libs/kstd/kstd/bits/format/string.hpp
index a2b298d4..ab034e7c 100644
--- a/libs/kstd/kstd/bits/format/string.hpp
+++ b/libs/kstd/kstd/bits/format/string.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_STRING_HPP
#define KSTD_BITS_FORMAT_STRING_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/format/context.hpp>
#include <kstd/bits/format/error.hpp>
diff --git a/libs/kstd/kstd/bits/format/vformat.cpp b/libs/kstd/kstd/bits/format/vformat.cpp
index 1bf293a4..7210a0b6 100644
--- a/libs/kstd/kstd/bits/format/vformat.cpp
+++ b/libs/kstd/kstd/bits/format/vformat.cpp
@@ -1,6 +1,7 @@
-#include <kstd/format>
-#include <kstd/string>
+#include <kstd/format.hpp>
+#include <kstd/string.hpp>
+#include <algorithm>
#include <cstddef>
#include <iterator>
#include <string_view>
@@ -221,4 +222,23 @@ namespace kstd::bits::format
return m_size;
}
+ auto span_writer::push(std::string_view text) -> void
+ {
+ if (m_position < m_span.size() - 1)
+ {
+ auto space_left = m_span.size() - m_position;
+ auto to_copy = std::min(space_left, text.size());
+ std::ranges::copy_n(text.begin(), to_copy, m_span.subspan(m_position).begin());
+ m_position += to_copy;
+ }
+ }
+
+ auto span_writer::push(char character) -> void
+ {
+ if (m_position < m_span.size() - 1)
+ {
+ m_span[m_position++] = character;
+ }
+ }
+
} // namespace kstd::bits::format \ No newline at end of file
diff --git a/libs/kstd/kstd/bits/format/vformat.hpp b/libs/kstd/kstd/bits/format/vformat.hpp
index 2db56d17..63b41ab6 100644
--- a/libs/kstd/kstd/bits/format/vformat.hpp
+++ b/libs/kstd/kstd/bits/format/vformat.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_FORMAT_VFORMAT_HPP
#define KSTD_BITS_FORMAT_VFORMAT_HPP
-// IWYU pragma: private, include <kstd/format>
+// IWYU pragma: private, include <kstd/format.hpp>
#include <kstd/bits/basic_string.hpp>
#include <kstd/bits/format/args.hpp>
@@ -11,8 +11,10 @@
#include <algorithm>
#include <cstddef>
#include <iterator>
+#include <span>
#include <string_view>
#include <type_traits>
+#include <utility>
namespace kstd
{
@@ -28,7 +30,7 @@ namespace kstd
//! @param args The arguments for the format string.
auto vformat_to(output_buffer & buffer, std::string_view format, format_args args) -> void;
- struct string_writer : output_buffer
+ struct string_writer final : output_buffer
{
auto push(std::string_view text) -> void final;
auto push(char character) -> void final;
@@ -40,7 +42,7 @@ namespace kstd
};
//! A buffer that merely records the size of the output written to it.
- struct size_recorder : output_buffer
+ struct size_recorder final : output_buffer
{
auto push(std::string_view text) -> void final;
auto push(char character) -> void final;
@@ -52,9 +54,9 @@ namespace kstd
};
template<std::output_iterator<char> Output>
- struct iterator_writer : output_buffer
+ struct iterator_writer final : output_buffer
{
- explicit iterator_writer(Output iterator)
+ constexpr explicit iterator_writer(Output iterator)
: m_output{iterator}
{}
@@ -77,6 +79,25 @@ namespace kstd
Output m_output{};
};
+ struct span_writer final : output_buffer
+ {
+ constexpr explicit span_writer(std::span<char> span)
+ : m_span{span}
+ {}
+
+ auto push(std::string_view text) -> void override;
+ auto push(char character) -> void override;
+
+ [[nodiscard]] constexpr auto position() const noexcept -> std::size_t
+ {
+ return m_position;
+ }
+
+ private:
+ std::size_t m_position{};
+ std::span<char> m_span{};
+ };
+
} // namespace bits::format
//! Format a given string with the provided arguments.
@@ -108,6 +129,21 @@ namespace kstd
return buffer.iterator();
}
+ //! Format a given string with the provided arguments.
+ //!
+ //! @param span The span to write to.
+ //! @param format The format string.
+ //! @param args The arguments for the format string.
+ //! @return A pair of the span written to and the next position to write to.
+ template<typename... ArgumentTypes>
+ auto format_to(std::span<char> span, format_string<std::type_identity_t<ArgumentTypes>...> format,
+ ArgumentTypes &&... args) -> std::pair<std::span<char>, std::size_t>
+ {
+ auto buffer = bits::format::span_writer{span};
+ bits::format::vformat_to(buffer, format.str_view, make_format_args(std::forward<ArgumentTypes>(args)...).args);
+ return {span, buffer.position()};
+ }
+
//! Determine the number of characters required to format the format string with the given arguments.
//!
//! @param format The format string.
diff --git a/libs/kstd/kstd/bits/observer_ptr.hpp b/libs/kstd/kstd/bits/observer_ptr.hpp
index 2593d7a4..e63e5d77 100644
--- a/libs/kstd/kstd/bits/observer_ptr.hpp
+++ b/libs/kstd/kstd/bits/observer_ptr.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_OBSERVER_PTR_HPP
#define KSTD_OBSERVER_PTR_HPP
-// IWYU pragma: private, include <kstd/memory>
+// IWYU pragma: private, include <kstd/memory.hpp>
#include <kstd/os/error.hpp>
diff --git a/libs/kstd/kstd/bits/observer_ptr.test.cpp b/libs/kstd/kstd/bits/observer_ptr.tests.cpp
index f26fc09a..eca14ccd 100644
--- a/libs/kstd/kstd/bits/observer_ptr.test.cpp
+++ b/libs/kstd/kstd/bits/observer_ptr.tests.cpp
@@ -1,4 +1,4 @@
-#include <kstd/memory>
+#include <kstd/memory.hpp>
#include <kstd/test_support/os_panic.hpp>
#include <catch2/catch_test_macros.hpp>
diff --git a/libs/kstd/kstd/bits/print_sink.hpp b/libs/kstd/kstd/bits/print_sink.hpp
index af765e06..a1e9b0d4 100644
--- a/libs/kstd/kstd/bits/print_sink.hpp
+++ b/libs/kstd/kstd/bits/print_sink.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_BITS_PRINT_SINK_HPP
#define KSTD_BITS_PRINT_SINK_HPP
-// IWYU pragma: private, include <kstd/print>
+// IWYU pragma: private, include <kstd/print.hpp>
namespace kstd
{
diff --git a/libs/kstd/kstd/bits/shared_ptr.hpp b/libs/kstd/kstd/bits/shared_ptr.hpp
index 57a89c0d..ce4bfb7f 100644
--- a/libs/kstd/kstd/bits/shared_ptr.hpp
+++ b/libs/kstd/kstd/bits/shared_ptr.hpp
@@ -6,7 +6,7 @@
#include <type_traits>
#include <utility>
-// IWYU pragma: private, include <kstd/memory>
+// IWYU pragma: private, include <kstd/memory.hpp>
namespace kstd
{
diff --git a/libs/kstd/kstd/bits/unique_ptr.hpp b/libs/kstd/kstd/bits/unique_ptr.hpp
index 3d803b4a..1df18cf2 100644
--- a/libs/kstd/kstd/bits/unique_ptr.hpp
+++ b/libs/kstd/kstd/bits/unique_ptr.hpp
@@ -3,7 +3,7 @@
#include <utility>
-// IWYU pragma: private, include <kstd/memory>
+// IWYU pragma: private, include <kstd/memory.hpp>
namespace kstd
{
diff --git a/libs/kstd/kstd/cstring b/libs/kstd/kstd/cstring.hpp
index bd8b28d8..bd8b28d8 100644
--- a/libs/kstd/kstd/cstring
+++ b/libs/kstd/kstd/cstring.hpp
diff --git a/libs/kstd/kstd/ext/bitfield_enum b/libs/kstd/kstd/ext/bitfield_enum.hpp
index 80fe9d29..80fe9d29 100644
--- a/libs/kstd/kstd/ext/bitfield_enum
+++ b/libs/kstd/kstd/ext/bitfield_enum.hpp
diff --git a/libs/kstd/kstd/flat_map b/libs/kstd/kstd/flat_map.hpp
index e51eb918..31557760 100644
--- a/libs/kstd/kstd/flat_map
+++ b/libs/kstd/kstd/flat_map.hpp
@@ -3,7 +3,7 @@
#include <kstd/bits/flat_map.hpp>
#include <kstd/os/error.hpp>
-#include <kstd/vector>
+#include <kstd/vector.hpp>
#include <algorithm>
#include <concepts>
diff --git a/libs/kstd/kstd/flat_map.test.cpp b/libs/kstd/kstd/flat_map.tests.cpp
index 9df03bb4..bfd02303 100644
--- a/libs/kstd/kstd/flat_map.test.cpp
+++ b/libs/kstd/kstd/flat_map.tests.cpp
@@ -1,4 +1,4 @@
-#include <kstd/flat_map>
+#include <kstd/flat_map.hpp>
#include <kstd/test_support/os_panic.hpp>
diff --git a/libs/kstd/kstd/format b/libs/kstd/kstd/format.hpp
index 5ed798db..5d7f4ae6 100644
--- a/libs/kstd/kstd/format
+++ b/libs/kstd/kstd/format.hpp
@@ -5,6 +5,7 @@
#include <kstd/bits/format/arg.hpp>
#include <kstd/bits/format/args.hpp>
#include <kstd/bits/format/context.hpp>
+#include <kstd/bits/format/error.hpp>
#include <kstd/bits/format/formatter.hpp>
#include <kstd/bits/format/formatter/bool.hpp>
#include <kstd/bits/format/formatter/byte.hpp>
diff --git a/libs/kstd/kstd/format.test.cpp b/libs/kstd/kstd/format.tests.cpp
index 6126605f..a34cf063 100644
--- a/libs/kstd/kstd/format.test.cpp
+++ b/libs/kstd/kstd/format.tests.cpp
@@ -1,7 +1,8 @@
-#include <kstd/format>
+#include <kstd/format.hpp>
#include <catch2/catch_test_macros.hpp>
+#include <array>
#include <iterator>
#include <sstream>
#include <string_view>
@@ -116,6 +117,95 @@ SCENARIO("Formatting to an output iterator", "[format]")
}
}
+SCENARIO("Formatting to a span", "[format]")
+{
+ GIVEN("a format string without any placeholders")
+ {
+ constexpr auto fmt = "This is a test"sv;
+
+ WHEN("calling format without any arguments.")
+ {
+ auto buffer = std::array<char, 100>{};
+ auto [span, length] = kstd::format_to(buffer, fmt);
+
+ THEN("the unmodified string is written to the span")
+ {
+ REQUIRE(std::string_view{span.data(), length} == "This is a test");
+ }
+ }
+
+ WHEN("calling format with additional arguments")
+ {
+ auto buffer = std::array<char, 100>{};
+ auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3);
+
+ THEN("the unmodified string is written to the span")
+ {
+ REQUIRE(std::string_view(span.data(), length) == "This is a test");
+ }
+ }
+
+ WHEN("the span is too small")
+ {
+ auto buffer = std::array<char, 4>{};
+ auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3);
+
+ THEN("the written length is equal to the span size")
+ {
+ REQUIRE(length == span.size());
+ }
+
+ THEN("only part of the unmodified string is written to the span")
+ {
+ REQUIRE(std::string_view(span.data(), length) == "This");
+ }
+ }
+ }
+
+ GIVEN("a format string with placeholders")
+ {
+ constexpr auto fmt = "Here are some placeholders: {} {} {}"sv;
+
+ WHEN("calling format with the same number of arguments as there are placeholders")
+ {
+ auto buffer = std::array<char, 100>{};
+ auto [span, length] = kstd::format_to(buffer, fmt, 1, true, -100);
+
+ THEN("the formatted string is written to the span")
+ {
+ REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 1 true -100");
+ }
+ }
+
+ WHEN("calling format with too many arguments")
+ {
+ auto buffer = std::array<char, 100>{};
+ auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6);
+
+ THEN("the formatted string is written to the span")
+ {
+ REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 2 false -200");
+ }
+ }
+
+ WHEN("the span is too small")
+ {
+ auto buffer = std::array<char, 4>{};
+ auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6);
+
+ THEN("the written length is equal to the span size")
+ {
+ REQUIRE(length == span.size());
+ }
+
+ THEN("only part of the unmodified string is written to the span")
+ {
+ REQUIRE(std::string_view(span.data(), length) == "Here");
+ }
+ }
+ }
+}
+
SCENARIO("Determining formatted size")
{
GIVEN("a format string without any placeholders")
diff --git a/libs/kstd/kstd/libc/string.cpp b/libs/kstd/kstd/libc/string.cpp
index b7cdb82e..15ecc70f 100644
--- a/libs/kstd/kstd/libc/string.cpp
+++ b/libs/kstd/kstd/libc/string.cpp
@@ -1,4 +1,4 @@
-#include <kstd/cstring>
+#include <kstd/cstring.hpp>
#include <algorithm>
#include <bit>
diff --git a/libs/kstd/kstd/memory b/libs/kstd/kstd/memory.hpp
index f108c6d6..f108c6d6 100644
--- a/libs/kstd/kstd/memory
+++ b/libs/kstd/kstd/memory.hpp
diff --git a/libs/kstd/kstd/mutex.cpp b/libs/kstd/kstd/mutex.cpp
index 73876572..c1c5b190 100644
--- a/libs/kstd/kstd/mutex.cpp
+++ b/libs/kstd/kstd/mutex.cpp
@@ -1,4 +1,4 @@
-#include <kstd/mutex>
+#include <kstd/mutex.hpp>
#include <kstd/os/error.hpp>
diff --git a/libs/kstd/kstd/mutex b/libs/kstd/kstd/mutex.hpp
index b2a31aa9..b2a31aa9 100644
--- a/libs/kstd/kstd/mutex
+++ b/libs/kstd/kstd/mutex.hpp
diff --git a/libs/kstd/kstd/posix.hpp b/libs/kstd/kstd/posix.hpp
new file mode 100644
index 00000000..12bd5ec0
--- /dev/null
+++ b/libs/kstd/kstd/posix.hpp
@@ -0,0 +1,85 @@
+#ifndef KSTD_CERRNO_HPP
+#define KSTD_CERRNO_HPP
+
+namespace kstd::posix
+{
+
+ constexpr auto static inline eafnosupport = 1;
+ constexpr auto static inline eaddrinuse = 2;
+ constexpr auto static inline eaddrnotavail = 3;
+ constexpr auto static inline eisconn = 4;
+ constexpr auto static inline e2big = 5;
+ constexpr auto static inline edom = 6;
+ constexpr auto static inline efault = 7;
+ constexpr auto static inline ebadf = 8;
+ constexpr auto static inline ebadmsg = 9;
+ constexpr auto static inline epipe = 10;
+ constexpr auto static inline econnaborted = 11;
+ constexpr auto static inline ealready = 12;
+ constexpr auto static inline econnrefused = 13;
+ constexpr auto static inline econnreset = 14;
+ constexpr auto static inline exdev = 15;
+ constexpr auto static inline edestaddrreq = 16;
+ constexpr auto static inline ebusy = 17;
+ constexpr auto static inline enotempty = 18;
+ constexpr auto static inline enoexec = 19;
+ constexpr auto static inline eexist = 20;
+ constexpr auto static inline efbig = 21;
+ constexpr auto static inline enametoolong = 22;
+ constexpr auto static inline enosys = 23;
+ constexpr auto static inline ehostunreach = 24;
+ constexpr auto static inline eidrm = 25;
+ constexpr auto static inline eilseq = 26;
+ constexpr auto static inline enotty = 27;
+ constexpr auto static inline eintr = 28;
+ constexpr auto static inline einval = 29;
+ constexpr auto static inline espipe = 30;
+ constexpr auto static inline eio = 31;
+ constexpr auto static inline eisdir = 32;
+ constexpr auto static inline emsgsize = 33;
+ constexpr auto static inline enetdown = 34;
+ constexpr auto static inline enetreset = 35;
+ constexpr auto static inline enetunreach = 36;
+ constexpr auto static inline enobufs = 37;
+ constexpr auto static inline echild = 38;
+ constexpr auto static inline enolink = 39;
+ constexpr auto static inline enolck = 40;
+ constexpr auto static inline enomsg = 41;
+ constexpr auto static inline enoprotoopt = 42;
+ constexpr auto static inline enospc = 43;
+ constexpr auto static inline enodev = 44;
+ constexpr auto static inline enxio = 45;
+ constexpr auto static inline enoent = 46;
+ constexpr auto static inline esrch = 47;
+ constexpr auto static inline enotdir = 48;
+ constexpr auto static inline enotsock = 49;
+ constexpr auto static inline enotconn = 50;
+ constexpr auto static inline enomem = 51;
+ constexpr auto static inline enotsup = 52;
+ constexpr auto static inline ecanceled = 53;
+ constexpr auto static inline einprogress = 54;
+ constexpr auto static inline eperm = 55;
+ constexpr auto static inline eopnotsupp = 56;
+ constexpr auto static inline ewouldblock = 57;
+ constexpr auto static inline eownerdead = 58;
+ constexpr auto static inline eacces = 59;
+ constexpr auto static inline eproto = 60;
+ constexpr auto static inline eprotonosupport = 61;
+ constexpr auto static inline erofs = 62;
+ constexpr auto static inline edeadlk = 63;
+ constexpr auto static inline eagain = 64;
+ constexpr auto static inline erange = 65;
+ constexpr auto static inline esocktnosupport = 66;
+ constexpr auto static inline enotrecoverable = 67;
+ constexpr auto static inline etxtbsy = 68;
+ constexpr auto static inline etimedout = 69;
+ constexpr auto static inline emfile = 70;
+ constexpr auto static inline enfile = 71;
+ constexpr auto static inline emlink = 72;
+ constexpr auto static inline eloop = 73;
+ constexpr auto static inline eoverflow = 74;
+ constexpr auto static inline eprototype = 75;
+
+} // namespace kstd::posix
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/kstd/print b/libs/kstd/kstd/print.hpp
index 1033f722..0d37efbe 100644
--- a/libs/kstd/kstd/print
+++ b/libs/kstd/kstd/print.hpp
@@ -2,7 +2,7 @@
#define KSTD_PRINT
#include <kstd/bits/print_sink.hpp> // IWYU pragma: export
-#include <kstd/format>
+#include <kstd/format.hpp>
#include <kstd/os/print.hpp>
#include <type_traits>
@@ -26,6 +26,7 @@ namespace kstd
//! @qualifier kernel-defined
//! Format the given error string using the given arguments and print it to the currently active output device.
//!
+ //! @param sink The output sink to print to.
//! @param format The format string
//! @param args The arguments to use to place in the format string's placeholders.
template<typename... Args>
@@ -54,6 +55,7 @@ namespace kstd
//! Format the given error string using the given arguments and print it, including a newline, to the currently active
//! output device.
//!
+ //! @param sink The output sink to print to.
//! @param format The format string
//! @param args The arguments
template<typename... Args>
diff --git a/libs/kstd/kstd/ranges b/libs/kstd/kstd/ranges.hpp
index 78c3adbf..78c3adbf 100644
--- a/libs/kstd/kstd/ranges
+++ b/libs/kstd/kstd/ranges.hpp
diff --git a/libs/kstd/kstd/result.hpp b/libs/kstd/kstd/result.hpp
new file mode 100644
index 00000000..7b027a8d
--- /dev/null
+++ b/libs/kstd/kstd/result.hpp
@@ -0,0 +1,35 @@
+#ifndef KSTD_RESULT_HPP
+#define KSTD_RESULT_HPP
+
+#include <kstd/system_error.hpp>
+
+#include <expected>
+#include <type_traits>
+#include <utility>
+
+namespace kstd
+{
+
+ template<typename SuccessType>
+ using result = std::expected<SuccessType, error_code>;
+
+ template<typename SuccessType>
+ requires(!std::is_void_v<SuccessType>)
+ constexpr auto inline success(SuccessType && value) -> result<std::remove_cvref_t<SuccessType>>
+ {
+ return result<std::remove_cvref_t<SuccessType>>{std::in_place, std::forward<SuccessType>(value)};
+ }
+
+ constexpr auto inline success() -> result<void>
+ {
+ return result<void>{std::in_place};
+ }
+
+ constexpr auto inline failure(error_code error) -> std::unexpected<error_code>
+ {
+ return std::unexpected(error);
+ }
+
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/kstd/stack b/libs/kstd/kstd/stack.hpp
index 02e44ea4..27e693f2 100644
--- a/libs/kstd/kstd/stack
+++ b/libs/kstd/kstd/stack.hpp
@@ -1,7 +1,7 @@
#ifndef KSTD_STACK_HPP
#define KSTD_STACK_HPP
-#include <kstd/vector>
+#include <kstd/vector.hpp>
#include <initializer_list>
#include <utility>
diff --git a/libs/kstd/kstd/string b/libs/kstd/kstd/string.hpp
index 4a67a3a4..9978affc 100644
--- a/libs/kstd/kstd/string
+++ b/libs/kstd/kstd/string.hpp
@@ -7,9 +7,9 @@
#include <kstd/bits/format/formatter/cstring.hpp>
#include <kstd/bits/format/formatter/integral.hpp>
#include <kstd/bits/format/vformat.hpp>
-#include <kstd/cstring>
+#include <kstd/cstring.hpp>
#include <kstd/os/error.hpp>
-#include <kstd/vector>
+#include <kstd/vector.hpp>
#include <concepts>
#include <cstddef>
diff --git a/libs/kstd/kstd/string.test.cpp b/libs/kstd/kstd/string.tests.cpp
index e11877e5..b8fa1139 100644
--- a/libs/kstd/kstd/string.test.cpp
+++ b/libs/kstd/kstd/string.tests.cpp
@@ -1,6 +1,6 @@
-#include <kstd/string>
+#include <kstd/string.hpp>
-#include <kstd/allocator>
+#include <kstd/allocator.hpp>
#include <kstd/test_support/os_panic.hpp>
#include <catch2/catch_test_macros.hpp>
diff --git a/libs/kstd/kstd/system_error.hpp b/libs/kstd/kstd/system_error.hpp
new file mode 100644
index 00000000..09efb097
--- /dev/null
+++ b/libs/kstd/kstd/system_error.hpp
@@ -0,0 +1,636 @@
+#ifndef KSTD_SYSTEM_ERROR_HPP
+#define KSTD_SYSTEM_ERROR_HPP
+
+#include <kstd/format.hpp>
+#include <kstd/posix.hpp> // IWYU pragma: export
+
+#include <compare>
+#include <cstdint>
+#include <functional>
+#include <string_view>
+#include <type_traits>
+
+namespace kstd
+{
+
+ struct error_condition;
+ struct error_code;
+
+ //! Determine if a given enumeration type is an error condition enumeration.
+ //!
+ //! An enumeration type is an error condition enumeration if it defines generic, system-level error conditions.
+ //! Specific subsystem error enumerations on the other hand are not generic enough to be considered error conditions
+ //! and are thus called error codes.
+ //!
+ //! @note Types may opt in to being an error condition enumeration by specializing this class template.
+ //!
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ requires(std::is_enum_v<CandidateType>)
+ struct is_error_condition_enum : std::false_type
+ {
+ };
+
+ //! Determine if a given enumeration type is an error condition enumeration.
+ //!
+ //! @see is_error_condition_enum
+ //!
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ constexpr auto inline is_error_condition_enum_v = is_error_condition_enum<CandidateType>::value;
+
+ //! Determine if a given enumeration type is an error condition enumeration.
+ //!
+ //! @see is_error_condition_enum
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ concept error_condition_enum = std::is_enum_v<CandidateType> && is_error_condition_enum_v<CandidateType>;
+
+ //! Determine if a given enumeration type is an error code enumeration.
+ //!
+ //! An enumeration type is an error code enumeration if it defines specific, subsystem-level error codes.
+ //! Generic error conditions are not specific enough to be considered error codes and are thus called error
+ //! conditions.
+ //!
+ //! @note Types may opt in to being an error code enumeration by specializing this class template.
+ //!
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ requires(std::is_enum_v<CandidateType>)
+ struct is_error_code_enum : std::false_type
+ {
+ };
+
+ //! Determine if a given enumeration type is an error code enumeration.
+ //!
+ //! @see is_error_code_enum
+ //!
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ constexpr auto inline is_error_code_enum_v = is_error_code_enum<CandidateType>::value;
+
+ //! Determine if a given enumeration type is an error code enumeration.
+ //!
+ //! @see is_error_code_enum
+ //!
+ //! @tparam CandidateType The type to check.
+ template<typename CandidateType>
+ concept error_code_enum = std::is_enum_v<CandidateType> && is_error_code_enum_v<CandidateType>;
+
+ //! A category of error codes or conditions.
+ //!
+ //! An error category is a group of related error codes or conditions. Each error code or condition belongs to exactly
+ //! one error category. Error categories are used to provide additional context and information about the error codes
+ //! or conditions they contain. They can also be used to compare error codes or conditions from different categories.
+ //!
+ //! Subsystems shall defined their own error categories for their error codes, by inheriting from this class.
+ struct error_category
+ {
+ constexpr error_category() noexcept = default;
+
+ error_category(error_category const &) = delete;
+
+ constexpr virtual ~error_category() = default;
+
+ auto operator=(error_category const &) -> error_category & = delete;
+
+ //! Get the name of this error category.
+ [[nodiscard]] constexpr auto virtual name() const noexcept -> std::string_view = 0;
+
+ //! Get the default error condition for a given error code value in this category.
+ //!
+ //! @param value The error code value to get the default error condition for.
+ //! @return The default error condition for the given error code value in this category.
+ [[nodiscard]] constexpr auto virtual default_error_condition(int value) const noexcept -> error_condition;
+
+ //! Check if a given error code value is equivalent to a given error condition in this category.
+ //!
+ //! @param value The error code value to check.
+ //! @param other The error condition to compare against.
+ //! @return True if the error code value is equivalent to the error condition in this category, false otherwise.
+ [[nodiscard]] constexpr auto virtual equivalent(int value, error_condition const & other) const noexcept -> bool;
+
+ //! Check if a given error code is equivalent to a given error condition in this category.
+ //!
+ //! @param code The error code to check.
+ //! @param condition The error condition to compare against.
+ //! @return True if the error code is equivalent to the error condition in this category, false otherwise.
+ [[nodiscard]] constexpr auto virtual equivalent(error_code const & code, int condition) const noexcept -> bool;
+
+ //! Get the message for a given error code value in this category.
+ //!
+ //! @param value The error code value to get the message for.
+ //! @return The message for the given error code value in this category.
+ [[nodiscard]] constexpr auto virtual message(int value) const noexcept -> std::string_view = 0;
+
+ //! Check if this error category is equal to another one.
+ [[nodiscard]] constexpr auto operator==(error_category const & other) const noexcept -> bool
+ {
+ return this == &other;
+ }
+
+ //! Lexicographically compare this error category to a different one.
+ [[nodiscard]] constexpr auto operator<=>(error_category const & other) const noexcept -> std::strong_ordering
+ {
+ return std::compare_three_way{}(this, &other);
+ }
+ };
+
+ //! An error condition represents a generic, system-level error.
+ //!
+ //! Error conditions are used to represent errors to be tested for.
+ struct error_condition
+ {
+ //! Construct an error condition with a default value and category.
+ constexpr error_condition() noexcept;
+
+ //! Construct an error condition with a specific value and category.
+ //!
+ //! @param value The error code value.
+ //! @param category The error category.
+ constexpr error_condition(int value, error_category const & category) noexcept
+ : m_value{value}
+ , m_category{&category}
+ {}
+
+ //! Construct an error condition from an error condition enumeration value.
+ //!
+ //! @tparam Enum The error condition enumeration type.
+ //! @param value The error condition enumeration value.
+ template<error_condition_enum Enum>
+ constexpr error_condition(Enum value) noexcept
+ : error_condition{make_error_condition(value)}
+ {}
+
+ //! Assign an error condition enumeration value to this error condition.
+ //!
+ //! @tparam Enum The error condition enumeration type.
+ //! @param value The error condition enumeration value.
+ template<error_condition_enum Enum>
+ constexpr auto operator=(Enum value) noexcept -> error_condition &
+ {
+ *this = make_error_condition(value);
+ }
+
+ //! Assign a new value and category to this error condition.
+ //!
+ //! @param value The new error code value.
+ //! @param category The new error category.
+ constexpr auto assign(int value, error_category const & category) noexcept -> void
+ {
+ m_value = value;
+ m_category = &category;
+ }
+
+ //! Clear this error condition.
+ //!
+ //! This sets the value to 0 and the category to the generic error category.
+ constexpr auto clear() noexcept -> void;
+
+ //! Get the raw error code value of this error condition.
+ [[nodiscard]] constexpr auto value() const noexcept -> int
+ {
+ return m_value;
+ }
+
+ //! Get the error category of this error condition.
+ [[nodiscard]] constexpr auto category() const noexcept -> error_category const &
+ {
+ return *m_category;
+ }
+
+ //! Get the message associated with this error condition based on its value and category.
+ [[nodiscard]] constexpr auto message() const noexcept -> std::string_view
+ {
+ return m_category->message(m_value);
+ }
+
+ //! Check if this error condition holds an error.
+ //!
+ //! @return @p true iff. this error condition holds a non-zero value, @p false otherwise.
+ [[nodiscard]] constexpr explicit operator bool() const noexcept
+ {
+ return m_value != 0;
+ }
+
+ //! Check if two error conditions are equal.
+ //!
+ //! Error conditions are considered equal if they hold the same value and reference the same category.
+ [[nodiscard]] constexpr auto friend operator==(error_condition const & lhs, error_condition const & rhs) noexcept
+ -> bool
+ {
+ return lhs.category() == rhs.category() && lhs.value() == rhs.value();
+ }
+
+ //! Lexicographically compare two error conditions.
+ [[nodiscard]] constexpr auto friend operator<=>(error_condition const & lhs, error_condition const & rhs) noexcept
+ -> std::strong_ordering
+ {
+ if (auto result = lhs.category() <=> rhs.category(); result != std::strong_ordering::equal)
+ {
+ return result;
+ }
+
+ return lhs.value() <=> rhs.value();
+ }
+
+ private:
+ int m_value{};
+ error_category const * m_category{};
+ };
+
+ //! An error code represents a specific, subsystem-level error.
+ //!
+ //! Error codes are used to represent errors that are specific to a subsystem. Equivalence between error codes and
+ //! error conditions can be defined per each error enumeration type.
+ struct error_code
+ {
+ //! Construct an error code with a default value and category.
+ constexpr error_code() noexcept;
+
+ //! Construct an error code with a specific value and category.
+ constexpr error_code(int value, error_category const & category) noexcept
+ : m_value{value}
+ , m_category{&category}
+ {}
+
+ //! Construct an error code from an error code enumeration value.
+ //!
+ //! @tparam Enum The error code enumeration type.
+ //! @param value The error code enumeration value.
+ template<error_code_enum Enum>
+ constexpr error_code(Enum value) noexcept
+ : error_code{make_error_code(value)}
+ {}
+
+ //! Assign an error code enumeration value to this error code.
+ //!
+ //! The category is chosen based on the enumeration type of the value.
+ //! @tparam Enum The error code enumeration type.
+ //! @param value The error code enumeration value.
+ template<error_code_enum Enum>
+ constexpr auto operator=(Enum value) noexcept -> error_code &
+ {
+ return *this = make_error_code(value);
+ }
+
+ //! Assign a new value and category to this error code.
+ //!
+ //! @param value The new error code value.
+ //! @param category The new error code category.
+ constexpr auto assign(int value, error_category const & category) noexcept -> void
+ {
+ m_value = value;
+ m_category = &category;
+ }
+
+ //! Clear this error code.
+ constexpr auto clear() noexcept -> void;
+
+ //! Get the raw error code value of this error code.
+ [[nodiscard]] constexpr auto value() const noexcept -> int
+ {
+ return m_value;
+ }
+
+ //! Get the error category of this error code.
+ [[nodiscard]] constexpr auto category() const noexcept -> error_category const &
+ {
+ return *m_category;
+ }
+
+ //! Get and error condition that is equivalent to this error code.
+ [[nodiscard]] constexpr auto default_error_condition() const noexcept -> error_condition
+ {
+ return m_category->default_error_condition(m_value);
+ }
+
+ //! Get the message associated with this error code based on its value and category.
+ [[nodiscard]] constexpr auto message() const noexcept -> std::string_view
+ {
+ return m_category->message(m_value);
+ }
+
+ //! Check if this error code holds an error.
+ //!
+ //! @return @p true iff. this error code holds a non-zero value, @p false otherwise.
+ [[nodiscard]] constexpr explicit operator bool() const noexcept
+ {
+ return m_value != 0;
+ }
+
+ //! Check if two error codes are equal.
+ //!
+ //! Error codes are considered equal if they hold the same value and reference the same category.
+ [[nodiscard]] constexpr auto friend operator==(error_code const & lhs, error_code const & rhs) noexcept -> bool
+ {
+ return lhs.category() == rhs.category() && lhs.value() == rhs.value();
+ }
+
+ //! Lexicographically compare two error codes.
+ [[nodiscard]] constexpr auto friend operator<=>(error_code const & lhs, error_code const & rhs) noexcept
+ -> std::strong_ordering
+ {
+ if (auto result = lhs.category() <=> rhs.category(); result != std::strong_ordering::equal)
+ {
+ return result;
+ }
+
+ return lhs.value() <=> rhs.value();
+ }
+
+ private:
+ int m_value{};
+ error_category const * m_category{};
+ };
+
+ enum struct errc : std::uint32_t
+ {
+ address_family_not_supported = posix::eafnosupport,
+ address_in_use = posix::eaddrinuse,
+ address_not_available = posix::eaddrnotavail,
+ already_connected = posix::eisconn,
+ argument_list_too_long = posix::e2big,
+ argument_out_of_domain = posix::edom,
+ bad_address = posix::efault,
+ bad_file_descriptor = posix::ebadf,
+ bad_message = posix::ebadmsg,
+ broken_pipe = posix::epipe,
+ connection_aborted = posix::econnaborted,
+ connection_already_in_progress = posix::ealready,
+ connection_refused = posix::econnrefused,
+ connection_reset = posix::econnreset,
+ cross_device_link = posix::exdev,
+ destination_address_required = posix::edestaddrreq,
+ device_or_resource_busy = posix::ebusy,
+ directory_not_empty = posix::enotempty,
+ executable_format_error = posix::enoexec,
+ file_exists = posix::eexist,
+ file_too_large = posix::efbig,
+ filename_too_long = posix::enametoolong,
+ function_not_supported = posix::enosys,
+ host_unreachable = posix::ehostunreach,
+ identifier_removed = posix::eidrm,
+ illegal_byte_sequence = posix::eilseq,
+ inappropriate_io_control_operation = posix::enotty,
+ interrupted = posix::eintr,
+ invalid_argument = posix::einval,
+ invalid_seek = posix::espipe,
+ io_error = posix::eio,
+ is_a_directory = posix::eisdir,
+ message_size = posix::emsgsize,
+ network_down = posix::enetdown,
+ network_reset = posix::enetreset,
+ network_unreachable = posix::enetunreach,
+ no_buffer_space = posix::enobufs,
+ no_child_process = posix::echild,
+ no_link = posix::enolink,
+ no_lock_available = posix::enolck,
+ no_message = posix::enomsg,
+ no_protocol_option = posix::enoprotoopt,
+ no_space_on_device = posix::enospc,
+ no_such_device_or_address = posix::enxio,
+ no_such_device = posix::enodev,
+ no_such_file_or_directory = posix::enoent,
+ no_such_process = posix::esrch,
+ not_a_directory = posix::enotdir,
+ not_a_socket = posix::enotsock,
+ not_connected = posix::enotconn,
+ not_enough_memory = posix::enomem,
+ not_supported = posix::enotsup,
+ operation_canceled = posix::ecanceled,
+ operation_in_progress = posix::einprogress,
+ operation_not_permitted = posix::eperm,
+ operation_not_supported = posix::eopnotsupp,
+ operation_would_block = posix::ewouldblock,
+ owner_dead = posix::eownerdead,
+ permission_denied = posix::eacces,
+ protocol_error = posix::eproto,
+ protocol_not_supported = posix::eprotonosupport,
+ read_only_file_system = posix::erofs,
+ resource_deadlock_would_occur = posix::edeadlk,
+ resource_unavailable_try_again = posix::eagain,
+ result_out_of_range = posix::erange,
+ state_not_recoverable = posix::enotrecoverable,
+ text_file_busy = posix::etxtbsy,
+ timed_out = posix::etimedout,
+ too_many_files_open_in_system = posix::enfile,
+ too_many_files_open = posix::emfile,
+ too_many_links = posix::emlink,
+ too_many_symbolic_link_levels = posix::eloop,
+ value_too_large = posix::eoverflow,
+ wrong_protocol_type = posix::eprototype,
+ };
+
+ //! Mark the kstd::errc enumeration as an error condition enumeration.
+ template<>
+ struct is_error_condition_enum<errc> : std::true_type
+ {
+ };
+
+ namespace bits
+ {
+ constexpr auto to_message(errc error) -> std::string_view
+ {
+ switch (error)
+ {
+ // clang-format off
+ case errc::address_family_not_supported: return "address family not supported";
+ case errc::address_in_use: return "address in use";
+ case errc::address_not_available: return "address not available";
+ case errc::already_connected: return "already connected";
+ case errc::argument_list_too_long: return "argument list too long";
+ case errc::argument_out_of_domain: return "argument out of domain";
+ case errc::bad_address: return "bad address";
+ case errc::bad_file_descriptor: return "bad file descriptor";
+ case errc::bad_message: return "bad message";
+ case errc::broken_pipe: return "broken pipe";
+ case errc::connection_aborted: return "connection aborted";
+ case errc::connection_already_in_progress: return "connection already in progress";
+ case errc::connection_refused: return "connection refused";
+ case errc::connection_reset: return "connection reset";
+ case errc::cross_device_link: return "cross device link";
+ case errc::destination_address_required: return "destination address required";
+ case errc::device_or_resource_busy: return "device or resource busy";
+ case errc::directory_not_empty: return "directory not empty";
+ case errc::executable_format_error: return "invalid executable format";
+ case errc::file_exists: return "file exists";
+ case errc::file_too_large: return "file too large";
+ case errc::filename_too_long: return "filename too long";
+ case errc::function_not_supported: return "function not supported";
+ case errc::host_unreachable: return "host unreachable";
+ case errc::identifier_removed: return "identifier removed";
+ case errc::illegal_byte_sequence: return "illegal byte sequence";
+ case errc::inappropriate_io_control_operation: return "inappropriate io control operation";
+ case errc::interrupted: return "system call interrupted";
+ case errc::invalid_argument: return "invalid argument";
+ case errc::invalid_seek: return "invalid seek";
+ case errc::io_error: return "input/output error";
+ case errc::is_a_directory: return "is a directory";
+ case errc::message_size: return "message size";
+ case errc::network_down: return "network down";
+ case errc::network_reset: return "network reset";
+ case errc::network_unreachable: return "network unreachable";
+ case errc::no_buffer_space: return "no buffer space";
+ case errc::no_child_process: return "no child process";
+ case errc::no_link: return "no link";
+ case errc::no_lock_available: return "no lock available";
+ case errc::no_message: return "no message";
+ case errc::no_protocol_option: return "no protocol option";
+ case errc::no_space_on_device: return "no space on device";
+ case errc::no_such_device: return "no such device";
+ case errc::no_such_device_or_address: return "no such device or address";
+ case errc::no_such_file_or_directory: return "no such file or directory";
+ case errc::no_such_process: return "no such process";
+ case errc::not_a_directory: return "not a directory";
+ case errc::not_a_socket: return "not a socket";
+ case errc::not_connected: return "not connected";
+ case errc::not_enough_memory: return "not enough memory";
+ case errc::not_supported: return "not supported";
+ case errc::operation_canceled: return "operation canceled";
+ case errc::operation_in_progress: return "operation in progress";
+ case errc::operation_not_permitted: return "operation not permitted";
+ case errc::operation_not_supported: return "operation not supported";
+ case errc::operation_would_block: return "operation would block";
+ case errc::owner_dead: return "owner dead";
+ case errc::permission_denied: return "permission denied";
+ case errc::protocol_error: return "protocol error";
+ case errc::protocol_not_supported: return "protocol not supported";
+ case errc::read_only_file_system: return "read only file system";
+ case errc::resource_deadlock_would_occur: return "resource deadlock would occur";
+ case errc::resource_unavailable_try_again: return "resource unavailable, try again";
+ case errc::result_out_of_range: return "result out of range";
+ case errc::state_not_recoverable: return "state not recoverable";
+ case errc::text_file_busy: return "text file busy";
+ case errc::timed_out: return "timed out";
+ case errc::too_many_files_open: return "too many files open";
+ case errc::too_many_files_open_in_system: return "too many files open in system";
+ case errc::too_many_links: return "too many links";
+ case errc::too_many_symbolic_link_levels: return "too many symbolic link levels";
+ case errc::value_too_large: return "value too large";
+ case errc::wrong_protocol_type: return "wrong protocol type";
+ default: return "unknown error";
+ // clang-format on
+ }
+ }
+
+ struct generic_category_t final : error_category
+ {
+ [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override
+ {
+ return "generic";
+ }
+
+ [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override
+ {
+ return to_message(static_cast<errc>(value));
+ }
+ } constexpr inline generic_category_instance{};
+
+ struct system_category_t final : error_category
+ {
+ [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override
+ {
+ return "system";
+ }
+
+ [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override
+ {
+ return to_message(static_cast<errc>(value));
+ }
+ } constexpr inline system_category_instance{};
+ } // namespace bits
+
+ //! Get a reference to the generic error category.
+ constexpr auto inline generic_category() noexcept -> error_category const &
+ {
+ return bits::generic_category_instance;
+ }
+
+ //! Get a reference to the system error category.
+ constexpr auto inline system_category() noexcept -> error_category const &
+ {
+ return bits::system_category_instance;
+ }
+
+ constexpr auto inline error_category::default_error_condition(int value) const noexcept -> error_condition
+ {
+ return error_condition{value, *this};
+ }
+
+ constexpr auto inline error_category::equivalent(int value, error_condition const & other) const noexcept -> bool
+ {
+ return default_error_condition(value) == other;
+ }
+
+ constexpr auto error_category::equivalent(error_code const & code, int condition) const noexcept -> bool
+ {
+ return *this == code.category() && code.value() == condition;
+ }
+
+ constexpr error_condition::error_condition() noexcept
+ : error_condition{0, generic_category()}
+ {}
+
+ constexpr auto error_condition::clear() noexcept -> void
+ {
+ m_value = 0;
+ m_category = &generic_category();
+ }
+
+ constexpr auto operator==(error_code const & code, error_condition const & condition) noexcept -> bool
+ {
+ return code.category().equivalent(code.value(), condition) ||
+ condition.category().equivalent(code, condition.value());
+ }
+
+ constexpr error_code::error_code() noexcept
+ : error_code{0, system_category()} {};
+
+ constexpr auto error_code::clear() noexcept -> void
+ {
+ m_value = 0;
+ m_category = &system_category();
+ }
+
+ //! Create an error code from an kstd::errc enumeration value.
+ [[nodiscard]] constexpr auto inline make_error_code(errc const value) noexcept -> error_code
+ {
+ return {static_cast<int>(value), generic_category()};
+ }
+
+ //! Create an error condition from an kstd::errc enumeration value.
+ [[nodiscard]] constexpr auto inline make_error_condition(errc const value) noexcept -> error_condition
+ {
+ return {static_cast<int>(value), generic_category()};
+ }
+
+ //! Enable formatting of kstd::error_code
+ //!
+ //! There are currently no valid format specifiers for error codes.
+ template<>
+ struct formatter<error_code>
+ {
+ constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator
+ {
+ auto it = context.begin();
+ if (it != context.end() && *it != '}')
+ {
+ bits::format::error("Invalid specifier for string_view.");
+ }
+ return it;
+ }
+
+ auto format(error_code const & error, format_context & context) const -> void
+ {
+ context.push(error.category().name());
+ context.push(':');
+ formatter<int>{}.format(error.value(), context);
+ context.push(':');
+ context.push(error.message());
+ }
+ };
+
+} // namespace kstd
+
+#endif
diff --git a/libs/kstd/kstd/system_error.tests.cpp b/libs/kstd/kstd/system_error.tests.cpp
new file mode 100644
index 00000000..59e11926
--- /dev/null
+++ b/libs/kstd/kstd/system_error.tests.cpp
@@ -0,0 +1,100 @@
+#include <kstd/system_error.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/generators/catch_generators.hpp>
+
+SCENARIO("Error condition initialization and construction", "[kstd][system_error]")
+{
+ GIVEN("An empty context")
+ {
+ WHEN("constructing by default")
+ {
+ auto error = kstd::error_condition{};
+
+ THEN("the category is equal to generic_category")
+ {
+ REQUIRE(error.category() == kstd::generic_category());
+ }
+
+ THEN("the value is 0")
+ {
+ REQUIRE(error.value() == 0);
+ }
+
+ THEN("conversion to bool yields false")
+ {
+ REQUIRE_FALSE(error);
+ }
+ }
+ }
+}
+
+SCENARIO("Error code initialization and construction", "[kstd][system_error]")
+{
+ GIVEN("An empty context")
+ {
+ WHEN("constructing by default")
+ {
+ auto error = kstd::error_code{};
+
+ THEN("the category is equal to system_category")
+ {
+ REQUIRE(error.category() == kstd::system_category());
+ }
+
+ THEN("the value is 0")
+ {
+ REQUIRE(error.value() == 0);
+ }
+
+ THEN("conversion to bool yields false")
+ {
+ REQUIRE_FALSE(error);
+ }
+ }
+ }
+}
+
+SCENARIO("Error code messages", "[kstd][system_error]")
+{
+ GIVEN("An error code")
+ {
+ auto enumerator = GENERATE(
+ kstd::errc::address_family_not_supported, kstd::errc::address_in_use, kstd::errc::address_not_available,
+ kstd::errc::already_connected, kstd::errc::argument_list_too_long, kstd::errc::argument_out_of_domain,
+ kstd::errc::bad_address, kstd::errc::bad_file_descriptor, kstd::errc::bad_message, kstd::errc::broken_pipe,
+ kstd::errc::connection_aborted, kstd::errc::connection_already_in_progress, kstd::errc::connection_refused,
+ kstd::errc::connection_reset, kstd::errc::cross_device_link, kstd::errc::destination_address_required,
+ kstd::errc::device_or_resource_busy, kstd::errc::directory_not_empty, kstd::errc::executable_format_error,
+ kstd::errc::file_exists, kstd::errc::file_too_large, kstd::errc::filename_too_long,
+ kstd::errc::function_not_supported, kstd::errc::host_unreachable, kstd::errc::identifier_removed,
+ kstd::errc::illegal_byte_sequence, kstd::errc::inappropriate_io_control_operation, kstd::errc::interrupted,
+ kstd::errc::invalid_argument, kstd::errc::invalid_seek, kstd::errc::io_error, kstd::errc::is_a_directory,
+ kstd::errc::message_size, kstd::errc::network_down, kstd::errc::network_reset, kstd::errc::network_unreachable,
+ kstd::errc::no_buffer_space, kstd::errc::no_child_process, kstd::errc::no_link, kstd::errc::no_lock_available,
+ kstd::errc::no_message, kstd::errc::no_protocol_option, kstd::errc::no_space_on_device,
+ kstd::errc::no_such_device_or_address, kstd::errc::no_such_device, kstd::errc::no_such_file_or_directory,
+ kstd::errc::no_such_process, kstd::errc::not_a_directory, kstd::errc::not_a_socket, kstd::errc::not_connected,
+ kstd::errc::not_enough_memory, kstd::errc::not_supported, kstd::errc::operation_canceled,
+ kstd::errc::operation_in_progress, kstd::errc::operation_not_permitted, kstd::errc::operation_not_supported,
+ kstd::errc::operation_would_block, kstd::errc::owner_dead, kstd::errc::permission_denied,
+ kstd::errc::protocol_error, kstd::errc::protocol_not_supported, kstd::errc::read_only_file_system,
+ kstd::errc::resource_deadlock_would_occur, kstd::errc::resource_unavailable_try_again,
+ kstd::errc::result_out_of_range, kstd::errc::state_not_recoverable, kstd::errc::text_file_busy,
+ kstd::errc::timed_out, kstd::errc::too_many_files_open_in_system, kstd::errc::too_many_files_open,
+ kstd::errc::too_many_links, kstd::errc::too_many_symbolic_link_levels, kstd::errc::value_too_large,
+ kstd::errc::wrong_protocol_type);
+
+ auto error = kstd::make_error_code(enumerator);
+
+ WHEN("getting the message")
+ {
+ auto message = error.message();
+
+ THEN("the message is not 'unknown error'")
+ {
+ REQUIRE(message != "unknown error");
+ }
+ }
+ }
+}
diff --git a/libs/kstd/kstd/test_support/os_panic.test.cpp b/libs/kstd/kstd/test_support/os_panic.tests.cpp
index c30411aa..c30411aa 100644
--- a/libs/kstd/kstd/test_support/os_panic.test.cpp
+++ b/libs/kstd/kstd/test_support/os_panic.tests.cpp
diff --git a/libs/kstd/kstd/unikstd.h b/libs/kstd/kstd/unikstd.h
deleted file mode 100644
index aa60be63..00000000
--- a/libs/kstd/kstd/unikstd.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef KSTD_UNIKSTD_HPP
-#define KSTD_UNIKSTD_HPP
-
-#include <cstddef>
-#include <type_traits>
-
-namespace kstd
-{
- using ssize_t = std::make_signed_t<std::size_t>;
-} // namespace kstd
-
-#endif \ No newline at end of file
diff --git a/libs/kstd/kstd/units b/libs/kstd/kstd/units.hpp
index df5eb374..df5eb374 100644
--- a/libs/kstd/kstd/units
+++ b/libs/kstd/kstd/units.hpp
diff --git a/libs/kstd/kstd/vector b/libs/kstd/kstd/vector.hpp
index 736b854d..d6ad232a 100644
--- a/libs/kstd/kstd/vector
+++ b/libs/kstd/kstd/vector.hpp
@@ -1,10 +1,10 @@
#ifndef KSTD_VECTOR_HPP
#define KSTD_VECTOR_HPP
-#include <kstd/allocator>
+#include <kstd/allocator.hpp>
#include <kstd/bits/concepts.hpp>
#include <kstd/os/error.hpp>
-#include <kstd/ranges>
+#include <kstd/ranges.hpp>
#include <algorithm>
#include <concepts>
@@ -107,6 +107,7 @@ namespace kstd
//! @tparam ForwardIterator An iterator type used to describe the source range.
//! @param first The start of the source range.
//! @param last The end of the source range.
+ //! @param allocator The allocator to use in the vector.
template<std::forward_iterator ForwardIterator>
constexpr vector(ForwardIterator first, ForwardIterator last,
allocator_type const & allocator =
@@ -127,6 +128,7 @@ namespace kstd
//! @tparam InputIterator An iterator type used to describe the source range.
//! @param first The start of the source range.
//! @param last The end of the source range.
+ //! @param allocator The allocator to use in the vector.
template<std::input_iterator InputIterator>
constexpr vector(InputIterator first, InputIterator last,
allocator_type const & allocator =
@@ -228,6 +230,7 @@ namespace kstd
//! Construct a new vector and initialize it's content by copying all elements in the given initializer list.
//!
//! @param list The initializer list containing the source objects.
+ //! @param allocator The allocator to use in the vector.
vector(std::initializer_list<value_type> list, allocator_type const & allocator = allocator_type{})
: vector{std::ranges::begin(list), std::ranges::end(list), allocator}
{}
@@ -639,6 +642,7 @@ namespace kstd
//! Insert the element of a given range into the vector at a given position.
//!
+ //! @param position The position where to insert the elements.
//! @param range The source range to insert elements from.
//! @tparam SourceRange A container compatible range type.
template<typename SourceRange>
diff --git a/libs/kstd/kstd/vector.test.cpp b/libs/kstd/kstd/vector.tests.cpp
index 8bf8f79d..72c1127a 100644
--- a/libs/kstd/kstd/vector.test.cpp
+++ b/libs/kstd/kstd/vector.tests.cpp
@@ -1,6 +1,6 @@
-#include <kstd/vector>
+#include <kstd/vector.hpp>
-#include <kstd/ranges>
+#include <kstd/ranges.hpp>
#include <kstd/test_support/os_panic.hpp>
#include <kstd/test_support/test_types.hpp>