From e7ccb96aecae7b231fb05818d7e45a767aebc31d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 18 Mar 2026 17:18:37 +0100 Subject: kstd: introduce strong type for memory amounts --- libs/kstd/include/kstd/units | 145 +++++++++++++++++++++ libs/multiboot2/CMakeLists.txt | 1 + libs/multiboot2/include/multiboot2/information.hpp | 16 ++- .../include/multiboot2/information/data.hpp | 31 ++++- 4 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 libs/kstd/include/kstd/units (limited to 'libs') diff --git a/libs/kstd/include/kstd/units b/libs/kstd/include/kstd/units new file mode 100644 index 0000000..f6dcdb1 --- /dev/null +++ b/libs/kstd/include/kstd/units @@ -0,0 +1,145 @@ +#ifndef KSTD_UNITS_HPP +#define KSTD_UNITS_HPP + +#include +#include +#include + +namespace kstd +{ + + //! A basic template for strongly typed units. + template + struct basic_unit + { + using value_type = ValueType; + + explicit constexpr basic_unit(value_type value) noexcept + : value{value} + {} + + explicit constexpr operator value_type() const noexcept + { + return value; + } + + constexpr auto operator+(basic_unit const & other) const noexcept -> basic_unit + { + return basic_unit{value + other.value}; + } + + constexpr auto operator+=(basic_unit const & other) noexcept -> basic_unit & + { + return *this = *this + other; + } + + constexpr auto operator-(basic_unit const & other) const noexcept -> basic_unit + { + return basic_unit{value - other.value}; + } + + constexpr auto operator-=(basic_unit const & other) noexcept -> basic_unit & + { + return *this = *this - other; + } + + constexpr auto operator*(std::integral auto factor) noexcept -> basic_unit + { + return basic_unit{value * factor}; + } + + constexpr auto operator*=(std::integral auto factor) noexcept -> basic_unit + { + return *this = *this * factor; + } + + constexpr auto operator/(std::integral auto divisor) noexcept -> basic_unit + { + return basic_unit{value / divisor}; + } + + constexpr auto operator/=(std::integral auto divisor) noexcept -> basic_unit + { + return *this = *this / divisor; + } + + constexpr auto operator/(basic_unit const & other) const noexcept + { + return value / other.value; + } + + constexpr auto operator<=>(basic_unit const & other) const noexcept -> std::strong_ordering = default; + + value_type value; + }; + + template + constexpr auto operator*(Factor factor, basic_unit const & unit) noexcept + -> basic_unit + { + return basic_unit{unit.value * factor}; + } + + namespace units + { + using bytes = basic_unit; + + constexpr auto KiB(std::size_t value) noexcept -> bytes + { + return bytes{value * 1024}; + } + + constexpr auto MiB(std::size_t value) noexcept -> bytes + { + return bytes{value * 1024 * 1024}; + } + + constexpr auto GiB(std::size_t value) noexcept -> bytes + { + return bytes{value * 1024 * 1024 * 1024}; + } + + template + constexpr auto operator+(ValueType * pointer, bytes offset) -> ValueType * + { + return pointer + offset.value; + } + + } // namespace units + + namespace units_literals + { + constexpr auto operator""_B(unsigned long long value) noexcept -> units::bytes + { + return units::bytes{value}; + } + + constexpr auto operator""_KiB(unsigned long long value) noexcept -> units::bytes + { + return units::KiB(value); + } + + constexpr auto operator""_MiB(unsigned long long value) noexcept -> units::bytes + { + return units::MiB(value); + } + + constexpr auto operator""_GiB(unsigned long long value) noexcept -> units::bytes + { + return units::GiB(value); + } + + } // namespace units_literals + + template + constexpr auto object_size(ValueType const &) -> units::bytes + { + return units::bytes{sizeof(ValueType)}; + } + + template + constexpr auto type_size = units::bytes{sizeof(T)}; + +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index 350a996..b306b66 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -20,6 +20,7 @@ target_include_directories("multiboot2" INTERFACE target_link_libraries("multiboot2" INTERFACE "libs::elf" + "libs::kstd" ) set_target_properties("multiboot2" PROPERTIES diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index fbd534c..d2fac2e 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -5,11 +5,12 @@ #include "information/iterator.hpp" // IWYU pragma: export #include "information/tag.hpp" // IWYU pragma: export +#include + #include #include #include -#include #include #include #include @@ -119,7 +120,12 @@ namespace multiboot2 */ [[nodiscard]] auto string() const noexcept -> std::string_view { - return {data(), size()}; + return {data(), vla_tag::size()}; + } + + [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{end_address - start_address}; } }; @@ -130,9 +136,9 @@ namespace multiboot2 using pointer = iterator::pointer; using reference = iterator::reference; - [[nodiscard]] auto size_bytes() const noexcept -> std::size_t + [[nodiscard]] auto size() const noexcept -> kstd::units::bytes { - return m_size; + return kstd::units::bytes{m_size}; } // Range access @@ -190,7 +196,7 @@ namespace multiboot2 { return get>().and_then( [](auto x) -> std::optional> { - if (x.entry_size == elf::section_header_size) + if (x.entry_size_in_B == elf::section_header_size) { return std::optional{x}; } diff --git a/libs/multiboot2/include/multiboot2/information/data.hpp b/libs/multiboot2/include/multiboot2/information/data.hpp index 9fa6d5b..3b07d20 100644 --- a/libs/multiboot2/include/multiboot2/information/data.hpp +++ b/libs/multiboot2/include/multiboot2/information/data.hpp @@ -6,6 +6,8 @@ #include "multiboot2/constants/information_id.hpp" #include "multiboot2/constants/memory_type.hpp" +#include + #include namespace multiboot2 @@ -27,6 +29,16 @@ namespace multiboot2 //! loader. struct basic_memory : tag_data { + [[nodiscard]] constexpr auto lower() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{lower_KiB * 1024}; + } + + [[nodiscard]] constexpr auto upper() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{upper_KiB * 1024}; + } + //! The amount of lower memory available to the system. //! //! Any memory below the 1 MiB address boundary is considered to be lower memory. The maximum possible value for @@ -72,11 +84,16 @@ namespace multiboot2 //! time. The array begins after the last member of this structure. struct elf_symbols : tag_data { + [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{entry_size_in_B}; + } + //! The number of section header table entries. std::uint32_t count; //! The size of each section header table entry. - std::uint32_t entry_size; + std::uint32_t entry_size_in_B; //! The section number of the string table containing the section names. std::uint32_t string_table_index; @@ -102,6 +119,11 @@ namespace multiboot2 return type == memory_type::available; } + [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{size_in_B}; + } + //! The physical start address of this region std::uint64_t base; @@ -117,11 +139,16 @@ namespace multiboot2 std::uint32_t : 0; }; + [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{entry_size_in_B}; + } + //! The size of each entry present in the map. //! //! This field is present to allow for future extension of the entry format. Each entry's size is guaranteed to //! always be an integer multiple of 8. - std::uint32_t entry_size; + std::uint32_t entry_size_in_B; //! The version of each entry present in the map std::uint32_t entry_version; -- cgit v1.2.3