diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-12-19 11:46:46 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-12-19 11:46:46 +0100 |
| commit | de96b0588ab680e1002c12df7ea7900d7eb71cf8 (patch) | |
| tree | 41728f4f5c77a4d96dc3d89096483dfee75b3482 | |
| parent | 266dde7d535d997a45f6eef41e44ebcaa516b75a (diff) | |
| download | teachos-de96b0588ab680e1002c12df7ea7900d7eb71cf8.tar.xz teachos-de96b0588ab680e1002c12df7ea7900d7eb71cf8.zip | |
kstd: move println to kstd
| -rw-r--r-- | arch/x86_64/include/x86_64/vga/text.hpp | 20 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 9 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/kernel_mapper.cpp | 5 | ||||
| -rw-r--r-- | arch/x86_64/src/vga/text.cpp | 32 | ||||
| -rw-r--r-- | kapi/include/kapi/cio.hpp | 100 | ||||
| -rw-r--r-- | kapi/include/kapi/cio/output_device.hpp | 24 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | kernel/src/kapi/cio.cpp | 183 | ||||
| -rw-r--r-- | kernel/src/kapi/system.cpp | 7 | ||||
| -rw-r--r-- | kernel/src/kstd/os.cpp (renamed from kernel/src/kstd.cpp) | 0 | ||||
| -rw-r--r-- | kernel/src/kstd/print.cpp | 145 | ||||
| -rw-r--r-- | kernel/src/main.cpp | 6 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/print | 86 |
13 files changed, 313 insertions, 309 deletions
diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index 9f80f94..fcda67f 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -121,25 +121,7 @@ namespace teachos::vga::x86_64::text */ auto cursor(bool enabled) -> void; - auto write(std::string_view text) -> void override - { - write(text, common_attributes::green_on_black); - } - - auto writeln(std::string_view text) -> void override - { - writeln(text, common_attributes::green_on_black); - } - - auto write_error(std::string_view text) -> void override - { - write(text, common_attributes::red_on_black); - } - - auto writeln_error(std::string_view text) -> void override - { - writeln(text, common_attributes::red_on_black); - } + auto write(cio::output_stream stream, std::string_view text) -> void override; private: using glyph = std::pair<char, std::byte>; diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 0a45a51..5234110 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,7 +1,6 @@ #include "kapi/memory.hpp" #include "kapi/boot.hpp" -#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -17,6 +16,8 @@ #include "x86_64/memory/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" +#include <kstd/print> + #include <multiboot2/information.hpp> #include <atomic> @@ -164,7 +165,7 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - cio::println("[x86_64:MEM] Enabling additional CPU protection features."); + kstd::println("[x86_64:MEM] Enabling additional CPU protection features."); enable_cpu_protections(); @@ -172,7 +173,7 @@ namespace teachos::memory buffered_allocator.emplace(&*region_based_allocator); recursive_page_mapper.emplace(*buffered_allocator); - cio::println("[x86_64:MEM] Preparing new paging hierarchy."); + kstd::println("[x86_64:MEM] Preparing new paging hierarchy."); auto new_pml4_frame = inject_faux_pml4(*buffered_allocator, *recursive_page_mapper); @@ -180,7 +181,7 @@ namespace teachos::memory remap_vga_text_mode_buffer(*recursive_page_mapper); remap_multiboot_information(*recursive_page_mapper); - cio::println("[x86_64:MEM] Switching to new paging hierarchy."); + kstd::println("[x86_64:MEM] Switching to new paging hierarchy."); auto cr3 = cpu::x86_64::cr3::read(); cr3.frame(new_pml4_frame); diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index 5295bb3..50fa325 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -1,11 +1,12 @@ #include "x86_64/memory/kernel_mapper.hpp" -#include "kapi/cio.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" #include "x86_64/boot/ld.hpp" +#include <kstd/print> + #include <elf/format.hpp> #include <elf/section_header.hpp> #include <multiboot2/information.hpp> @@ -70,7 +71,7 @@ namespace teachos::memory::x86_64 auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, page_mapper & mapper) -> void { - cio::println("[x86_64:MEM] mapping {} ({} bytes)", name, section.size); + kstd::println("[x86_64:MEM] mapping {} ({} bytes)", name, section.size); auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE; diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index d4548a2..8f6214e 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,6 +1,7 @@ #include "x86_64/vga/text.hpp" #include "kapi/boot.hpp" +#include "kapi/cio.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" @@ -76,6 +77,20 @@ namespace teachos::vga::x86_64::text m_position = (line() - scroll_count) * DEFAULT_TEXT_BUFFER_WIDTH; } + auto device::write(cio::output_stream stream, std::string_view text) -> void + { + auto attributes = [&] -> attribute { + switch (stream) + { + case cio::output_stream::stderr: + return common_attributes::red_on_black; + default: + return common_attributes::green_on_black; + } + }(); + write(text, attributes); + } + auto device::write(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); @@ -87,16 +102,17 @@ namespace teachos::vga::x86_64::text { scroll(); } - buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)}; - }; - auto device::writeln(std::string_view code_points, attribute attribute) -> void - { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); - if (column()) + if (code_point == '\n') { - newline(); + if (column()) + { + newline(); + } + return; } - } + + buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)}; + }; } // namespace teachos::vga::x86_64::text diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp index 98c715b..30619ec 100644 --- a/kapi/include/kapi/cio.hpp +++ b/kapi/include/kapi/cio.hpp @@ -5,10 +5,8 @@ #include <kstd/format> -#include <array> #include <optional> #include <string_view> -#include <type_traits> namespace teachos::cio { @@ -27,79 +25,31 @@ namespace teachos::cio //! @return The previously active output device. auto set_output_device(output_device & device) -> std::optional<output_device *>; - //! @qualifier kernel-defined - //! Print the given text to the currently active output device. - //! - //! @param text The text to print. - auto print(std::string_view text) -> void; - - //! @qualifier kernel-defined - //! Print the given text, including a newline, to the currently active output device. - //! - //! @param text The text to print. - auto println(std::string_view text) -> void; - - //! @qualifier kernel-defined - //! Print the given error text, to the currently active output device. - //! - //! @param text The error text to print. - auto print_error(std::string_view text) -> void; - - //! @qualifier kernel-defined - //! Print the given error text, including a newline, to the currently active output device. - //! - //! @param text The error text to print. - auto println_error(std::string_view text) -> void; - - template<typename... Args> - // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) - auto print(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void - { - auto vprint(std::string_view format, kstd::format_args args) -> void; - auto arguments = std::array{ - kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} - ... - }; - vprint(format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); - } - - template<typename... Args> - // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) - auto println(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void - { - auto vprint(std::string_view format, kstd::format_args args) -> void; - auto arguments = std::array{ - kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} - ... - }; - vprint(format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); - println(""); - } - - template<typename... Args> - // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) - auto print_error(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void - { - auto vprint_error(std::string_view format, kstd::format_args args) -> void; - auto arguments = std::array{ - kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} - ... - }; - vprint_error(format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); - } - - template<typename... Args> - // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) - auto println_error(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void - { - auto vprint_error(std::string_view format, kstd::format_args args) -> void; - auto arguments = std::array{ - kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} - ... - }; - vprint_error(format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); - println_error(""); - } + auto write(output_stream stream, std::string_view text) -> void; + + // //! @qualifier kernel-defined + // //! Print the given text to the currently active output device. + // //! + // //! @param text The text to print. + // auto print(std::string_view text) -> void; + + // //! @qualifier kernel-defined + // //! Print the given text, including a newline, to the currently active output device. + // //! + // //! @param text The text to print. + // auto println(std::string_view text) -> void; + + // //! @qualifier kernel-defined + // //! Print the given error text, to the currently active output device. + // //! + // //! @param text The error text to print. + // auto print_error(std::string_view text) -> void; + + // //! @qualifier kernel-defined + // //! Print the given error text, including a newline, to the currently active output device. + // //! + // //! @param text The error text to print. + // auto println_error(std::string_view text) -> void; } // namespace teachos::cio diff --git a/kapi/include/kapi/cio/output_device.hpp b/kapi/include/kapi/cio/output_device.hpp index 0599906..bbdf6ed 100644 --- a/kapi/include/kapi/cio/output_device.hpp +++ b/kapi/include/kapi/cio/output_device.hpp @@ -8,6 +8,12 @@ namespace teachos::cio { + enum struct output_stream + { + stdout, + stderr, + }; + //! The interface of a device able to perform character output on a platform. struct output_device { @@ -20,23 +26,9 @@ namespace teachos::cio //! Write the given text to the output device. //! + //! @param stream The stream to write to. //! @param text The text to write. - auto virtual write(std::string_view text) -> void = 0; - - //! Write the given text to the output device, appending a newline - //! - //! @param text The text to write. - auto virtual writeln(std::string_view text) -> void = 0; - - //! Write the given error text to the output device. - //! - //! @param text The text to write. - auto virtual write_error(std::string_view text) -> void = 0; - - //! Write the given error text to the output device, appending a newline - //! - //! @param text The text to write. - auto virtual writeln_error(std::string_view text) -> void = 0; + auto virtual write(output_stream stream, std::string_view text) -> void = 0; protected: output_device() = default; diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 6bddf7c..7733c1b 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,7 +1,10 @@ add_executable("kernel" - "src/kstd.cpp" "src/main.cpp" + # KSTD OS Implementation + "src/kstd/os.cpp" + "src/kstd/print.cpp" + # Platform Independent KAPI implementation "src/kapi/cio.cpp" "src/kapi/memory.cpp" diff --git a/kernel/src/kapi/cio.cpp b/kernel/src/kapi/cio.cpp index 500d61e..fd5ad0d 100644 --- a/kernel/src/kapi/cio.cpp +++ b/kernel/src/kapi/cio.cpp @@ -1,10 +1,5 @@ #include "kapi/cio.hpp" -#include <kstd/format> - -#include <array> -#include <cstddef> -#include <iterator> #include <optional> #include <string_view> #include <utility> @@ -16,72 +11,10 @@ namespace teachos::cio struct null_device final : public output_device { null_device static instance; - - auto write(std::string_view) -> void override {} - auto writeln(std::string_view) -> void override {} - - auto write_error(std::string_view) -> void override {} - auto writeln_error(std::string_view) -> void override {} + auto write(output_stream, std::string_view) -> void override {} }; constinit null_device null_device::instance; - - struct write_buffer - { - constexpr auto static size = 128uz; - - write_buffer(write_buffer const &) = delete; - write_buffer(write_buffer &&) = delete; - auto operator=(write_buffer const &) -> write_buffer & = delete; - auto operator=(write_buffer &&) -> write_buffer & = delete; - - explicit write_buffer(output_device * device, bool write_to_error) - : m_device{device} - , m_write_to_error{write_to_error} - {} - - ~write_buffer() noexcept - { - flush(); - } - - auto flush() noexcept -> void - { - if (m_position > 0) - { - std::string_view chunk{m_buffer.data(), m_position}; - if (m_write_to_error) - { - m_device->write_error(chunk); - } - else - { - m_device->write(chunk); - } - m_position = 0; - } - } - - auto static callback(void * object, std::string_view text) -> void - { - auto * self = static_cast<write_buffer *>(object); - for (char const character : text) - { - if (self->m_position >= size) - { - self->flush(); - } - self->m_buffer.at(self->m_position++) = character; - } - } - - private: - output_device * m_device; - bool m_write_to_error; - std::array<char, size> m_buffer{}; - std::size_t m_position{}; - }; - } // namespace // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) @@ -96,117 +29,9 @@ namespace teachos::cio return std::exchange(active_device, &device); } - auto print(std::string_view text) -> void - { - active_device->write(text); - } - - auto println(std::string_view text) -> void - { - active_device->writeln(text); - } - - auto print_error(std::string_view text) -> void - { - active_device->write_error(text); - } - - auto println_error(std::string_view text) -> void - { - active_device->writeln_error(text); - } - - namespace - { - auto static vprint_impl(std::string_view fmt, kstd::format_args args, bool write_to_error) -> void - { - if (!active_device) - return; - - auto writer = write_buffer{active_device, write_to_error}; - auto context = kstd::format_context{.writer = write_buffer::callback, .user_data = &writer}; - - auto current = fmt.begin(); - auto end = fmt.end(); - auto next_automatic_index = 0uz; - - while (current != end) - { - if (*current != '{') - { - auto start = current; - while (current != end && *current != '{') - { - std::advance(current, 1); - } - context.push(std::string_view(start, current - start)); - continue; - } - - if (std::next(current) != end && *(std::next(current)) == '{') - { - context.push('{'); - std::advance(current, 2); - continue; - } - - std::advance(current, 1); - - auto index = 0uz; - if (current != end && *current >= '0' && *current <= '9') - { - while (current != end && *current >= '0' && *current <= '9') - { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) - index = index * 10 + static_cast<std::size_t>(*current - '0'); - std::advance(current, 1); - } - } - else - { - index = next_automatic_index++; - } - - auto remaining_fmt = std::string_view{current, static_cast<std::size_t>(std::distance(current, end))}; - - auto const arg = args.get(index); - if (arg.format) - { - auto const after_specs = arg.format(arg.value, remaining_fmt, context); - auto const consumed = remaining_fmt.size() - after_specs.size(); - std::advance(current, consumed); - } - else - { - context.push("{?}"); - while (current != end && *current != '}') - std::advance(current, 1); - } - - if (current != end && *current == '}') - { - std::advance(current, 1); - } - else - { - context.push("{fmt-err}"); - while (current != end && *current != '}') - std::advance(current, 1); - if (current != end) - std::advance(current, 1); - } - } - } - } // namespace - - auto vprint(std::string_view fmt, kstd::format_args args) -> void - { - vprint_impl(fmt, args, false); - } - - auto vprint_error(std::string_view fmt, kstd::format_args args) -> void + auto write(output_stream stream, std::string_view text) -> void { - vprint_impl(fmt, args, true); + active_device->write(stream, text); } -} // namespace teachos::cio
\ No newline at end of file +} // namespace teachos::cio diff --git a/kernel/src/kapi/system.cpp b/kernel/src/kapi/system.cpp index 1cca82e..cdde049 100644 --- a/kernel/src/kapi/system.cpp +++ b/kernel/src/kapi/system.cpp @@ -1,8 +1,9 @@ #include "kapi/system.hpp" -#include "kapi/cio.hpp" #include "kapi/cpu.hpp" +#include <kstd/print> + #include <source_location> #include <string_view> @@ -12,8 +13,8 @@ namespace teachos::system [[gnu::weak]] auto panic(std::string_view message, std::source_location location) -> void { - cio::println_error("[PANIC] in {} : {} @ {}:{}", location.function_name(), message, location.file_name(), - location.line()); + kstd::println(kstd::print_sink::stderr, "[PANIC] in {} : {} @ {}:{}", location.function_name(), message, + location.file_name(), location.line()); cpu::halt(); } diff --git a/kernel/src/kstd.cpp b/kernel/src/kstd/os.cpp index 41c4d60..41c4d60 100644 --- a/kernel/src/kstd.cpp +++ b/kernel/src/kstd/os.cpp diff --git a/kernel/src/kstd/print.cpp b/kernel/src/kstd/print.cpp new file mode 100644 index 0000000..d2fdafa --- /dev/null +++ b/kernel/src/kstd/print.cpp @@ -0,0 +1,145 @@ +#include "kapi/cio.hpp" + +#include <kstd/format> +#include <kstd/print> + +#include <array> +#include <cstddef> +#include <iterator> +#include <string_view> + +namespace kstd::os +{ + + namespace + { + struct write_buffer + { + using output_stream = teachos::cio::output_stream; + + constexpr auto static size = 128uz; + + write_buffer(write_buffer const &) = delete; + write_buffer(write_buffer &&) = delete; + auto operator=(write_buffer const &) -> write_buffer & = delete; + auto operator=(write_buffer &&) -> write_buffer & = delete; + + explicit write_buffer(output_stream stream) + : m_stream{stream} + {} + + ~write_buffer() noexcept + { + flush(); + } + + auto flush() noexcept -> void + { + if (m_position > 0) + { + std::string_view chunk{m_buffer.data(), m_position}; + teachos::cio::write(m_stream, chunk); + m_position = 0; + } + } + + auto static callback(void * object, std::string_view text) -> void + { + auto * self = static_cast<write_buffer *>(object); + for (char const character : text) + { + if (self->m_position >= size) + { + self->flush(); + } + self->m_buffer.at(self->m_position++) = character; + } + } + + private: + output_stream m_stream; + std::array<char, size> m_buffer{}; + std::size_t m_position{}; + }; + + } // namespace + + auto vprint(print_sink sink, std::string_view format, kstd::format_args args) -> void + { + auto writer = write_buffer{(sink == print_sink::stderr) ? teachos::cio::output_stream::stderr + : teachos::cio::output_stream::stdout}; + auto context = kstd::format_context{.writer = write_buffer::callback, .user_data = &writer}; + + auto current = format.begin(); + auto end = format.end(); + auto next_automatic_index = 0uz; + + while (current != end) + { + if (*current != '{') + { + auto start = current; + while (current != end && *current != '{') + { + std::advance(current, 1); + } + context.push(std::string_view(start, current - start)); + continue; + } + + if (std::next(current) != end && *(std::next(current)) == '{') + { + context.push('{'); + std::advance(current, 2); + continue; + } + + std::advance(current, 1); + + auto index = 0uz; + if (current != end && *current >= '0' && *current <= '9') + { + while (current != end && *current >= '0' && *current <= '9') + { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + index = index * 10 + static_cast<std::size_t>(*current - '0'); + std::advance(current, 1); + } + } + else + { + index = next_automatic_index++; + } + + auto remaining_fmt = std::string_view{current, static_cast<std::size_t>(std::distance(current, end))}; + + auto const arg = args.get(index); + if (arg.format) + { + auto const after_specs = arg.format(arg.value, remaining_fmt, context); + auto const consumed = remaining_fmt.size() - after_specs.size(); + std::advance(current, consumed); + } + else + { + context.push("{?}"); + while (current != end && *current != '}') + std::advance(current, 1); + } + + if (current != end && *current == '}') + { + std::advance(current, 1); + } + else + { + context.push("{fmt-err}"); + while (current != end && *current != '}') + std::advance(current, 1); + if (current != end) + std::advance(current, 1); + } + } + } + +} // namespace kstd::os diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 3394275..f1e5dd0 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -2,13 +2,15 @@ #include "kapi/memory.hpp" #include "kapi/system.hpp" +#include <kstd/print> + auto main() -> int { teachos::cio::init(); - teachos::cio::println("[OS] IO subsystem initialized."); + kstd::println("[OS] IO subsystem initialized."); teachos::memory::init(); - teachos::cio::println("[OS] Memory subsystem initialized."); + kstd::println("[OS] Memory subsystem initialized."); teachos::system::panic("Returning from kernel main!"); } diff --git a/libs/kstd/include/kstd/print b/libs/kstd/include/kstd/print new file mode 100644 index 0000000..df42997 --- /dev/null +++ b/libs/kstd/include/kstd/print @@ -0,0 +1,86 @@ +#ifndef KSTD_PRINT +#define KSTD_PRINT + +#include <kstd/format> + +#include <array> +#include <string_view> +#include <type_traits> + +namespace kstd +{ + + enum struct print_sink + { + stdout, + stderr, + }; + + namespace os + { + auto vprint(print_sink sink, std::string_view format, kstd::format_args args) -> void; + } // namespace os + + //! @qualifier kernel-defined + //! Format the given string using the given arguments and print it to the currently active output device. + //! + //! @param format The format string + //! @param args The arguments to use to place in the format string's placeholders. + template<typename... Args> + // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) + auto print(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void + { + auto arguments = std::array<kstd::format_arg, sizeof...(Args)>{ + kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} + ... + }; + os::vprint(print_sink::stdout, format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); + } + + //! @qualifier kernel-defined + //! Format the given error string using the given arguments and print it to the currently active output device. + //! + //! @param format The format string + //! @param args The arguments to use to place in the format string's placeholders. + template<typename... Args> + // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) + auto print(print_sink sink, kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void + { + auto arguments = std::array<kstd::format_arg, sizeof...(Args)>{ + kstd::format_arg{&args, kstd::format_dispatcher<std::remove_cvref_t<Args>>} + ... + }; + os::vprint(sink, format.str, kstd::format_args{arguments.data(), sizeof...(Args)}); + } + + //! @qualifier kernel-defined + //! Format the given string using the given arguments and print it, including a newline, to the currently active + //! output device. + //! + //! @param format The format string + //! @param args The arguments to use to place in the format string's placeholders. + template<typename... Args> + // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) + auto println(kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void + { + print(format, std::forward<Args>(args)...); + print(print_sink::stdout, "\n"); + } + + //! @qualifier kernel-defined + //! Format the given error string using the given arguments and print it, including a newline, to the currently active + //! output device. + //! + //! @param format The format string + //! @param args The arguments + template<typename... Args> + // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) + auto println(print_sink sink, kstd::format_string<std::type_identity_t<Args>...> format, Args &&... args) -> void + { + print(sink, format, std::forward<Args>(args)...); + print(sink, "\n"); + } + +} // namespace kstd + +#endif
\ No newline at end of file |
