aboutsummaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-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
4 files changed, 156 insertions, 4 deletions
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")