aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kapi/kapi/system.hpp44
-rw-r--r--kernel/kapi/system.cpp9
-rw-r--r--libs/kstd/kstd/bits/format/formatter/cstring.hpp6
-rw-r--r--libs/kstd/kstd/bits/format/vformat.cpp20
-rw-r--r--libs/kstd/kstd/bits/format/vformat.hpp44
-rw-r--r--libs/kstd/kstd/format.tests.cpp90
6 files changed, 209 insertions, 4 deletions
diff --git a/kapi/kapi/system.hpp b/kapi/kapi/system.hpp
index 8a20af94..f7dd4d7c 100644
--- a/kapi/kapi/system.hpp
+++ b/kapi/kapi/system.hpp
@@ -1,8 +1,15 @@
#ifndef TEACHOS_KAPI_SYSTEM_HPP
#define TEACHOS_KAPI_SYSTEM_HPP
+#include <kstd/format.hpp>
+#include <kstd/system_error.hpp>
+
+#include <array>
+#include <cstddef>
#include <source_location>
+#include <span>
#include <string_view>
+#include <type_traits>
namespace kapi::system
{
@@ -10,6 +17,26 @@ namespace kapi::system
//! @addtogroup kapi-system-kernel-defined
//! @{
+ template<typename... FormatArguments>
+ struct panic_format_string
+ {
+ kstd::format_string<FormatArguments...> format;
+ std::source_location location;
+
+ template<std::size_t Size>
+ consteval panic_format_string(char const (&format)[Size], // NOLINT
+ std::source_location location = std::source_location::current())
+ : format{format}
+ , location{location}
+ {}
+
+ consteval panic_format_string(std::string_view const & format,
+ std::source_location location = std::source_location::current())
+ : format{format}
+ , location{location}
+ {}
+ };
+
//! Terminate kernel execution with the given error message.
//!
//! This function terminates the execution of the kernel and attempts to issue the given error message to the user.
@@ -17,6 +44,14 @@ namespace kapi::system
//! @param message The message associated with the panic
[[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void;
+ //! Termite kernel execution with the given error message and error code.
+ //!
+ //! This function terminates the execution of the kernel and attempts to issue the given error message to the user.
+ //! @param message The message associated with the panic.
+ //! @param error The erro code associated with the panic.
+ [[noreturn]] auto panic(std::string_view message, kstd::error_code error,
+ std::source_location = std::source_location::current()) -> void;
+
//! @} // end group kernel-defined
//! @addtogroup kapi-system-platform-defined
@@ -26,6 +61,15 @@ namespace kapi::system
auto memory_initialized() -> void;
//! @} // end group platform-defined
+ //
+ template<typename... FormatArguments>
+ [[noreturn]] auto panic(panic_format_string<std::type_identity_t<FormatArguments>...> format,
+ FormatArguments &&... arguments)
+ {
+ auto buffer = std::array<char, 512uz>{};
+ auto [_, length] = kstd::format_to(std::span{buffer}, format.format, std::forward<FormatArguments>(arguments)...);
+ panic(std::string_view{buffer.data(), length}, format.location);
+ }
} // namespace kapi::system
diff --git a/kernel/kapi/system.cpp b/kernel/kapi/system.cpp
index 86c99515..23dadd3a 100644
--- a/kernel/kapi/system.cpp
+++ b/kernel/kapi/system.cpp
@@ -3,6 +3,7 @@
#include <kapi/cpu.hpp>
#include <kstd/print.hpp>
+#include <kstd/system_error.hpp>
#include <source_location>
#include <string_view>
@@ -18,4 +19,12 @@ namespace kapi::system
cpu::halt();
}
+ [[gnu::weak]]
+ auto panic(std::string_view message, kstd::error_code error, std::source_location location) -> void
+ {
+ kstd::println(kstd::print_sink::stderr, "[PANIC] in {} : {} ({}:{}) @ {}:{}", location.function_name(), message,
+ error.category().name(), error.message(), location.file_name(), location.line());
+ cpu::halt();
+ }
+
} // namespace kapi::system
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/vformat.cpp b/libs/kstd/kstd/bits/format/vformat.cpp
index 495f0a10..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.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 829e0ea4..63b41ab6 100644
--- a/libs/kstd/kstd/bits/format/vformat.hpp
+++ b/libs/kstd/kstd/bits/format/vformat.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/format.tests.cpp b/libs/kstd/kstd/format.tests.cpp
index d38a8107..a34cf063 100644
--- a/libs/kstd/kstd/format.tests.cpp
+++ b/libs/kstd/kstd/format.tests.cpp
@@ -2,6 +2,7 @@
#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")