From 9589e79e9990054e8bba08f183dd7b72819d6078 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Jul 2026 20:24:15 +0200 Subject: chore: move system error implementation out of line --- kernel/CMakeLists.txt | 2 + kernel/kernel/filesystem/error.cpp | 103 +++++++++ kernel/kernel/filesystem/error.hpp | 94 +------- kernel/kernel/filesystem/ext2/error.cpp | 92 ++++++++ kernel/kernel/filesystem/ext2/error.hpp | 81 +------ kernel/kernel/filesystem/open_file_descriptor.cpp | 2 - libs/kstd/CMakeLists.txt | 1 + libs/kstd/kstd/system_error.cpp | 233 ++++++++++++++++++++ libs/kstd/kstd/system_error.hpp | 254 +++------------------- 9 files changed, 463 insertions(+), 399 deletions(-) create mode 100644 kernel/kernel/filesystem/error.cpp create mode 100644 kernel/kernel/filesystem/ext2/error.cpp create mode 100644 libs/kstd/kstd/system_error.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 1f7f66c4..7ada841d 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -47,6 +47,7 @@ target_sources("kernel_lib" PRIVATE # Filesystem Subsystem "kernel/filesystem/dentry.cpp" "kernel/filesystem/device_inode.cpp" + "kernel/filesystem/error.cpp" "kernel/filesystem/filesystem.cpp" "kernel/filesystem/inode.cpp" "kernel/filesystem/mount_table.cpp" @@ -61,6 +62,7 @@ target_sources("kernel_lib" PRIVATE "kernel/filesystem/devfs/inode.cpp" # ext2 Filesystem + "kernel/filesystem/ext2/error.cpp" "kernel/filesystem/ext2/filesystem.cpp" "kernel/filesystem/ext2/inode.cpp" diff --git a/kernel/kernel/filesystem/error.cpp b/kernel/kernel/filesystem/error.cpp new file mode 100644 index 00000000..5512a5af --- /dev/null +++ b/kernel/kernel/filesystem/error.cpp @@ -0,0 +1,103 @@ +#include + +#include + +#include + +namespace kernel::filesystem +{ + + namespace + { + struct vfs_category_t final : kstd::error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "vfs"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + switch (static_cast(value)) + { + case vfs_errc::invalid_path: + return "invalid path"; + case vfs_errc::no_such_file_or_directory: + return "no such file or directory"; + case vfs_errc::mount_point_not_found: + return "mount point not found"; + case vfs_errc::mount_busy: + return "mount point is busy"; + case vfs_errc::has_child_mounts: + return "mount point has child mounts"; + case vfs_errc::invalid_filesystem: + return "invalid filesystem"; + case vfs_errc::unmount_failed: + return "unmount failed"; + case vfs_errc::too_many_symbolic_link_levels: + return "too many symbolic link levels"; + case vfs_errc::unsupported_filesystem: + return "unsupported filesystem"; + case vfs_errc::invalid_file_descriptor: + return "invalid file descriptor"; + case vfs_errc::invalid_inode: + return "invalid inode"; + case vfs_errc::not_a_directory: + return "not a directory"; + case vfs_errc::is_a_directory: + return "is a directory"; + case vfs_errc::read_only_file_system: + return "readonly filesystem"; + case vfs_errc::file_exists: + return "file already exists"; + case vfs_errc::no_such_device: + return "no such device"; + default: + return "unknown VFS error"; + } + } + + [[nodiscard]] constexpr auto default_error_condition(int value) const noexcept -> kstd::error_condition override + { + switch (static_cast(value)) + { + case vfs_errc::invalid_path: + case vfs_errc::invalid_filesystem: + case vfs_errc::invalid_inode: + return make_error_condition(kstd::errc::invalid_argument); + case vfs_errc::no_such_file_or_directory: + case vfs_errc::mount_point_not_found: + return make_error_condition(kstd::errc::no_such_file_or_directory); + case kernel::filesystem::vfs_errc::mount_busy: + case kernel::filesystem::vfs_errc::has_child_mounts: + case vfs_errc::unmount_failed: + return make_error_condition(kstd::errc::device_or_resource_busy); + case vfs_errc::too_many_symbolic_link_levels: + return make_error_condition(kstd::errc::too_many_symbolic_link_levels); + case vfs_errc::unsupported_filesystem: + return make_error_condition(kstd::errc::not_supported); + case vfs_errc::invalid_file_descriptor: + return make_error_condition(kstd::errc::bad_file_descriptor); + case vfs_errc::not_a_directory: + return make_error_condition(kstd::errc::not_a_directory); + case vfs_errc::is_a_directory: + return make_error_condition(kstd::errc::is_a_directory); + case vfs_errc::read_only_file_system: + return make_error_condition(kstd::errc::read_only_file_system); + case vfs_errc::file_exists: + return make_error_condition(kstd::errc::file_exists); + case vfs_errc::no_such_device: + return make_error_condition(kstd::errc::no_such_device); + default: + return kstd::error_condition{value, *this}; + } + } + } constexpr vfs_category_instance{}; + } // namespace + + [[nodiscard]] auto vfs_category() noexcept -> kstd::error_category const & + { + return vfs_category_instance; + } + +} // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp index 286d7a24..8c9d9e0b 100644 --- a/kernel/kernel/filesystem/error.hpp +++ b/kernel/kernel/filesystem/error.hpp @@ -3,7 +3,6 @@ #include -#include #include namespace kernel::filesystem @@ -29,98 +28,7 @@ namespace kernel::filesystem no_such_device, }; - namespace detail - { - struct vfs_category_t final : kstd::error_category - { - [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override - { - return "vfs"; - } - - [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override - { - switch (static_cast(value)) - { - case vfs_errc::invalid_path: - return "invalid path"; - case vfs_errc::no_such_file_or_directory: - return "no such file or directory"; - case vfs_errc::mount_point_not_found: - return "mount point not found"; - case vfs_errc::mount_busy: - return "mount point is busy"; - case vfs_errc::has_child_mounts: - return "mount point has child mounts"; - case vfs_errc::invalid_filesystem: - return "invalid filesystem"; - case vfs_errc::unmount_failed: - return "unmount failed"; - case vfs_errc::too_many_symbolic_link_levels: - return "too many symbolic link levels"; - case vfs_errc::unsupported_filesystem: - return "unsupported filesystem"; - case vfs_errc::invalid_file_descriptor: - return "invalid file descriptor"; - case vfs_errc::invalid_inode: - return "invalid inode"; - case vfs_errc::not_a_directory: - return "not a directory"; - case vfs_errc::is_a_directory: - return "is a directory"; - case vfs_errc::read_only_file_system: - return "readonly filesystem"; - case vfs_errc::file_exists: - return "file already exists"; - case vfs_errc::no_such_device: - return "no such device"; - default: - return "unknown VFS error"; - } - } - - [[nodiscard]] constexpr auto default_error_condition(int value) const noexcept -> kstd::error_condition override - { - switch (static_cast(value)) - { - case vfs_errc::invalid_path: - case vfs_errc::invalid_filesystem: - case vfs_errc::invalid_inode: - return make_error_condition(kstd::errc::invalid_argument); - case vfs_errc::no_such_file_or_directory: - case vfs_errc::mount_point_not_found: - return make_error_condition(kstd::errc::no_such_file_or_directory); - case kernel::filesystem::vfs_errc::mount_busy: - case kernel::filesystem::vfs_errc::has_child_mounts: - case vfs_errc::unmount_failed: - return make_error_condition(kstd::errc::device_or_resource_busy); - case vfs_errc::too_many_symbolic_link_levels: - return make_error_condition(kstd::errc::too_many_symbolic_link_levels); - case vfs_errc::unsupported_filesystem: - return make_error_condition(kstd::errc::not_supported); - case vfs_errc::invalid_file_descriptor: - return make_error_condition(kstd::errc::bad_file_descriptor); - case vfs_errc::not_a_directory: - return make_error_condition(kstd::errc::not_a_directory); - case vfs_errc::is_a_directory: - return make_error_condition(kstd::errc::is_a_directory); - case vfs_errc::read_only_file_system: - return make_error_condition(kstd::errc::read_only_file_system); - case vfs_errc::file_exists: - return make_error_condition(kstd::errc::file_exists); - case vfs_errc::no_such_device: - return make_error_condition(kstd::errc::no_such_device); - default: - return kstd::error_condition{value, *this}; - } - } - } constexpr inline vfs_category_instance{}; - } // namespace detail - - [[nodiscard]] constexpr auto inline vfs_category() noexcept -> kstd::error_category const & - { - return detail::vfs_category_instance; - } + [[nodiscard]] auto vfs_category() noexcept -> kstd::error_category const &; [[nodiscard]] constexpr auto inline make_error_code(vfs_errc error) noexcept -> kstd::error_code { diff --git a/kernel/kernel/filesystem/ext2/error.cpp b/kernel/kernel/filesystem/ext2/error.cpp new file mode 100644 index 00000000..1da4ef36 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/error.cpp @@ -0,0 +1,92 @@ +#include + +#include + +#include + +#include + +namespace kernel::filesystem::ext2 +{ + + namespace + { + struct ext2_category_t final : kstd::error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + switch (static_cast(value)) + { + case ext2_errc::invalid_magic_number: + return "invalid filesystem magic"; + case ext2_errc::invalid_root_inode: + return "invalid root inode"; + case ext2_errc::invalid_block_group_index: + return "block group index out of bounds"; + case ext2_errc::invalid_block_index: + return "block index out of bounds"; + case ext2_errc::invalid_block_number: + return "block number out of bounds"; + case ext2_errc::failed_to_read_superblock: + return "failed to read superblock"; + case ext2_errc::failed_to_read_block_group_descriptors: + return "failed to read block group descriptors"; + case ext2_errc::not_enough_free_blocks: + return "not enough free blocks"; + case ext2_errc::not_enough_inodes: + return "not enough inodes"; + default: + return "unknown ext2 error"; + }; + } + + [[nodiscard]] constexpr auto equivalent(int code, kstd::error_condition const & condition) const noexcept + -> bool override + { + switch (static_cast(code)) + { + case ext2_errc::invalid_magic_number: + case ext2_errc::invalid_root_inode: + if (condition.category() == kernel::filesystem::vfs_category()) + { + return condition.value() == static_cast(kernel::filesystem::vfs_errc::invalid_filesystem); + } + else if (condition.category() == kstd::generic_category()) + { + return condition.value() == static_cast(kstd::errc::invalid_argument); + } + break; + case ext2_errc::invalid_block_group_index: + case ext2_errc::invalid_block_index: + case ext2_errc::invalid_block_number: + case ext2_errc::failed_to_read_superblock: + case ext2_errc::failed_to_read_block_group_descriptors: + if (condition.category() == kstd::generic_category()) + { + return condition.value() == static_cast(kstd::errc::io_error); + } + break; + case ext2_errc::not_enough_free_blocks: + case ext2_errc::not_enough_inodes: + if (condition.category() == kstd::generic_category()) + { + return condition.value() == static_cast(kstd::errc::no_space_on_device); + } + break; + } + return kstd::error_category::equivalent(code, condition); + } + } constexpr inline ext2_category_instance{}; + } // namespace + + [[nodiscard]] auto ext2_category() noexcept -> kstd::error_category const & + { + return ext2_category_instance; + } + +} // namespace kernel::filesystem::ext2 diff --git a/kernel/kernel/filesystem/ext2/error.hpp b/kernel/kernel/filesystem/ext2/error.hpp index 7de3b24b..dcdf7295 100644 --- a/kernel/kernel/filesystem/ext2/error.hpp +++ b/kernel/kernel/filesystem/ext2/error.hpp @@ -5,7 +5,6 @@ #include -#include #include namespace kernel::filesystem::ext2 @@ -24,85 +23,7 @@ namespace kernel::filesystem::ext2 not_enough_inodes }; - namespace detail - { - struct ext2_category_t final : kstd::error_category - { - [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override - { - return "ext2"; - } - - [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override - { - switch (static_cast(value)) - { - case ext2_errc::invalid_magic_number: - return "invalid filesystem magic"; - case ext2_errc::invalid_root_inode: - return "invalid root inode"; - case ext2_errc::invalid_block_group_index: - return "block group index out of bounds"; - case ext2_errc::invalid_block_index: - return "block index out of bounds"; - case ext2_errc::invalid_block_number: - return "block number out of bounds"; - case ext2_errc::failed_to_read_superblock: - return "failed to read superblock"; - case ext2_errc::failed_to_read_block_group_descriptors: - return "failed to read block group descriptors"; - case ext2_errc::not_enough_free_blocks: - return "not enough free blocks"; - case ext2_errc::not_enough_inodes: - return "not enough inodes"; - default: - return "unknown ext2 error"; - }; - } - - [[nodiscard]] constexpr auto equivalent(int code, kstd::error_condition const & condition) const noexcept - -> bool override - { - switch (static_cast(code)) - { - case ext2_errc::invalid_magic_number: - case ext2_errc::invalid_root_inode: - if (condition.category() == kernel::filesystem::vfs_category()) - { - return condition.value() == static_cast(kernel::filesystem::vfs_errc::invalid_filesystem); - } - else if (condition.category() == kstd::generic_category()) - { - return condition.value() == static_cast(kstd::errc::invalid_argument); - } - break; - case ext2_errc::invalid_block_group_index: - case ext2_errc::invalid_block_index: - case ext2_errc::invalid_block_number: - case ext2_errc::failed_to_read_superblock: - case ext2_errc::failed_to_read_block_group_descriptors: - if (condition.category() == kstd::generic_category()) - { - return condition.value() == static_cast(kstd::errc::io_error); - } - break; - case ext2_errc::not_enough_free_blocks: - case ext2_errc::not_enough_inodes: - if (condition.category() == kstd::generic_category()) - { - return condition.value() == static_cast(kstd::errc::no_space_on_device); - } - break; - } - return kstd::error_category::equivalent(code, condition); - } - } constexpr inline ext2_category_instance{}; - } // namespace detail - - [[nodiscard]] constexpr auto inline ext2_category() noexcept -> kstd::error_category const & - { - return detail::ext2_category_instance; - } + [[nodiscard]] auto ext2_category() noexcept -> kstd::error_category const &; [[nodiscard]] constexpr auto inline make_error_code(ext2_errc error) noexcept -> kstd::error_code { diff --git a/kernel/kernel/filesystem/open_file_descriptor.cpp b/kernel/kernel/filesystem/open_file_descriptor.cpp index 6277d0b6..e233b5da 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.cpp +++ b/kernel/kernel/filesystem/open_file_descriptor.cpp @@ -7,8 +7,6 @@ #include #include -#include - namespace kernel::filesystem { open_file_descriptor::open_file_descriptor(kstd::shared_ptr const & dentry) diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 9c68feed..e2b56d2f 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -18,6 +18,7 @@ add_library("kstd::lib" ALIAS "kstd") target_sources("kstd" PRIVATE "kstd/os/error.cpp" "kstd/mutex.cpp" + "kstd/system_error.cpp" "kstd/bits/format/vformat.cpp" ) diff --git a/libs/kstd/kstd/system_error.cpp b/libs/kstd/kstd/system_error.cpp new file mode 100644 index 00000000..8ecf40d7 --- /dev/null +++ b/libs/kstd/kstd/system_error.cpp @@ -0,0 +1,233 @@ +#include + +#include + +namespace kstd +{ + + namespace + { + 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(value)); + } + } constexpr 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(value)); + } + } constexpr system_category_instance{}; + } // namespace + + auto generic_category() noexcept -> error_category const & + { + return generic_category_instance; + } + + auto system_category() noexcept -> error_category const & + { + return system_category_instance; + } + + error_condition::error_condition() noexcept + : m_value{0} + , m_category{&generic_category()} + {} + + error_condition::error_condition(int value, error_category const & category) noexcept + : m_value{value} + , m_category{&category} + {} + + auto error_category::default_error_condition(int value) const noexcept -> error_condition + { + return error_condition{value, *this}; + } + + auto error_category::equivalent(int value, error_condition const & other) const noexcept -> bool + { + return default_error_condition(value) == other; + } + + auto error_category::equivalent(error_code const & code, int condition) const noexcept -> bool + { + return *this == code.category() && code.value() == condition; + } + + auto error_condition::assign(int value, error_category const & category) noexcept -> void + { + m_value = value; + m_category = &category; + } + + auto error_condition::clear() noexcept -> void + { + m_value = 0; + m_category = &generic_category(); + } + + [[nodiscard]] auto error_condition::value() const noexcept -> int + { + return m_value; + } + + [[nodiscard]] auto error_condition::category() const noexcept -> error_category const & + { + return *m_category; + } + + [[nodiscard]] auto error_condition::message() const noexcept -> std::string_view + { + return m_category->message(m_value); + } + + error_code::error_code() noexcept + : error_code{0, system_category()} {}; + + error_code::error_code(int value, error_category const & category) noexcept + : m_value{value} + , m_category{&category} + {} + + auto error_code::assign(int value, error_category const & category) noexcept -> void + { + m_value = value; + m_category = &category; + } + + auto error_code::clear() noexcept -> void + { + m_value = 0; + m_category = &system_category(); + } + + auto error_code::value() const noexcept -> int + { + return m_value; + } + + auto error_code::category() const noexcept -> error_category const & + { + return *m_category; + } + + auto error_code::default_error_condition() const noexcept -> error_condition + { + return m_category->default_error_condition(m_value); + } + + auto error_code::message() const noexcept -> std::string_view + { + return m_category->message(m_value); + } + + auto make_error_code(errc const value) noexcept -> error_code + { + return {static_cast(value), generic_category()}; + } + + auto make_error_condition(errc const value) noexcept -> error_condition + { + return {static_cast(value), generic_category()}; + } + +} // namespace kstd diff --git a/libs/kstd/kstd/system_error.hpp b/libs/kstd/kstd/system_error.hpp index 09efb097..d6e78ffe 100644 --- a/libs/kstd/kstd/system_error.hpp +++ b/libs/kstd/kstd/system_error.hpp @@ -95,33 +95,33 @@ namespace kstd 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; + [[nodiscard]] 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; + [[nodiscard]] 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; + [[nodiscard]] 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; + [[nodiscard]] 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; + [[nodiscard]] 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 @@ -142,16 +142,13 @@ namespace kstd struct error_condition { //! Construct an error condition with a default value and category. - constexpr error_condition() noexcept; + 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} - {} + error_condition(int value, error_category const & category) noexcept; //! Construct an error condition from an error condition enumeration value. //! @@ -176,34 +173,21 @@ namespace kstd //! //! @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; - } + auto assign(int value, error_category const & category) noexcept -> void; //! Clear this error condition. //! //! This sets the value to 0 and the category to the generic error category. - constexpr auto clear() noexcept -> void; + auto clear() noexcept -> void; //! Get the raw error code value of this error condition. - [[nodiscard]] constexpr auto value() const noexcept -> int - { - return m_value; - } + [[nodiscard]] auto value() const noexcept -> int; //! Get the error category of this error condition. - [[nodiscard]] constexpr auto category() const noexcept -> error_category const & - { - return *m_category; - } + [[nodiscard]] auto category() const noexcept -> error_category const &; //! 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); - } + [[nodiscard]] auto message() const noexcept -> std::string_view; //! Check if this error condition holds an error. //! @@ -246,13 +230,10 @@ namespace kstd struct error_code { //! Construct an error code with a default value and category. - constexpr error_code() noexcept; + 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} - {} + error_code(int value, error_category const & category) noexcept; //! Construct an error code from an error code enumeration value. //! @@ -278,38 +259,22 @@ namespace kstd //! //! @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; - } + auto assign(int value, error_category const & category) noexcept -> void; //! Clear this error code. - constexpr auto clear() noexcept -> void; + auto clear() noexcept -> void; //! Get the raw error code value of this error code. - [[nodiscard]] constexpr auto value() const noexcept -> int - { - return m_value; - } + [[nodiscard]] auto value() const noexcept -> int; //! Get the error category of this error code. - [[nodiscard]] constexpr auto category() const noexcept -> error_category const & - { - return *m_category; - } + [[nodiscard]] auto category() const noexcept -> error_category const &; //! 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); - } + [[nodiscard]] auto default_error_condition() const noexcept -> error_condition; //! 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); - } + [[nodiscard]] auto message() const noexcept -> std::string_view; //! Check if this error code holds an error. //! @@ -327,6 +292,12 @@ namespace kstd return lhs.category() == rhs.category() && lhs.value() == rhs.value(); } + constexpr auto friend operator==(error_code const & code, error_condition const & condition) noexcept -> bool + { + return code.category().equivalent(code.value(), condition) || + condition.category().equivalent(code, condition.value()); + } + //! Lexicographically compare two error codes. [[nodiscard]] constexpr auto friend operator<=>(error_code const & lhs, error_code const & rhs) noexcept -> std::strong_ordering @@ -428,182 +399,17 @@ namespace kstd { }; - 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(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(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; - } + auto generic_category() noexcept -> error_category const &; //! 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(); - } + auto system_category() noexcept -> error_category const &; //! 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(value), generic_category()}; - } + [[nodiscard]] auto make_error_code(errc const value) noexcept -> error_code; //! 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(value), generic_category()}; - } + [[nodiscard]] auto make_error_condition(errc const value) noexcept -> error_condition; //! Enable formatting of kstd::error_code //! -- cgit v1.2.3