diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-06-02 17:32:08 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-06-02 17:32:08 +0200 |
| commit | 3274bb4377b9f04b7a70139a86283e0fae44b228 (patch) | |
| tree | face2b0b544578e5efd1c28c8d75b3307d6e4a8a | |
| parent | e92df52c599f78f36a278508a2b6be5f3a15f3db (diff) | |
| parent | 46d3f8978e9f4235064daf5f19de5bf3054e7c24 (diff) | |
| download | kernel-3274bb4377b9f04b7a70139a86283e0fae44b228.tar.xz kernel-3274bb4377b9f04b7a70139a86283e0fae44b228.zip | |
Merge branch 'fmorgner/develop-BA-FS26/dynamic-fs' into 'develop-BA-FS26'
Add support infrastructure for automatic file system registration
See merge request teachos/kernel!46
| -rw-r--r-- | arch/x86_64/scripts/kernel.ld | 6 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | kernel/include/kernel/filesystem/type.hpp | 42 | ||||
| -rw-r--r-- | kernel/include/kernel/filesystem/type_registry.hpp | 53 | ||||
| -rw-r--r-- | kernel/include/kernel/filesystem/vfs.hpp | 7 | ||||
| -rw-r--r-- | kernel/kapi/filesystem.cpp | 2 | ||||
| -rw-r--r-- | kernel/src/filesystem/dentry.cpp | 2 | ||||
| -rw-r--r-- | kernel/src/filesystem/devfs/filesystem.cpp | 22 | ||||
| -rw-r--r-- | kernel/src/filesystem/ext2/filesystem.cpp | 23 | ||||
| -rw-r--r-- | kernel/src/filesystem/rootfs/filesystem.cpp | 25 | ||||
| -rw-r--r-- | kernel/src/filesystem/type_registry.cpp | 72 | ||||
| -rw-r--r-- | kernel/src/filesystem/type_registry.tests.cpp | 77 | ||||
| -rw-r--r-- | kernel/src/filesystem/vfs.cpp | 14 | ||||
| -rw-r--r-- | kernel/src/filesystem/vfs.tests.cpp | 32 | ||||
| -rw-r--r-- | kernel/src/main.cpp | 4 | ||||
| -rw-r--r-- | libs/acpi/acpi/common/basic_table.hpp | 5 | ||||
| -rw-r--r-- | libs/acpi/acpi/common/vla_table.hpp | 5 | ||||
| -rw-r--r-- | libs/kstd/kstd/flat_map | 16 | ||||
| -rw-r--r-- | libs/kstd/kstd/flat_map.test.cpp | 10 | ||||
| -rw-r--r-- | libs/kstd/kstd/string | 105 | ||||
| -rw-r--r-- | libs/kstd/kstd/string.test.cpp | 44 |
21 files changed, 455 insertions, 113 deletions
diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index a429570..dbb0f8f 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -72,6 +72,12 @@ SECTIONS .kernel_rodata ALIGN(4K) : AT (ADDR (.kernel_rodata) - TEACHOS_VMA) { *(.rodata*) + + . = ALIGN(8); + + PROVIDE(__start_fs_types = .); + KEEP(*(fs_types)); + PROVIDE(__stop_fs_types = .); } :kernel_rodata .kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index cbc7fa5..2388370 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -53,6 +53,7 @@ target_sources("kernel_lib" PRIVATE "src/filesystem/mount.cpp" "src/filesystem/open_file_descriptor.cpp" "src/filesystem/open_file_table.cpp" + "src/filesystem/type_registry.cpp" "src/filesystem/vfs.cpp" # DevFS Filesystem @@ -200,6 +201,7 @@ if(BUILD_TESTING) "src/filesystem/mount.tests.cpp" "src/filesystem/open_file_descriptor.tests.cpp" "src/filesystem/open_file_table.tests.cpp" + "src/filesystem/type_registry.tests.cpp" "src/filesystem/vfs.tests.cpp" # Storage Subsystem Tests diff --git a/kernel/include/kernel/filesystem/type.hpp b/kernel/include/kernel/filesystem/type.hpp new file mode 100644 index 0000000..0948e54 --- /dev/null +++ b/kernel/include/kernel/filesystem/type.hpp @@ -0,0 +1,42 @@ +#ifndef TEACH_OS_KERNEL_FILESYSTEM_TYPE_HPP +#define TEACH_OS_KERNEL_FILESYSTEM_TYPE_HPP + +#include <kernel/filesystem/filesystem.hpp> + +#include <kstd/memory> + +#include <string_view> + +namespace kernel::filesystem +{ + + //! A type descriptor for a filesystem driver. + //! + //! Each filesystem must expose an instance of a class derived from this type in order to be registered with the vfs + //! filesystem registry. + struct type + { + virtual ~type() = default; + + //! Get the name of the filesystem represented by this descriptor. + [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; + + //! Check if filesystems of this type require a device to back them. + [[nodiscard]] virtual auto requires_device() const noexcept -> bool = 0; + + //! Create a new instance of the filesytem represented by this descriptor. + [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr<filesystem> = 0; + }; + + template<typename Type> + struct type_registration + { + constexpr auto static instance = Type{}; + [[using gnu: section("fs_types"), used, visibility("hidden")]] constexpr auto static pointer{ + kstd::make_observer<type const>(&instance), + }; + }; + +} // namespace kernel::filesystem + +#endif diff --git a/kernel/include/kernel/filesystem/type_registry.hpp b/kernel/include/kernel/filesystem/type_registry.hpp new file mode 100644 index 0000000..3be7295 --- /dev/null +++ b/kernel/include/kernel/filesystem/type_registry.hpp @@ -0,0 +1,53 @@ +#ifndef TEACH_OS_KERNEL_TYPE_REGISRY_HPP +#define TEACH_OS_KERNEL_TYPE_REGISRY_HPP + +#include <kernel/filesystem/type.hpp> + +#include <kstd/flat_map> +#include <kstd/memory> +#include <kstd/string> + +#include <cstddef> +#include <span> +#include <string_view> + +namespace kernel::filesystem +{ + + struct type_registry + { + using value_type = type; + using pointer = kstd::observer_ptr<value_type const>; + + auto static init() -> void; + auto static get() -> type_registry &; + + constexpr type_registry() noexcept = default; + + //! Add a type descriptor to this registry. + //! + //! This function will register the given descriptor with this registry, given that no descriptor for a filesystem + //! with the same name exists in this registry already. + //! + //! @param descriptor The filesystem type descriptor to add to the registry. + //! @return @p true iff. the descriptor was successfully added, @p false if not. + auto add(pointer descriptor) -> bool; + + //! Get all currently registered type descriptors. + //! + //! @return A span containing all currently registered filesystem type descriptors. + [[nodiscard]] auto all() const noexcept -> std::span<pointer const>; + + //! Get the number of registered filesystem types. + //! + //! @return The number of filesystem descriptors currently registered with this registry. + [[nodiscard]] auto size() const noexcept -> std::size_t; + + private: + //! A map from filesystem names (identifiers) to filesystem type descriptors. + kstd::flat_map<std::string_view, pointer> m_descriptors{}; + }; + +} // namespace kernel::filesystem + +#endif diff --git a/kernel/include/kernel/filesystem/vfs.hpp b/kernel/include/kernel/filesystem/vfs.hpp index e6f2327..ddc9a9b 100644 --- a/kernel/include/kernel/filesystem/vfs.hpp +++ b/kernel/include/kernel/filesystem/vfs.hpp @@ -35,6 +35,8 @@ namespace kernel::filesystem invalid_filesystem = -5 }; + vfs(); + /** @brief Initialize the virtual filesystem. @warning Panics if the VFS has already been initialized. @@ -83,9 +85,6 @@ namespace kernel::filesystem auto unmount(std::string_view path) -> operation_result; private: - vfs() = default; - auto init_internal() -> void; - /** * Note: Resolving a dentry requires traversing mount points; since the * associated 'mount' object is discovered as a byproduct of this @@ -107,7 +106,7 @@ namespace kernel::filesystem auto graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void; - mount_table m_mount_table; + mount_table m_mount_table{}; }; } // namespace kernel::filesystem diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp index 838d2cb..68b51c9 100644 --- a/kernel/kapi/filesystem.cpp +++ b/kernel/kapi/filesystem.cpp @@ -45,7 +45,7 @@ namespace kapi::filesystem { if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) { - if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->absolute_path().view()) == + if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->absolute_path()) == kernel::filesystem::vfs::operation_result::success) { return kernel::filesystem::open_file_table::get().remove_file(file_descriptor); diff --git a/kernel/src/filesystem/dentry.cpp b/kernel/src/filesystem/dentry.cpp index 14de875..3d8e01a 100644 --- a/kernel/src/filesystem/dentry.cpp +++ b/kernel/src/filesystem/dentry.cpp @@ -41,7 +41,7 @@ namespace kernel::filesystem auto dentry::name() const -> std::string_view { - return m_name.view(); + return m_name; } auto dentry::absolute_path() const -> kstd::string diff --git a/kernel/src/filesystem/devfs/filesystem.cpp b/kernel/src/filesystem/devfs/filesystem.cpp index f0d8bf7..ce887ff 100644 --- a/kernel/src/filesystem/devfs/filesystem.cpp +++ b/kernel/src/filesystem/devfs/filesystem.cpp @@ -5,6 +5,7 @@ #include <kernel/filesystem/devfs/inode.hpp> #include <kernel/filesystem/device_inode.hpp> #include <kernel/filesystem/inode.hpp> +#include <kernel/filesystem/type.hpp> #include <kapi/devices/device.hpp> @@ -15,6 +16,27 @@ namespace kernel::filesystem::devfs { + struct type final : kernel::filesystem::type + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "devfs"; + } + + [[nodiscard]] auto requires_device() const noexcept -> bool override + { + return false; + } + + [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override + { + return kstd::make_shared<filesystem>(); + } + }; + + [[gnu::used]] + constexpr auto registration = type_registration<type>{}; + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result { m_root_inode = kstd::make_shared<inode>(); diff --git a/kernel/src/filesystem/ext2/filesystem.cpp b/kernel/src/filesystem/ext2/filesystem.cpp index 12aeaaa..3180a19 100644 --- a/kernel/src/filesystem/ext2/filesystem.cpp +++ b/kernel/src/filesystem/ext2/filesystem.cpp @@ -6,6 +6,7 @@ #include <kernel/filesystem/ext2/superblock.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> +#include <kernel/filesystem/type.hpp> #include <kstd/memory> #include <kstd/unikstd.h> @@ -18,6 +19,28 @@ namespace kernel::filesystem::ext2 { + + struct type final : kernel::filesystem::type + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] auto requires_device() const noexcept -> bool override + { + return true; + } + + [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override + { + return kstd::make_shared<filesystem>(); + } + }; + + [[gnu::used]] + constexpr auto registration = type_registration<type>{}; + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result { kernel::filesystem::filesystem::mount(backing_inode); diff --git a/kernel/src/filesystem/rootfs/filesystem.cpp b/kernel/src/filesystem/rootfs/filesystem.cpp index 0ba2936..7fe5c1e 100644 --- a/kernel/src/filesystem/rootfs/filesystem.cpp +++ b/kernel/src/filesystem/rootfs/filesystem.cpp @@ -1,8 +1,9 @@ #include <kernel/filesystem/rootfs/filesystem.hpp> -#include "kernel/filesystem/filesystem.hpp" +#include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> #include <kernel/filesystem/rootfs/inode.hpp> +#include <kernel/filesystem/type.hpp> #include <kstd/memory> @@ -10,6 +11,28 @@ namespace kernel::filesystem::rootfs { + + struct type final : kernel::filesystem::type + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "rootfs"; + } + + [[nodiscard]] auto requires_device() const noexcept -> bool override + { + return true; + } + + [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override + { + return kstd::make_shared<filesystem>(); + } + }; + + [[gnu::used]] + constexpr auto registration = type_registration<type>{}; + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result { m_root_inode = kstd::make_shared<inode>(); diff --git a/kernel/src/filesystem/type_registry.cpp b/kernel/src/filesystem/type_registry.cpp new file mode 100644 index 0000000..d917c81 --- /dev/null +++ b/kernel/src/filesystem/type_registry.cpp @@ -0,0 +1,72 @@ +#include <kernel/filesystem/type_registry.hpp> + +#include <kapi/system.hpp> + +#include <kstd/memory> +#include <kstd/print> + +#include <algorithm> +#include <cstddef> +#include <optional> +#include <ranges> +#include <span> + +namespace kernel::filesystem +{ + + extern "C" + { + extern type_registry::pointer const __start_fs_types; + extern type_registry::pointer const __stop_fs_types; + } + + namespace + { + auto constinit instance = std::optional<type_registry>{}; + } + + auto type_registry::init() -> void + { + if (instance) + { + kapi::system::panic("[FILESYSTEM] tried to initialize type registry more than once!"); + } + + instance.emplace(); + + auto type_descriptors = std::span{&__start_fs_types, &__stop_fs_types} | // + std::views::filter([](auto p) { return p != nullptr; }); + + std::ranges::for_each(type_descriptors, [](auto descriptor) { + kstd::println("[FILESYSTEM] registering '{}'", descriptor->name()); + instance->add(descriptor); + }); + } + + auto type_registry::get() -> type_registry & + { + if (!instance) + { + kapi::system::panic("[FILESYSTEM] type registry has not been initialized!"); + } + + return *instance; + } + + auto type_registry::add(pointer descriptor) -> bool + { + auto result = m_descriptors.emplace(descriptor->name(), descriptor); + return result.second; + } + + auto type_registry::all() const noexcept -> std::span<pointer const> + { + return {m_descriptors.values().begin(), m_descriptors.values().end()}; + } + + auto type_registry::size() const noexcept -> std::size_t + { + return m_descriptors.size(); + } + +} // namespace kernel::filesystem diff --git a/kernel/src/filesystem/type_registry.tests.cpp b/kernel/src/filesystem/type_registry.tests.cpp new file mode 100644 index 0000000..8382579 --- /dev/null +++ b/kernel/src/filesystem/type_registry.tests.cpp @@ -0,0 +1,77 @@ +#include <kernel/filesystem/type_registry.hpp> + +#include <kernel/filesystem/filesystem.hpp> +#include <kernel/filesystem/type.hpp> + +#include <kstd/memory> + +#include <catch2/catch_test_macros.hpp> + +#include <iterator> +#include <string_view> + +struct test_type final : kernel::filesystem::type +{ + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "bht_testfs"; + } + + [[nodiscard]] auto requires_device() const noexcept -> bool override + { + return false; + } + + [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override + { + return nullptr; + } +}; + +SCENARIO("Filesystem type registry initialization and construction", "[filesystem]") +{ + GIVEN("A default constructed type_registry") + { + auto instance = kernel::filesystem::type_registry{}; + + WHEN("getting the span of filesystem descriptors") + { + auto descriptors = instance.all(); + + THEN("the span is empty") + { + REQUIRE(descriptors.empty()); + } + } + } +} + +SCENARIO("Filesystem type registry modifiers", "[filesystem]") +{ + GIVEN("A default constructed type_registry") + { + auto instance = kernel::filesystem::type_registry{}; + + WHEN("adding a type descriptor") + { + auto descriptor = test_type{}; + + instance.add(kstd::make_observer(&descriptor)); + + THEN("the size of the registry is one") + { + REQUIRE(instance.size() == 1); + } + + THEN("the span is not empty") + { + REQUIRE_FALSE(instance.all().empty()); + } + + THEN("the span's size is equal to the registry size") + { + REQUIRE(std::size(instance.all()) == std::size(instance)); + } + } + } +} diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp index ae85291..e5dff8c 100644 --- a/kernel/src/filesystem/vfs.cpp +++ b/kernel/src/filesystem/vfs.cpp @@ -12,7 +12,6 @@ #include <kapi/system.hpp> #include <kstd/memory> -#include <kstd/string> #include <kstd/vector> #include <algorithm> @@ -36,11 +35,10 @@ namespace kernel::filesystem kapi::system::panic("[FILESYSTEM] vfs has already been initialized."); } - active_vfs.emplace(vfs{}); - active_vfs->init_internal(); + active_vfs.emplace(); } - auto vfs::init_internal() -> void + vfs::vfs() { // mount rootfs at / auto root_fs = kstd::make_shared<rootfs::filesystem>(); @@ -226,22 +224,22 @@ namespace kernel::filesystem continue; } - auto next_dentry = current_dentry->find_child(part.view()); + auto next_dentry = current_dentry->find_child(part); if (!next_dentry) { auto current_fs = current_mount->get_filesystem(); - auto found_inode = current_fs->lookup(current_dentry->get_inode(), part.view()); + auto found_inode = current_fs->lookup(current_dentry->get_inode(), part); if (!found_inode) { return {nullptr, nullptr}; } - next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part.view()); + next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part); current_dentry->add_child(next_dentry); } else if (next_dentry->has_flag(dentry::dentry_flags::is_mount_point)) { - current_mount = m_mount_table.find_mount(next_dentry->absolute_path().view()); + current_mount = m_mount_table.find_mount(next_dentry->absolute_path()); if (!current_mount) { kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found."); diff --git a/kernel/src/filesystem/vfs.tests.cpp b/kernel/src/filesystem/vfs.tests.cpp index 962e067..f1d0df0 100644 --- a/kernel/src/filesystem/vfs.tests.cpp +++ b/kernel/src/filesystem/vfs.tests.cpp @@ -106,8 +106,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); REQUIRE(mounted_monkey_1 != nullptr); - REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); @@ -129,9 +128,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS REQUIRE(mounted_monkey_1 != nullptr); REQUIRE(mounted_fish1 != nullptr); - REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) == - kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.close(mounted_fish1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_fish1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") == @@ -148,8 +146,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); - REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); } @@ -165,8 +162,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); - REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); - REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path().view()), std::runtime_error); + REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path()), std::runtime_error); } THEN("images can be stacked mounted and correct file system is unmounted again") @@ -177,7 +174,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto mounted_tickets = vfs.open("/information/entrance/tickets.txt"); REQUIRE(mounted_tickets != nullptr); - REQUIRE(vfs.close(mounted_tickets->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_tickets->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); mounted_tickets = vfs.open("/information/entrance/tickets.txt"); @@ -200,7 +197,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto water = vfs.open("/monkey_house/infrastructure/water.txt"); REQUIRE(water != nullptr); - REQUIRE(vfs.close(water->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success); @@ -221,7 +218,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto water = vfs.open("/monkey_house/infrastructure/water.txt"); REQUIRE(water != nullptr); - REQUIRE(vfs.close(water->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success); auto dev_ram_16 = vfs.open("/dev/ram16"); REQUIRE(dev_ram_16 == nullptr); @@ -239,7 +236,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); - REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/dev") == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success); @@ -362,7 +359,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read}; REQUIRE(buffer_as_str == "sheep_1"); - REQUIRE(vfs.close(dentry->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(dentry->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt"); @@ -395,8 +392,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS buffer_as_str = std::string_view{reinterpret_cast<char *>(goat_buffer.data()), bytes_read}; REQUIRE(buffer_as_str == "goat_1"); - REQUIRE(vfs.close(sheep_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.close(goat_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(goat_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); @@ -407,8 +404,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto still_mounted_sheep_1 = vfs.open("/information/sheep_1.txt"); REQUIRE(still_mounted_sheep_1 != nullptr); - REQUIRE(vfs.close(still_mounted_sheep_1->absolute_path().view()) == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(still_mounted_sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt"); diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 6985e94..8dc1349 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -1,3 +1,4 @@ +#include "kernel/filesystem/type_registry.hpp" #include <kernel/devices/storage/management.hpp> #include <kernel/filesystem/open_file_table.hpp> #include <kernel/filesystem/vfs.hpp> @@ -138,6 +139,9 @@ auto main() -> int kernel::filesystem::open_file_table::init(); kstd::println("[OS] Global open file table initialized."); + kernel::filesystem::type_registry::init(); + kstd::println("[OS] Builtin filesystems registered."); + kernel::filesystem::vfs::init(); kstd::println("[OS] Virtual filesystem initialized."); diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp index 33f23d5..f5b5b27 100644 --- a/libs/acpi/acpi/common/basic_table.hpp +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -28,6 +28,11 @@ namespace acpi { return signature() == table_signature_v<TableType> && validate_checksum(); } + + private: + friend TableType; + + constexpr basic_table() noexcept = default; }; } // namespace acpi diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp index a65a28e..d3f33a7 100644 --- a/libs/acpi/acpi/common/vla_table.hpp +++ b/libs/acpi/acpi/common/vla_table.hpp @@ -109,6 +109,11 @@ namespace acpi { return end(); } + + private: + friend TableType; + + constexpr vla_table() noexcept = default; }; } // namespace acpi diff --git a/libs/kstd/kstd/flat_map b/libs/kstd/kstd/flat_map index f12b1b5..943e9fc 100644 --- a/libs/kstd/kstd/flat_map +++ b/libs/kstd/kstd/flat_map @@ -356,6 +356,22 @@ namespace kstd return find(key) != cend(); } + //! Get a reference to the keys container. + //! + //! @return a reference to the keys container. + [[nodiscard]] constexpr auto keys() const noexcept -> key_container_type const & + { + return m_containers.keys; + } + + //! Get a reference to the values container. + //! + //! @return a reference to the values container. + [[nodiscard]] constexpr auto values() const noexcept -> mapped_container_type const & + { + return m_containers.values; + } + private: containers m_containers; key_compare m_comparator; diff --git a/libs/kstd/kstd/flat_map.test.cpp b/libs/kstd/kstd/flat_map.test.cpp index 2e5a47c..6c57173 100644 --- a/libs/kstd/kstd/flat_map.test.cpp +++ b/libs/kstd/kstd/flat_map.test.cpp @@ -20,6 +20,16 @@ SCENARIO("Flat Map initialization and construction", "[flat_map]") { REQUIRE_FALSE(map.contains(1)); } + + THEN("the keys container is empty") + { + REQUIRE(map.keys().empty()); + } + + THEN("the values container is empty") + { + REQUIRE(map.values().empty()); + } } } } diff --git a/libs/kstd/kstd/string b/libs/kstd/kstd/string index e228a04..9343b42 100644 --- a/libs/kstd/kstd/string +++ b/libs/kstd/kstd/string @@ -9,6 +9,7 @@ #include <kstd/vector> #include <algorithm> +#include <compare> #include <concepts> #include <cstddef> #include <string_view> @@ -52,7 +53,7 @@ namespace kstd * @brief Constructs a string from a string view by copying the characters into owned storage. * @param view The string view to copy the characters from. */ - string(std::string_view view) + explicit string(std::string_view view) : string() { append(view); @@ -101,6 +102,26 @@ namespace kstd */ constexpr auto operator=(string const & other) -> string & = default; + constexpr auto operator=(std::string_view const & other) -> string & + { + clear(); + append(other); + return *this; + } + + constexpr auto operator=(char const * other) -> string & + { + clear(); + append(std::string_view{other}); + return *this; + } + + //! Create a string view from this string. + constexpr operator std::string_view() const noexcept + { + return {data(), size()}; + } + /** * @brief Returns the number of characters in this string, not including the null terminator. */ @@ -224,6 +245,7 @@ namespace kstd { if (!view.empty()) { + m_storage.reserve(size() + view.size() + 1); std::ranges::for_each(view, [this](auto const ch) { push_back(ch); }); } @@ -237,7 +259,7 @@ namespace kstd */ constexpr auto append(string const & other) -> string & { - return append(other.view()); + return append(static_cast<std::string_view>(other)); } /** @@ -261,12 +283,29 @@ namespace kstd return *this; } - /** - * @brief Returns a string view of this string, which is a non-owning view into the characters of this string. - */ - [[nodiscard]] constexpr auto view() const noexcept -> std::string_view + //! Compare this string lexicographically to another string. + //! + //! @param other The string to compare to this one. + [[nodiscard]] constexpr auto operator<=>(string const & other) const noexcept -> std::strong_ordering = default; + + [[nodiscard]] constexpr auto operator==(string const & other) const noexcept -> bool = default; + + //! Compare this string lexicographically to a C-style string. + //! + //! @param other The C-style string to compare to this one. + //! @return The result of the comparison. + [[nodiscard]] constexpr auto operator<=>(char const * other) const noexcept + { + return static_cast<std::string_view>(*this) <=> other; + } + + //! Check if this string compares equal to a C-style string. + //! + //! @param other The C-style string to compare to this one. + //! @return @p true iff. this string compares equal to @p other, @p false otherwise. + [[nodiscard]] constexpr auto operator==(char const * other) const noexcept -> bool { - return std::string_view{data(), size()}; + return static_cast<std::string_view>(*this) == other; } private: @@ -316,62 +355,12 @@ namespace kstd return result; } - [[nodiscard]] constexpr auto inline operator==(string const & lhs, string const & rhs) -> bool - { - return lhs.view() == rhs.view(); - } - - [[nodiscard]] constexpr auto inline operator!=(string const & lhs, string const & rhs) -> bool - { - return !(lhs == rhs); - } - - [[nodiscard]] constexpr auto inline operator==(string const & lhs, std::string_view rhs) -> bool - { - return lhs.view() == rhs; - } - - [[nodiscard]] constexpr auto inline operator!=(string const & lhs, std::string_view rhs) -> bool - { - return !(lhs == rhs); - } - - [[nodiscard]] constexpr auto inline operator==(std::string_view lhs, string const & rhs) -> bool - { - return lhs == rhs.view(); - } - - [[nodiscard]] constexpr auto inline operator!=(std::string_view lhs, string const & rhs) -> bool - { - return !(lhs == rhs); - } - - [[nodiscard]] constexpr auto inline operator==(string const & lhs, char const * rhs) -> bool - { - return lhs.view() == std::string_view{rhs}; - } - - [[nodiscard]] constexpr auto inline operator!=(string const & lhs, char const * rhs) -> bool - { - return !(lhs == rhs); - } - - [[nodiscard]] constexpr auto inline operator==(char const * lhs, string const & rhs) -> bool - { - return std::string_view{lhs} == rhs.view(); - } - - [[nodiscard]] constexpr auto inline operator!=(char const * lhs, string const & rhs) -> bool - { - return !(lhs == rhs); - } - template<> struct formatter<string> : formatter<std::string_view> { auto format(string const & str, format_context & context) const -> void { - formatter<std::string_view>::format(str.view(), context); + formatter<std::string_view>::format(static_cast<std::string_view>(str), context); } }; diff --git a/libs/kstd/kstd/string.test.cpp b/libs/kstd/kstd/string.test.cpp index 9755676..b81cd3a 100644 --- a/libs/kstd/kstd/string.test.cpp +++ b/libs/kstd/kstd/string.test.cpp @@ -22,7 +22,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string is empty") { - REQUIRE(str.view() == std::string_view{}); + REQUIRE(str == std::string_view{}); } } } @@ -43,7 +43,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same characters as the view") { - REQUIRE(str.view() == view); + REQUIRE(str == view); } } } @@ -64,7 +64,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same characters as the C-style string") { - REQUIRE(str.view() == c_str); + REQUIRE(str == c_str); } } } @@ -85,7 +85,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same character as the given character") { - REQUIRE(str.view() == std::string_view{&ch, 1}); + REQUIRE(str == std::string_view{&ch, 1}); } } } @@ -100,7 +100,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the new string contains the same characters as the original") { - REQUIRE(str.view() == other.view()); + REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other)); } } @@ -113,7 +113,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same characters as the assigned string") { - REQUIRE(str.view() == other.view()); + REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other)); } } } @@ -129,7 +129,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same characters as the assigned view") { - REQUIRE(str.view() == view); + REQUIRE(str == view); } } } @@ -145,7 +145,7 @@ SCENARIO("String initialization and construction", "[string]") THEN("the string contains the same characters as the assigned C-style string") { - REQUIRE(str.view() == c_str); + REQUIRE(str == c_str); } } } @@ -164,7 +164,7 @@ SCENARIO("String concatenation", "[string]") THEN("the first string contains the characters of both strings concatenated") { - REQUIRE(str1.view() == "Blub Blub"); + REQUIRE(str1 == "Blub Blub"); } THEN("the size of the first string is the sum of the sizes of both strings") @@ -179,7 +179,7 @@ SCENARIO("String concatenation", "[string]") THEN("the first string contains the characters of both strings concatenated") { - REQUIRE(str1.view() == "Blub Blub"); + REQUIRE(str1 == "Blub Blub"); } THEN("the size of the first string is the sum of the sizes of both strings") @@ -194,7 +194,7 @@ SCENARIO("String concatenation", "[string]") THEN("the new string contains the characters of both strings concatenated") { - REQUIRE(str3.view() == "Blub Blub"); + REQUIRE(str3 == "Blub Blub"); } THEN("the size of the new string is the sum of the sizes of both strings") @@ -215,7 +215,7 @@ SCENARIO("String concatenation", "[string]") THEN("the string contains the characters of both the original string and the appended view concatenated") { - REQUIRE(str.view() == "Blub Blub"); + REQUIRE(str == "Blub Blub"); } THEN("the size of the string is the sum of the sizes of the original string and the appended view") @@ -236,7 +236,7 @@ SCENARIO("String concatenation", "[string]") THEN("the string contains the original characters followed by the appended character") { - REQUIRE(str.view() == "Blub!"); + REQUIRE(str == "Blub!"); } THEN("the size of the string is one more than the original size") @@ -251,7 +251,7 @@ SCENARIO("String concatenation", "[string]") THEN("the string contains the original characters followed by the appended character") { - REQUIRE(str.view() == "Blub!"); + REQUIRE(str == "Blub!"); } THEN("the size of the string is one more than the original size") @@ -276,8 +276,8 @@ SCENARIO("String conversion and comparison", "[string]") THEN("the string contains the decimal representation of the unsigned integer") { - REQUIRE(str1.view() == "12345"); - REQUIRE(str2.view() == "0"); + REQUIRE(str1 == "12345"); + REQUIRE(str2 == "0"); } } } @@ -335,7 +335,7 @@ SCENARIO("String clearing", "[string]") THEN("the string contains no characters") { - REQUIRE(str.view() == std::string_view{}); + REQUIRE(str == std::string_view{}); } } } @@ -351,7 +351,7 @@ SCENARIO("String iteration", "[string]") { kstd::string result; - for (auto ch : str.view()) + for (auto ch : static_cast<std::string_view>(str)) { result.push_back(ch); } @@ -396,14 +396,14 @@ SCENARIO("String iteration", "[string]") { kstd::string result; - for (auto ch : str.view()) + for (auto ch : static_cast<std::string_view>(str)) { result.push_back(ch); } THEN("the iterated characters are the same as the characters in the string") { - REQUIRE(result == str.view()); + REQUIRE(result == static_cast<std::string_view>(str)); } } @@ -429,7 +429,7 @@ SCENARIO("String iteration", "[string]") { kstd::string result; - for (auto ch : str.view()) + for (auto ch : static_cast<std::string_view>(str)) { result.push_back(ch); } @@ -438,7 +438,7 @@ SCENARIO("String iteration", "[string]") { REQUIRE(result.empty()); REQUIRE(result.size() == 0); - REQUIRE(result.view() == std::string_view{}); + REQUIRE(static_cast<std::string_view>(result) == std::string_view{}); } } } |
