From 22fbbf849497c32f5b237ab70e9ed8aef63e54cf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:21:32 +0000 Subject: libs: extract multiboot library --- libs/multiboot2/CMakeLists.txt | 26 ++++ libs/multiboot2/include/multiboot2/constants.hpp | 20 +++ libs/multiboot2/include/multiboot2/impl/data.hpp | 130 +++++++++++++++++ libs/multiboot2/include/multiboot2/impl/ids.hpp | 79 ++++++++++ .../include/multiboot2/impl/iterator.hpp | 63 ++++++++ libs/multiboot2/include/multiboot2/impl/tag.hpp | 113 +++++++++++++++ libs/multiboot2/include/multiboot2/information.hpp | 160 +++++++++++++++++++++ 7 files changed, 591 insertions(+) create mode 100644 libs/multiboot2/CMakeLists.txt create mode 100644 libs/multiboot2/include/multiboot2/constants.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/data.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/ids.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/iterator.hpp create mode 100644 libs/multiboot2/include/multiboot2/impl/tag.hpp create mode 100644 libs/multiboot2/include/multiboot2/information.hpp (limited to 'libs') diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt new file mode 100644 index 0000000..af56d5a --- /dev/null +++ b/libs/multiboot2/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION "3.27") + +project("multiboot2" + LANGUAGES CXX + VERSION "1.0.0" +) + +add_library("multiboot2" INTERFACE) +add_library("multiboot2::multiboot2" ALIAS "multiboot2") + +target_sources("multiboot2" INTERFACE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/multiboot2/constants.hpp" + "include/multiboot2/information.hpp" + + "include/multiboot2/impl/data.hpp" + "include/multiboot2/impl/ids.hpp" + "include/multiboot2/impl/iterator.hpp" + "include/multiboot2/impl/tag.hpp" +) + +target_include_directories("multiboot2" INTERFACE + "include" +) diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp new file mode 100644 index 0000000..30d52d0 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/constants.hpp @@ -0,0 +1,20 @@ +#ifndef MULTIBOOT2_CONSTANTS_HPP +#define MULTIBOOT2_CONSTANTS_HPP + +#include "impl/ids.hpp" // IWYU pragma: export + +#include + +namespace multiboot2 +{ + + using impl::architecture_id; + using impl::information_id; + using impl::memory_type; + using impl::tag_id; + + auto constexpr inline header_magic = std::uint32_t{0xe85250d6}; + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp new file mode 100644 index 0000000..367e8cb --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -0,0 +1,130 @@ +#ifndef MULTIBOOT2_IMPL_DATA_HPP +#define MULTIBOOT2_IMPL_DATA_HPP + +#include "multiboot2/impl/ids.hpp" + +#include + +namespace multiboot2::impl +{ + template + struct tag_data + { + auto constexpr inline static id = Id; + }; + + /** + * @brief Basic system memory information + */ + struct basic_memory_data : tag_data + { + /** + * @brief Amount of lower memory (below 1MiB) available to the system. + * + * The maximum possible value for this field is 640 KiB. + */ + std::uint32_t const lower_KiB; + + /** + * @brief Amount of upper memory (above 1MiB) available to the system. + * + * The maximum possible value for this field is the address of the first upper memory hole minus 1MiB. + */ + std::uint32_t const upper_KiB; + }; + + /** + * @brief Device the image got loaded from + */ + struct bios_boot_device_data : tag_data + { + /** + * @brief BIOS device number as understood by INT 13h. + */ + std::uint32_t device_number; + + /** + * @brief Number of the primary partition. + */ + std::uint32_t partition_number; + + /** + * @brief Number the sub-partion on the primary partition. + */ + std::uint32_t sub_partition_number; + }; + + /** + * @brief Supplied image command line + */ + struct command_line_data : tag_data + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief ELF symbols of the image + */ + struct elf_symbols_data : tag_data + { + std::uint32_t count; + std::uint32_t entry_size; + std::uint32_t string_table_index; + }; + + /** + * @brief Name of the boot loader + */ + struct loader_name_data : tag_data + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief Detailed map of the memory regions present in the system + * + */ + struct memory_map_data : tag_data + { + /** + * @brief A region of memory + */ + struct region + { + /** + * @brief Check if the memory described by this region is available for use. + */ + auto constexpr available() const noexcept { return type == memory_type::AVAILABLE; } + + /** + * @brief Start address of this region + */ + std::uint64_t const base; + + /** + * @brief Size of this region in bytes. + */ + std::uint64_t const size_in_B; + + /** + * @brief Type of this region. + */ + memory_type const type; + + std::uint32_t : 0; + }; + + /** + * @brief Size of each entry present in the map + */ + std::uint32_t const entry_size; + + /** + * @brief Version of each entry present in the map + */ + std::uint32_t const entry_version; + }; + +} // namespace multiboot2::impl + +#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/ids.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp new file mode 100644 index 0000000..3a7215e --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -0,0 +1,79 @@ +#ifndef MULTIBOOT2_IMPL_IDS_HPP +#define MULTIBOOT2_IMPL_IDS_HPP + +#include + +namespace multiboot2::impl +{ + + /** + * @brief Information tag IDs. + */ + enum struct information_id : std::uint32_t + { + END, ///< Signals final tag for the multiboot2 information structure. + CMDLINE, ///< Contains the command line string. + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel. + MODULE, ///< Indicates the boot module which was loaded along the kernel image. + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address). + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from. + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags. + VBE_INFO, ///< Includes information to access and utilize the device GPU. + FRAMEBUFFER, ///< VBE framebuffer information. + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel. + APM_INFO, ///< Advanced Power Management information. + EFI32, ///< EFI 32 bit system table pointer. + EFI64, ///< EFI 64 bit system table pointer. + SMBIOS, ///< Contains copy of all Sytem Management BIOS tables. + ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification. + ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification. + NETWORK, ///< Contains network information specified specified as DHCP. + EFI_MEMORY_MAP, ///< Contains EFI memory map. + EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called. + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer. + LOAD_BASE_ADDRESS ///< Contains image load base physical address. + }; + + /** + * @brief Header tag IDs. + */ + enum struct tag_id : std::uint32_t + { + END, + INFORMATION_REQUEST, + ADDRESSES, + ENTRY_ADDRESS, + CONSOLE_FLAGS, + PREFERRED_FRAMEBUFFER_MODE, + PAGE_ALIGN_MODULES, + EFI_BOOT_SERVICES_SUPPORTED, + EFI32_ENTRY_ADDRESS, + EFI64_ENTRY_ADDRESS, + RELOCATABLE, + }; + + /** + * @brief System architecture IDs. + */ + enum struct architecture_id : std::uint32_t + { + I386 = 0, + MIPS32 = 4, + }; + + /** + * @brief Memory type IDs. + */ + enum struct memory_type : std::uint32_t + { + AVAILABLE = 1, + RESERVED, + ACPI_RECLAIMABLE, + NON_VOLATILE_STORAGE, + BAD_RAM, + }; + +} // namespace multiboot2::impl + +#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp new file mode 100644 index 0000000..b84ef2c --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -0,0 +1,63 @@ +#ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP +#define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP + +#include "multiboot2/impl/ids.hpp" +#include "multiboot2/impl/tag.hpp" + +#include +#include +#include + +namespace multiboot2::impl +{ + + struct information_iterator + { + using iterator_category = std::forward_iterator_tag; + using value_type = impl::tag_header; + using pointer = value_type const *; + using reference = value_type const &; + using difference_type = std::ptrdiff_t; + + constexpr information_iterator() = default; + + constexpr explicit information_iterator(impl::tag_header const * offset) + : m_current(offset) + { + } + + auto constexpr operator==(information_iterator const &) const noexcept -> bool = default; + + auto constexpr operator*() const noexcept -> reference { return *(m_current.value()); } + + auto constexpr operator->() const noexcept -> pointer { return m_current.value(); } + + auto constexpr operator++() noexcept -> information_iterator & + { + if (m_current) + { + if (auto next = m_current.value()->next(); next->information_id() != information_id::END) + { + m_current = next; + } + m_current.reset(); + } + return *this; + } + + auto constexpr operator++(int) noexcept -> information_iterator + { + auto copy = *this; + ++(*this); + return copy; + } + + private: + std::optional m_current{}; + }; + + static_assert(std::input_or_output_iterator); + +} // namespace multiboot2::impl + +#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp new file mode 100644 index 0000000..f7471a4 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -0,0 +1,113 @@ +#ifndef MULTIBOOT2_IMPL_TAG_HPP +#define MULTIBOOT2_IMPL_TAG_HPP + +#include "multiboot2/impl/ids.hpp" + +#include +#include +#include + +namespace multiboot2::impl +{ + + /** + * @brief Header data and functionality shared by all tags. + */ + struct tag_header + { + tag_header() + : m_id{} + , m_size{} + { + } + + tag_header(tag_header const * data) + : tag_header{*data} + { + } + + auto full_size() const noexcept -> std::size_t { return (m_size + 7) & (~7); } + + auto information_id() const noexcept -> impl::information_id const & { return m_id; } + + auto next() const noexcept -> tag_header const * + { + return std::bit_cast(std::bit_cast(this) + full_size()); + } + + auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } + + protected: + impl::information_id const m_id; + std::uint32_t const m_size; + }; + + /** + * @brief A tag containing no variable length array data. + */ + template + struct tag : tag_header, Data + { + tag() + : tag_header{} + , Data{} + { + } + + explicit tag(tag_header const * header) + requires(sizeof(tag) > sizeof(tag_header)) + : tag_header{header} + , Data{*std::bit_cast(header + 1)} + { + } + + explicit tag(tag_header const * header) + requires(sizeof(tag) == sizeof(tag_header)) + : tag_header{header} + , Data{} + { + } + }; + + /** + * @brief A tag containing variable length array data. + */ + template typename Range> + struct vla_tag : tag + { + using range_type = Range; + + vla_tag() + : tag{} + , m_vla{} + { + } + + explicit vla_tag(tag_header const * header) + : tag{header} + , m_vla{vla_start(header), vla_size(header)} + { + } + + protected: + auto static vla_start(tag_header const * header) noexcept -> VlaData * + { + auto raw = std::bit_cast(header); + auto start = raw + sizeof(tag); + return std::bit_cast(start); + } + + auto static vla_size(tag_header const * header) noexcept -> std::size_t + { + auto size = (header->unaligned_size() - sizeof(tag) - + std::is_same_v> * 1) / + sizeof(VlaData); + return size; + } + + range_type const m_vla; + }; + +} // namespace multiboot2::impl + +#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp new file mode 100644 index 0000000..04ba183 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -0,0 +1,160 @@ +#ifndef JOS_MULTIBOOT2_INFORMATION_HPP +#define JOS_MULTIBOOT2_INFORMATION_HPP + +#include "impl/data.hpp" +#include "impl/iterator.hpp" +#include "impl/tag.hpp" + +#include +#include +#include +#include +#include +#include + +namespace multiboot2 +{ + + /** + * @copydoc multiboot2::impl::basic_memory_data + */ + struct basic_memory : impl::tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::bios_boot_device_data + */ + struct bios_boot_device : impl::tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::command_line_data + */ + struct command_line : impl::vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The command line string + */ + auto string() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::elf_symbols_data + */ + struct elf_symbols : impl::vla_tag + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto data() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::loader_name_data + */ + struct loader_name : impl::vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The name of the bootloader + */ + auto string() const noexcept -> std::string_view { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::memory_map_data + */ + struct memory_map : impl::vla_tag + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto begin() const noexcept -> iterator { return regions().begin(); } + + auto end() const noexcept -> iterator { return regions().end(); } + + /** + * @brief The available memory regions + */ + auto regions() const noexcept -> range_type { return m_vla; } + }; + + struct information_view + { + using iterator = impl::information_iterator; + using value_type = impl::information_iterator::value_type; + using pointer = impl::information_iterator::pointer; + using reference = impl::information_iterator::reference; + + auto size_bytes() const noexcept -> std::size_t { return m_size; } + + // Range access + + auto begin() const noexcept -> iterator { return iterator{&m_tags}; } + + auto end() const noexcept -> iterator { return iterator{}; } + + // Tag access + + template + auto has() const noexcept -> bool + { + return get().has_value(); + } + + auto maybe_basic_memory() const noexcept -> std::optional { return get(); } + + auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } + + auto maybe_bios_boot_device() const noexcept -> std::optional + { + return get(); + } + + auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } + + auto maybe_command_line() const noexcept -> std::optional { return get(); } + + auto command_line() const -> command_line { return maybe_command_line().value(); } + + auto maybe_elf_symbols() const noexcept -> std::optional { return get(); } + + auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } + + auto maybe_loader_name() const noexcept -> std::optional { return get(); } + + auto loader_name() const -> loader_name { return maybe_loader_name().value(); } + + auto maybe_memory_map() const noexcept -> std::optional { return get(); } + + auto memory_map() const -> memory_map { return maybe_memory_map().value(); } + + private: + template + auto constexpr get() const noexcept -> std::optional + { + if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); + found != end()) + { + return Tag{&*found}; + } + return std::nullopt; + } + + [[maybe_unused]] uint32_t const m_size{}; + uint32_t : 32; + impl::tag_header const m_tags{}; + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file -- cgit v1.2.3 From e7eedd234954509f4f5ec52b2d62cbc4a1723936 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:09 +0000 Subject: libs: begin extraction of kernel std --- libs/kstd/CMakeLists.txt | 24 ++++++++++++++++ libs/kstd/include/kstd/mutex.hpp | 60 ++++++++++++++++++++++++++++++++++++++++ libs/kstd/src/mutex.cpp | 16 +++++++++++ 3 files changed, 100 insertions(+) create mode 100644 libs/kstd/CMakeLists.txt create mode 100644 libs/kstd/include/kstd/mutex.hpp create mode 100644 libs/kstd/src/mutex.cpp (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt new file mode 100644 index 0000000..06083f3 --- /dev/null +++ b/libs/kstd/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION "3.27") + +project("kstd" + LANGUAGES CXX + VERSION "1.0.0" +) + +add_library("kstd" STATIC) +add_library("libs::kstd" ALIAS "kstd") + +target_sources("kstd" PRIVATE + "src/mutex.cpp" +) + +target_sources("kstd" PUBLIC + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/kstd/mutex.hpp" +) + +target_include_directories("kstd" PUBLIC + "include" +) diff --git a/libs/kstd/include/kstd/mutex.hpp b/libs/kstd/include/kstd/mutex.hpp new file mode 100644 index 0000000..cf8549f --- /dev/null +++ b/libs/kstd/include/kstd/mutex.hpp @@ -0,0 +1,60 @@ +#ifndef KSTD_MUTEX_HPP +#define KSTD_MUTEX_HPP + +#include + +namespace kstd +{ + /** + * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in + * use by another thread or not. + */ + struct mutex + { + /** + * @brief Defaulted constructor. + */ + mutex() = default; + + /** + * @brief Defaulted destructor. + */ + ~mutex() = default; + + /** + * @brief Deleted copy constructor. + */ + mutex(const mutex &) = delete; + + /** + * @brief Deleted assignment operator. + */ + mutex & operator=(const mutex &) = delete; + + /** + * @brief Lock the mutex (blocks for as long as it is not available). + */ + [[gnu::section(".stl_text")]] + auto lock() -> void; + + /** + * @brief Try to lock the mutex (non-blocking). + * + * @return True if lock has been acquired and false otherwise. + */ + [[gnu::section(".stl_text")]] + auto try_lock() -> bool; + + /** + * @brief Unlock the mutex. + */ + [[gnu::section(".stl_text")]] + auto unlock() -> void; + + private: + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. + }; + +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp new file mode 100644 index 0000000..cfb1c84 --- /dev/null +++ b/libs/kstd/src/mutex.cpp @@ -0,0 +1,16 @@ +#include "kstd/mutex.hpp" + +namespace kstd +{ + auto mutex::lock() -> void + { + while (!try_lock()) + { + asm volatile("nop"); + } + } + + auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + + auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } +} // namespace kstd -- cgit v1.2.3 From 1b603d1145b9ee10b1b12a0f765bd2bc1ebe2b3c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:59 +0000 Subject: libs: rename multiboot alias --- libs/multiboot2/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index af56d5a..386a127 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -6,7 +6,7 @@ project("multiboot2" ) add_library("multiboot2" INTERFACE) -add_library("multiboot2::multiboot2" ALIAS "multiboot2") +add_library("libs::multiboot2" ALIAS "multiboot2") target_sources("multiboot2" INTERFACE FILE_SET HEADERS -- cgit v1.2.3 From 25483b7af8df6b08d460f807fda04c6d409bd44e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:02:43 +0000 Subject: ide: start large-scale restructuring --- libs/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 libs/CMakeLists.txt (limited to 'libs') diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000..b2dbf86 --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM) +add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ No newline at end of file -- cgit v1.2.3 From ec572bff8150e2f8cd2dc99e053c5e8c8a0b99e3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:25:00 +0000 Subject: arch: prepare interfaces --- libs/kstd/CMakeLists.txt | 7 ------- libs/multiboot2/CMakeLists.txt | 7 ------- 2 files changed, 14 deletions(-) (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 06083f3..a29fac8 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -1,10 +1,3 @@ -cmake_minimum_required(VERSION "3.27") - -project("kstd" - LANGUAGES CXX - VERSION "1.0.0" -) - add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index 386a127..7b9e58a 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -1,10 +1,3 @@ -cmake_minimum_required(VERSION "3.27") - -project("multiboot2" - LANGUAGES CXX - VERSION "1.0.0" -) - add_library("multiboot2" INTERFACE) add_library("libs::multiboot2" ALIAS "multiboot2") -- cgit v1.2.3 From 763f38fff9336e40fce27565861e85c95d003a12 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:14:38 +0000 Subject: libs: move vector to kstd --- libs/kstd/include/kstd/bits/os.hpp | 13 + libs/kstd/include/kstd/vector.hpp | 596 +++++++++++++++++++++++++++++++++++++ 2 files changed, 609 insertions(+) create mode 100644 libs/kstd/include/kstd/bits/os.hpp create mode 100644 libs/kstd/include/kstd/vector.hpp (limited to 'libs') diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp new file mode 100644 index 0000000..0425b88 --- /dev/null +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -0,0 +1,13 @@ +#ifndef KSTD_OS_HPP +#define KSTD_OS_HPP + +#include +#include + +namespace kstd::os +{ + [[noreturn]] + auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; +} + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/vector.hpp b/libs/kstd/include/kstd/vector.hpp new file mode 100644 index 0000000..1009e81 --- /dev/null +++ b/libs/kstd/include/kstd/vector.hpp @@ -0,0 +1,596 @@ +#ifndef KSTD_VECTOR_HPP +#define KSTD_VECTOR_HPP + +#include "bits/os.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the vector instance should contain. + */ + template + struct vector + { + using value_type = T; ///< Type of the elements contained in the container. + using size_type = std::size_t; ///< Type of the size in the container. + using reference = value_type &; ///< Type of reference to the elements. + using const_reference = value_type const &; ///< Type of constant reference to the elements. + using pointer = value_type *; ///< Type of pointer to the elements. + using const_pointer = value_type const *; ///< Type of constant pointer to the elements. + + /** + * @brief Default Constructor. + */ + vector() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + explicit vector(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _data(new value_type[_capacity]{}) + { + std::ranges::fill(*this, initial); + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + explicit vector(InputIterator first, InputIterator last) + : _size(std::distance(first, last)) + , _capacity(std::distance(first, last)) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(first, last, _data); + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit vector(std::initializer_list initalizer_list) + : _size(initalizer_list.size()) + , _capacity(initalizer_list.size()) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(initalizer_list, _data); + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + */ + vector(vector const & other) + : _size(other._size) + , _capacity(other._capacity) + { + delete[] _data; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + } + + /** + * @brief Copy assignment operator. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + * @return Newly created copy. + */ + [[gnu::section(".stl_text")]] + vector & operator=(vector const & other) + { + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + return *this; + } + + /** + * @brief Destructor. + */ + ~vector() { delete[] _data; } + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _size; + } + + /** + * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we + * exactly require to decrease the amount of allocations and deallocation to improve speed. + * + * @return Current amount of space the vector has for elements. + */ + [[gnu::section(".stl_text")]] + auto capacity() const -> size_type + { + return _capacity; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) -> reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) const -> const_reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) -> reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) const -> const_reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push_back(U && value) -> void + { + increase_capacity_if_full(); + _data[_size] = std::forward(value); + (void)_size++; + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace_back(Args &&... args) -> value_type & + { + increase_capacity_if_full(); + _data[_size] = value_type{std::forward(args)...}; + auto const index = _size++; + return _data[index]; + } + + /** + * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop_back() -> void + { + throw_if_empty(); + (void)_size--; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() noexcept -> pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() const noexcept -> const_pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto cbegin() const noexcept -> const_pointer + { + return begin(); + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() noexcept -> pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() const noexcept -> const_pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto crbegin() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() noexcept -> pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() const noexcept -> const_pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto cend() const noexcept -> const_pointer + { + return end(); + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() noexcept -> pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() const noexcept -> const_pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto crend() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() -> pointer + { + return _data; + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() const -> const_pointer + { + return _data; + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() -> reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() const -> const_reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() -> reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() const -> const_reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without + * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current + * capacity(), new storage is allocated, otherwise the function does nothing. + * + * reserve() does not change the size of the vector. + * + * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the + * elements are invalidated. Otherwise, no iterators or references are invalidated. + * + * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of + * the vector greater than the value of capacity(). + * + * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for + * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing + * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and + * decreased performance. For example, a function that receives an arbitrary vector by reference and appends + * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage + * characteristics. + * + * When inserting a range, the range version of insert() is generally preferable as it preserves the correct + * capacity growth behavior, unlike reserve() followed by a series of push_back()s. + * + * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. + * + * @param new_capacity New capacity of the vector, in number of elements + */ + [[gnu::section(".stl_text")]] + auto reserve(size_type new_capacity) -> void + { + if (new_capacity <= _capacity) + { + return; + } + + _capacity = new_capacity; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). + * + * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are + * invalidated. If no reallocation occurs, no iterators or references are invalidated. + */ + [[gnu::section(".stl_text")]] + auto shrink_to_fit() -> void + { + if (_size == _capacity) + { + return; + } + + _capacity = _size; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _size <= 0; + } + + private: + /** + * @brief Halts the execution of the application if the data container is currently empty. + */ + auto throw_if_empty() const -> void + { + if (empty()) + { + os::panic("[Vector] Attempted to access element of currently empty vector"); + } + } + + auto throw_if_out_of_range(size_type index) const -> void + { + if (index >= _size) + { + os::panic("[Vector] Attempted to read element at invalid index"); + } + } + + /** + * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential + * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is + * normally perferable for the cache. + */ + auto increase_capacity_if_full() -> void + { + if (_size == _capacity) + { + reserve(_capacity == 0U ? 1U : _capacity * 2U); + } + } + + size_type _size = {}; ///< Amount of elements in the underlying data container + size_type _capacity = {}; ///< Amount of space for elements in the underlying data container + value_type * _data = {}; ///< Pointer to the first element in the underlying data container + }; + +} // namespace kstd + +#endif -- cgit v1.2.3 From 576935b6448802138639a324535614e0a966ead1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:16:19 +0000 Subject: libs: move unique_ptr to kstd --- libs/kstd/include/kstd/unique_pointer.hpp | 206 ++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 libs/kstd/include/kstd/unique_pointer.hpp (limited to 'libs') diff --git a/libs/kstd/include/kstd/unique_pointer.hpp b/libs/kstd/include/kstd/unique_pointer.hpp new file mode 100644 index 0000000..2861646 --- /dev/null +++ b/libs/kstd/include/kstd/unique_pointer.hpp @@ -0,0 +1,206 @@ +#ifndef KSTD_UNIQUE_POINTER_HPP +#define KSTD_UNIQUE_POINTER_HPP + +#include + +namespace kstd +{ + /** + * @brief Unique_pointer is a smart pointer that owns (is responsible for) and manages another object via a pointer + * and subsequently disposes of that object when the unique_pointer goes out of scope. + * + * @tparam T Type of the managed object. + */ + template + struct unique_pointer + { + /** + * @brief Constructor. + * + * @param ptr A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit unique_pointer(T * ptr = nullptr) + : pointer(ptr) + { + // Nothing to do. + } + + /** + * @brief Destructor that deletes the managed object. + */ + [[gnu::section(".stl_text")]] + ~unique_pointer() + { + delete pointer; + } + + /** + * @brief Deleted copy constructor to enforce unique ownership. + */ + unique_pointer(const unique_pointer &) = delete; + + /** + * @brief Deleted copy assignment operator to enforce unique ownership. + */ + auto operator=(const unique_pointer &) -> unique_pointer & = delete; + + /** + * @brief Move constructor. + * + * @param other Unique pointer to move from. + */ + [[gnu::section(".stl_text")]] + unique_pointer(unique_pointer && other) noexcept + : pointer(other.pointer) + { + other.pointer = nullptr; + } + + /** + * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). + * + * @param other Smart pointer from which ownership will be transferred. + * @return Reference to this unique pointer. + */ + [[gnu::section(".stl_text")]] + auto operator=(unique_pointer && other) noexcept -> unique_pointer & + { + if (this != &other) + { + delete pointer; + pointer = other.pointer; + other.pointer = nullptr; + } + return *this; + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const noexcept + { + return pointer != nullptr; + } + + /** + * @brief Releases the ownership of the managed object, if any. + * get() returns nullptr after the call. + * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). + * + * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be + * returned by get() before the call. + */ + [[gnu::section(".stl_text")]] + auto release() -> T * + { + T * temp = pointer; + pointer = nullptr; + return temp; + } + + /** + * @brief Replaces the managed object. + * + * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, + * except where provided as a compiler extension or as a debugging assert. Note that code such as + * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + auto reset(T * ptr = nullptr) -> void + { + delete pointer; + pointer = ptr; + } + + /** + * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. + * + * @param other Another unique_ptr object to swap the managed object and the deleter with. + */ + [[gnu::section(".stl_text")]] + auto swap(unique_pointer & other) -> void + { + using std::swap; + swap(pointer, other.pointer); + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const unique_pointer & other) const = default; + + private: + T * pointer; ///< The managed pointer. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(unique_pointer & lhs, unique_pointer & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @brief Constructs an object of type T and wraps it in a unique_pointer. Constructs a non-array type T. The + * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is + * not an array type. The function is equivalent to: unique_pointer(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Unique_pointer of an instance of type T. + */ + template + auto make_unique(Args &&... args) -> unique_pointer + { + return unique_pointer(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From f12fa671ccadfdeaca1529157c3bd458f9e37c30 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:18:45 +0000 Subject: libs: move shared_pointer to kstd --- libs/kstd/include/kstd/shared_pointer.hpp | 269 ++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 libs/kstd/include/kstd/shared_pointer.hpp (limited to 'libs') diff --git a/libs/kstd/include/kstd/shared_pointer.hpp b/libs/kstd/include/kstd/shared_pointer.hpp new file mode 100644 index 0000000..4717117 --- /dev/null +++ b/libs/kstd/include/kstd/shared_pointer.hpp @@ -0,0 +1,269 @@ +#ifndef KSTD_SHARED_POINTER_HPP +#define KSTD_SHARED_POINTER_HPP + +#include + +namespace kstd +{ + /** + * @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several + * shared_pointer objects may own the same object. The object is destroyed and its memory deallocated when either of + * the following happens: the last remaining shared_pointer owning the object is destroyed; the last remaining + * shared_pointer owning the object is assigned another pointer via operator= or reset(). A + * shared_pointer can share ownership of an object while storing a pointer to another object. This feature can be used + * to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), + * the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count + * reaches zero. + * + * @tparam T The type of the managed object. + */ + template + struct shared_pointer + { + /** + * @brief Constructor. + * + * @param pointer A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit shared_pointer(T * pointer = nullptr) + : pointer(pointer) + , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @param other The shared_pointer to copy from. + */ + [[gnu::section(".stl_text")]] + shared_pointer(const shared_pointer & other) + : pointer(other.pointer) + , ref_count(other.ref_count) + { + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + /** + * @brief Move constructor. + * + * @param other The shared_pointer to move from. + */ + [[gnu::section(".stl_text")]] + shared_pointer(shared_pointer && other) noexcept + : pointer(other.pointer) + , ref_count(other.ref_count) + { + other.pointer = nullptr; + other.ref_count = nullptr; + } + + /** + * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the + * object managed by r. If r manages no object, *this manages no object too. Equivalent to + * shared_ptr(r).swap(*this). + * + * @param other Another smart pointer to share the ownership with. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_pointer & operator=(const shared_pointer & other) + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + return *this; + } + + /** + * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of + * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). + * + * @param other Another smart pointer to acquire the ownership from. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_pointer & operator=(shared_pointer && other) noexcept + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + other.pointer = nullptr; + other.ref_count = nullptr; + } + + return *this; + } + + /** + * @brief Destructor. Cleans up resources if necessary. + */ + [[gnu::section(".stl_text")]] + ~shared_pointer() + { + cleanup(); + } + + /** + * @brief Replaces the managed object. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + void reset(T * ptr = nullptr) + { + cleanup(); + pointer = ptr; + ref_count = new std::atomic(ptr != nullptr ? 1 : 0); + } + + /** + * @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not + * adjusted. + * + * @param other The shared_pointer to swap with. + */ + [[gnu::section(".stl_text")]] + void swap(shared_pointer & other) + { + std::swap(pointer, other.pointer); + std::swap(ref_count, other.ref_count); + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Returns the number of different shared_pointer instances (*this included) managing the current object. If + * there is no managed object, ​0​ is returned. + * + * @note Common use cases include comparison with ​0​. If use_count returns zero, the shared pointer is empty + * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, + * there are no other owners. + * + * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed + * object. + */ + [[gnu::section(".stl_text")]] + auto use_count() const -> std::size_t + { + if (pointer != nullptr) + { + return *ref_count; + } + + return 0; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const + { + return pointer != nullptr; + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const shared_pointer & other) const = default; + + private: + /** + * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + */ + [[gnu::section(".stl_text")]] + auto cleanup() -> void + { + if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) + { + delete pointer; + delete ref_count; + } + } + + T * pointer; ///< The managed object. + std::atomic * ref_count; ///< Reference count. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(shared_pointer & lhs, shared_pointer & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @brief Constructs an object of type T and wraps it in a shared_pointer. Constructs a non-array type T. The + * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is + * not an array type. The function is equivalent to: shared_pointer(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Shared_pointer of an instance of type T. + */ + template + auto make_shared(Args &&... args) -> shared_pointer + { + return shared_pointer(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From be0d5d9453edb871393cd8ee5c83ad15f6ef8c9d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:21:01 +0000 Subject: libs: move stack to kstd --- libs/kstd/include/kstd/stack.hpp | 213 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 libs/kstd/include/kstd/stack.hpp (limited to 'libs') diff --git a/libs/kstd/include/kstd/stack.hpp b/libs/kstd/include/kstd/stack.hpp new file mode 100644 index 0000000..8c702cf --- /dev/null +++ b/libs/kstd/include/kstd/stack.hpp @@ -0,0 +1,213 @@ +#ifndef KSTD_STACK_HPP +#define KSTD_STACK_HPP + +#include "kstd/vector.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the stack instance should contain. + * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires + * access to pop_back(), push_back(), back(), size(), empty() and emplace_back() + */ + template> + struct stack + { + using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. + using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. + using size_type = Container::size_type; ///< Type of the size in the underlying container. + using reference = Container::reference; ///< Type of reference to the elements. + using const_reference = Container::const_reference; ///< Type of constant reference to the elements. + + /** + * @brief Default Constructor. + */ + stack() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + [[gnu::section(".stl_text")]] + explicit stack(size_type n, value_type initial = value_type{}) + : _container(n, initial) + { + // Nothing to do. + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + [[gnu::section(".stl_text")]] + explicit stack(InputIterator first, InputIterator last) + : _container(first, last) + { + // Nothing to do. + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + [[gnu::section(".stl_text")]] + explicit stack(std::initializer_list initalizer_list) + : _container(initalizer_list) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all + * elements from it. + * + * @param other Other instance of stack we want to copy the data from. + */ + [[gnu::section(".stl_text")]] + stack(stack const & other) + : _container(other) + { + // Nothing to do. + } + + /** + * @brief Copy assignment operator. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + * @return Newly created copy. + */ + [[gnu::section(".stl_text")]] + stack & operator=(stack const & other) + { + _container = other; + } + + /** + * @brief Destructor. + */ + ~stack() = default; + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _container.size(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() -> reference + { + return _container.back(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() const -> const_reference + { + return _container.back(); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push(U && value) -> void + { + _container.push_back(std::forward(value)); + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace(Args &&... args) -> reference + { + _container.emplace_back(std::forward(args)...); + } + + /** + * @brief Removes the last element of the container. + * + * @note Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop() -> void + { + _container.pop_back(); + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _container.empty(); + } + + private: + container_type _container = {}; ///< Underlying container used by the stack to actually save the data. + }; + +} // namespace kstd + +#endif -- cgit v1.2.3 From 4e99a7586748f9acd7027abc4c86a8df5f0c2e6f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:26:05 +0000 Subject: kstd: improve resemblence of STL --- libs/kstd/include/kstd/bits/shared_ptr.hpp | 269 +++++++++++++++++++++++++++++ libs/kstd/include/kstd/bits/unique_ptr.hpp | 206 ++++++++++++++++++++++ libs/kstd/include/kstd/memory.hpp | 7 + libs/kstd/include/kstd/shared_pointer.hpp | 269 ----------------------------- libs/kstd/include/kstd/unique_pointer.hpp | 206 ---------------------- 5 files changed, 482 insertions(+), 475 deletions(-) create mode 100644 libs/kstd/include/kstd/bits/shared_ptr.hpp create mode 100644 libs/kstd/include/kstd/bits/unique_ptr.hpp create mode 100644 libs/kstd/include/kstd/memory.hpp delete mode 100644 libs/kstd/include/kstd/shared_pointer.hpp delete mode 100644 libs/kstd/include/kstd/unique_pointer.hpp (limited to 'libs') diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp new file mode 100644 index 0000000..d41b165 --- /dev/null +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -0,0 +1,269 @@ +#ifndef KSTD_BITS_SHARED_PTR_HPP +#define KSTD_BITS_SHARED_PTR_HPP + +#include + +namespace kstd +{ + /** + * @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several + * shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of + * the following happens: the last remaining shared_ptr owning the object is destroyed; the last remaining + * shared_ptr owning the object is assigned another pointer via operator= or reset(). A + * shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used + * to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), + * the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count + * reaches zero. + * + * @tparam T The type of the managed object. + */ + template + struct shared_ptr + { + /** + * @brief Constructor. + * + * @param pointer A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit shared_ptr(T * pointer = nullptr) + : pointer(pointer) + , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @param other The shared_ptr to copy from. + */ + [[gnu::section(".stl_text")]] + shared_ptr(const shared_ptr & other) + : pointer(other.pointer) + , ref_count(other.ref_count) + { + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + /** + * @brief Move constructor. + * + * @param other The shared_ptr to move from. + */ + [[gnu::section(".stl_text")]] + shared_ptr(shared_ptr && other) noexcept + : pointer(other.pointer) + , ref_count(other.ref_count) + { + other.pointer = nullptr; + other.ref_count = nullptr; + } + + /** + * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the + * object managed by r. If r manages no object, *this manages no object too. Equivalent to + * shared_ptr(r).swap(*this). + * + * @param other Another smart pointer to share the ownership with. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_ptr & operator=(const shared_ptr & other) + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + + if (pointer != nullptr) + { + ++(*ref_count); + } + } + + return *this; + } + + /** + * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of + * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). + * + * @param other Another smart pointer to acquire the ownership from. + * @return Reference to this shared pointer. + */ + [[gnu::section(".stl_text")]] + shared_ptr & operator=(shared_ptr && other) noexcept + { + if (this != &other) + { + cleanup(); + pointer = other.pointer; + ref_count = other.ref_count; + other.pointer = nullptr; + other.ref_count = nullptr; + } + + return *this; + } + + /** + * @brief Destructor. Cleans up resources if necessary. + */ + [[gnu::section(".stl_text")]] + ~shared_ptr() + { + cleanup(); + } + + /** + * @brief Replaces the managed object. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + void reset(T * ptr = nullptr) + { + cleanup(); + pointer = ptr; + ref_count = new std::atomic(ptr != nullptr ? 1 : 0); + } + + /** + * @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not + * adjusted. + * + * @param other The shared_ptr to swap with. + */ + [[gnu::section(".stl_text")]] + void swap(shared_ptr & other) + { + std::swap(pointer, other.pointer); + std::swap(ref_count, other.ref_count); + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Returns the number of different shared_ptr instances (*this included) managing the current object. If + * there is no managed object, ​0​ is returned. + * + * @note Common use cases include comparison with ​0​. If use_count returns zero, the shared pointer is empty + * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, + * there are no other owners. + * + * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed + * object. + */ + [[gnu::section(".stl_text")]] + auto use_count() const -> std::size_t + { + if (pointer != nullptr) + { + return *ref_count; + } + + return 0; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const + { + return pointer != nullptr; + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const shared_ptr & other) const = default; + + private: + /** + * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + */ + [[gnu::section(".stl_text")]] + auto cleanup() -> void + { + if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) + { + delete pointer; + delete ref_count; + } + } + + T * pointer; ///< The managed object. + std::atomic * ref_count; ///< Reference count. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(shared_ptr & lhs, shared_ptr & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @brief Constructs an object of type T and wraps it in a shared_ptr. Constructs a non-array type T. The + * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is + * not an array type. The function is equivalent to: shared_ptr(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Shared_pointer of an instance of type T. + */ + template + auto make_shared(Args &&... args) -> shared_ptr + { + return shared_ptr(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/unique_ptr.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp new file mode 100644 index 0000000..1932913 --- /dev/null +++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp @@ -0,0 +1,206 @@ +#ifndef KSTD_BITS_UNIQUE_POINTER_HPP +#define KSTD_BITS_UNIQUE_POINTER_HPP + +#include + +namespace kstd +{ + /** + * @brief Unique_pointer is a smart pointer that owns (is responsible for) and manages another object via a pointer + * and subsequently disposes of that object when the unique_ptr goes out of scope. + * + * @tparam T Type of the managed object. + */ + template + struct unique_ptr + { + /** + * @brief Constructor. + * + * @param ptr A pointer to an object to manage (default is nullptr). + */ + [[gnu::section(".stl_text")]] + explicit unique_ptr(T * ptr = nullptr) + : pointer(ptr) + { + // Nothing to do. + } + + /** + * @brief Destructor that deletes the managed object. + */ + [[gnu::section(".stl_text")]] + ~unique_ptr() + { + delete pointer; + } + + /** + * @brief Deleted copy constructor to enforce unique ownership. + */ + unique_ptr(const unique_ptr &) = delete; + + /** + * @brief Deleted copy assignment operator to enforce unique ownership. + */ + auto operator=(const unique_ptr &) -> unique_ptr & = delete; + + /** + * @brief Move constructor. + * + * @param other Unique pointer to move from. + */ + [[gnu::section(".stl_text")]] + unique_ptr(unique_ptr && other) noexcept + : pointer(other.pointer) + { + other.pointer = nullptr; + } + + /** + * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). + * + * @param other Smart pointer from which ownership will be transferred. + * @return Reference to this unique pointer. + */ + [[gnu::section(".stl_text")]] + auto operator=(unique_ptr && other) noexcept -> unique_ptr & + { + if (this != &other) + { + delete pointer; + pointer = other.pointer; + other.pointer = nullptr; + } + return *this; + } + + /** + * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. + * + * @return Returns the object owned by *this, equivalent to *get(). + */ + [[gnu::section(".stl_text")]] + auto operator*() const -> T & + { + return *pointer; + } + + /** + * @brief Member access operator. + * + * @return Returns a pointer to the object owned by *this, i.e. get(). + */ + [[gnu::section(".stl_text")]] + auto operator->() const -> T * + { + return pointer; + } + + /** + * @brief Returns a pointer to the managed object or nullptr if no object is owned. + * + * @return Pointer to the managed object or nullptr if no object is owned. + */ + [[gnu::section(".stl_text")]] + auto get() const -> T * + { + return pointer; + } + + /** + * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. + * + * @return true if *this owns an object, false otherwise. + */ + [[gnu::section(".stl_text")]] + explicit operator bool() const noexcept + { + return pointer != nullptr; + } + + /** + * @brief Releases the ownership of the managed object, if any. + * get() returns nullptr after the call. + * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). + * + * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be + * returned by get() before the call. + */ + [[gnu::section(".stl_text")]] + auto release() -> T * + { + T * temp = pointer; + pointer = nullptr; + return temp; + } + + /** + * @brief Replaces the managed object. + * + * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, + * except where provided as a compiler extension or as a debugging assert. Note that code such as + * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. + * + * @param ptr Pointer to a new object to manage (default = nullptr). + */ + [[gnu::section(".stl_text")]] + auto reset(T * ptr = nullptr) -> void + { + delete pointer; + pointer = ptr; + } + + /** + * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. + * + * @param other Another unique_ptr object to swap the managed object and the deleter with. + */ + [[gnu::section(".stl_text")]] + auto swap(unique_ptr & other) -> void + { + using std::swap; + swap(pointer, other.pointer); + } + + /** + * @brief Defaulted three-way comparator operator. + */ + [[gnu::section(".stl_text")]] + auto operator<=>(const unique_ptr & other) const = default; + + private: + T * pointer; ///< The managed pointer. + }; + + /** + * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls + * lhs.swap(rhs). + * + * @tparam T Type of the managed object. + * @param lhs, rhs Smart pointers whose contents to swap. + */ + template + auto swap(unique_ptr & lhs, unique_ptr & rhs) -> void + { + lhs.swap(rhs); + } + + /** + * @brief Constructs an object of type T and wraps it in a unique_ptr. Constructs a non-array type T. The + * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is + * not an array type. The function is equivalent to: unique_ptr(new T(std::forward(args)...)). + * + * @tparam T Type of the managed object. + * @tparam Args Argument types for T's constructor. + * @param args List of arguments with which an instance of T will be constructed. + * @returns Unique_pointer of an instance of type T. + */ + template + auto make_unique(Args &&... args) -> unique_ptr + { + return unique_ptr(new T(std::forward(args)...)); + } +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/memory.hpp b/libs/kstd/include/kstd/memory.hpp new file mode 100644 index 0000000..cab2fba --- /dev/null +++ b/libs/kstd/include/kstd/memory.hpp @@ -0,0 +1,7 @@ +#ifndef KSTD_SHARED_POINTER_HPP +#define KSTD_SHARED_POINTER_HPP + +#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export +#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/shared_pointer.hpp b/libs/kstd/include/kstd/shared_pointer.hpp deleted file mode 100644 index 4717117..0000000 --- a/libs/kstd/include/kstd/shared_pointer.hpp +++ /dev/null @@ -1,269 +0,0 @@ -#ifndef KSTD_SHARED_POINTER_HPP -#define KSTD_SHARED_POINTER_HPP - -#include - -namespace kstd -{ - /** - * @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several - * shared_pointer objects may own the same object. The object is destroyed and its memory deallocated when either of - * the following happens: the last remaining shared_pointer owning the object is destroyed; the last remaining - * shared_pointer owning the object is assigned another pointer via operator= or reset(). A - * shared_pointer can share ownership of an object while storing a pointer to another object. This feature can be used - * to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), - * the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count - * reaches zero. - * - * @tparam T The type of the managed object. - */ - template - struct shared_pointer - { - /** - * @brief Constructor. - * - * @param pointer A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit shared_pointer(T * pointer = nullptr) - : pointer(pointer) - , ref_count(new std::atomic(pointer != nullptr ? 1 : 0)) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @param other The shared_pointer to copy from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(const shared_pointer & other) - : pointer(other.pointer) - , ref_count(other.ref_count) - { - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - /** - * @brief Move constructor. - * - * @param other The shared_pointer to move from. - */ - [[gnu::section(".stl_text")]] - shared_pointer(shared_pointer && other) noexcept - : pointer(other.pointer) - , ref_count(other.ref_count) - { - other.pointer = nullptr; - other.ref_count = nullptr; - } - - /** - * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the - * object managed by r. If r manages no object, *this manages no object too. Equivalent to - * shared_ptr(r).swap(*this). - * - * @param other Another smart pointer to share the ownership with. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(const shared_pointer & other) - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - - if (pointer != nullptr) - { - ++(*ref_count); - } - } - - return *this; - } - - /** - * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of - * the previous state of r, and r is empty. Equivalent to shared_ptr(std::move(r)).swap(*this). - * - * @param other Another smart pointer to acquire the ownership from. - * @return Reference to this shared pointer. - */ - [[gnu::section(".stl_text")]] - shared_pointer & operator=(shared_pointer && other) noexcept - { - if (this != &other) - { - cleanup(); - pointer = other.pointer; - ref_count = other.ref_count; - other.pointer = nullptr; - other.ref_count = nullptr; - } - - return *this; - } - - /** - * @brief Destructor. Cleans up resources if necessary. - */ - [[gnu::section(".stl_text")]] - ~shared_pointer() - { - cleanup(); - } - - /** - * @brief Replaces the managed object. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - void reset(T * ptr = nullptr) - { - cleanup(); - pointer = ptr; - ref_count = new std::atomic(ptr != nullptr ? 1 : 0); - } - - /** - * @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not - * adjusted. - * - * @param other The shared_pointer to swap with. - */ - [[gnu::section(".stl_text")]] - void swap(shared_pointer & other) - { - std::swap(pointer, other.pointer); - std::swap(ref_count, other.ref_count); - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Returns the number of different shared_pointer instances (*this included) managing the current object. If - * there is no managed object, ​0​ is returned. - * - * @note Common use cases include comparison with ​0​. If use_count returns zero, the shared pointer is empty - * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1, - * there are no other owners. - * - * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed - * object. - */ - [[gnu::section(".stl_text")]] - auto use_count() const -> std::size_t - { - if (pointer != nullptr) - { - return *ref_count; - } - - return 0; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const - { - return pointer != nullptr; - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const shared_pointer & other) const = default; - - private: - /** - * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. - */ - [[gnu::section(".stl_text")]] - auto cleanup() -> void - { - if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0) - { - delete pointer; - delete ref_count; - } - } - - T * pointer; ///< The managed object. - std::atomic * ref_count; ///< Reference count. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(shared_pointer & lhs, shared_pointer & rhs) -> void - { - lhs.swap(rhs); - } - - /** - * @brief Constructs an object of type T and wraps it in a shared_pointer. Constructs a non-array type T. The - * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is - * not an array type. The function is equivalent to: shared_pointer(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Shared_pointer of an instance of type T. - */ - template - auto make_shared(Args &&... args) -> shared_pointer - { - return shared_pointer(new T(std::forward(args)...)); - } -} // namespace kstd - -#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/unique_pointer.hpp b/libs/kstd/include/kstd/unique_pointer.hpp deleted file mode 100644 index 2861646..0000000 --- a/libs/kstd/include/kstd/unique_pointer.hpp +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef KSTD_UNIQUE_POINTER_HPP -#define KSTD_UNIQUE_POINTER_HPP - -#include - -namespace kstd -{ - /** - * @brief Unique_pointer is a smart pointer that owns (is responsible for) and manages another object via a pointer - * and subsequently disposes of that object when the unique_pointer goes out of scope. - * - * @tparam T Type of the managed object. - */ - template - struct unique_pointer - { - /** - * @brief Constructor. - * - * @param ptr A pointer to an object to manage (default is nullptr). - */ - [[gnu::section(".stl_text")]] - explicit unique_pointer(T * ptr = nullptr) - : pointer(ptr) - { - // Nothing to do. - } - - /** - * @brief Destructor that deletes the managed object. - */ - [[gnu::section(".stl_text")]] - ~unique_pointer() - { - delete pointer; - } - - /** - * @brief Deleted copy constructor to enforce unique ownership. - */ - unique_pointer(const unique_pointer &) = delete; - - /** - * @brief Deleted copy assignment operator to enforce unique ownership. - */ - auto operator=(const unique_pointer &) -> unique_pointer & = delete; - - /** - * @brief Move constructor. - * - * @param other Unique pointer to move from. - */ - [[gnu::section(".stl_text")]] - unique_pointer(unique_pointer && other) noexcept - : pointer(other.pointer) - { - other.pointer = nullptr; - } - - /** - * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). - * - * @param other Smart pointer from which ownership will be transferred. - * @return Reference to this unique pointer. - */ - [[gnu::section(".stl_text")]] - auto operator=(unique_pointer && other) noexcept -> unique_pointer & - { - if (this != &other) - { - delete pointer; - pointer = other.pointer; - other.pointer = nullptr; - } - return *this; - } - - /** - * @brief Dereference operator. If get() is a null pointer, the behavior is undefined. - * - * @return Returns the object owned by *this, equivalent to *get(). - */ - [[gnu::section(".stl_text")]] - auto operator*() const -> T & - { - return *pointer; - } - - /** - * @brief Member access operator. - * - * @return Returns a pointer to the object owned by *this, i.e. get(). - */ - [[gnu::section(".stl_text")]] - auto operator->() const -> T * - { - return pointer; - } - - /** - * @brief Returns a pointer to the managed object or nullptr if no object is owned. - * - * @return Pointer to the managed object or nullptr if no object is owned. - */ - [[gnu::section(".stl_text")]] - auto get() const -> T * - { - return pointer; - } - - /** - * @brief Checks whether *this owns an object, i.e. whether get() != nullptr. - * - * @return true if *this owns an object, false otherwise. - */ - [[gnu::section(".stl_text")]] - explicit operator bool() const noexcept - { - return pointer != nullptr; - } - - /** - * @brief Releases the ownership of the managed object, if any. - * get() returns nullptr after the call. - * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()). - * - * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be - * returned by get() before the call. - */ - [[gnu::section(".stl_text")]] - auto release() -> T * - { - T * temp = pointer; - pointer = nullptr; - return temp; - } - - /** - * @brief Replaces the managed object. - * - * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed, - * except where provided as a compiler extension or as a debugging assert. Note that code such as - * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does. - * - * @param ptr Pointer to a new object to manage (default = nullptr). - */ - [[gnu::section(".stl_text")]] - auto reset(T * ptr = nullptr) -> void - { - delete pointer; - pointer = ptr; - } - - /** - * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other. - * - * @param other Another unique_ptr object to swap the managed object and the deleter with. - */ - [[gnu::section(".stl_text")]] - auto swap(unique_pointer & other) -> void - { - using std::swap; - swap(pointer, other.pointer); - } - - /** - * @brief Defaulted three-way comparator operator. - */ - [[gnu::section(".stl_text")]] - auto operator<=>(const unique_pointer & other) const = default; - - private: - T * pointer; ///< The managed pointer. - }; - - /** - * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls - * lhs.swap(rhs). - * - * @tparam T Type of the managed object. - * @param lhs, rhs Smart pointers whose contents to swap. - */ - template - auto swap(unique_pointer & lhs, unique_pointer & rhs) -> void - { - lhs.swap(rhs); - } - - /** - * @brief Constructs an object of type T and wraps it in a unique_pointer. Constructs a non-array type T. The - * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is - * not an array type. The function is equivalent to: unique_pointer(new T(std::forward(args)...)). - * - * @tparam T Type of the managed object. - * @tparam Args Argument types for T's constructor. - * @param args List of arguments with which an instance of T will be constructed. - * @returns Unique_pointer of an instance of type T. - */ - template - auto make_unique(Args &&... args) -> unique_pointer - { - return unique_pointer(new T(std::forward(args)...)); - } -} // namespace kstd - -#endif \ No newline at end of file -- cgit v1.2.3 From 833738f7023324172dbb0922fe1be9ad9cc88330 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 20:35:38 +0000 Subject: libs: rename kstd headers to be more STL like --- libs/kstd/CMakeLists.txt | 9 +- libs/kstd/include/kstd/memory | 7 + libs/kstd/include/kstd/memory.hpp | 7 - libs/kstd/include/kstd/mutex | 60 ++++ libs/kstd/include/kstd/mutex.hpp | 60 ---- libs/kstd/include/kstd/stack | 213 ++++++++++++++ libs/kstd/include/kstd/stack.hpp | 213 -------------- libs/kstd/include/kstd/vector | 596 ++++++++++++++++++++++++++++++++++++++ libs/kstd/include/kstd/vector.hpp | 596 -------------------------------------- libs/kstd/src/mutex.cpp | 2 +- 10 files changed, 885 insertions(+), 878 deletions(-) create mode 100644 libs/kstd/include/kstd/memory delete mode 100644 libs/kstd/include/kstd/memory.hpp create mode 100644 libs/kstd/include/kstd/mutex delete mode 100644 libs/kstd/include/kstd/mutex.hpp create mode 100644 libs/kstd/include/kstd/stack delete mode 100644 libs/kstd/include/kstd/stack.hpp create mode 100644 libs/kstd/include/kstd/vector delete mode 100644 libs/kstd/include/kstd/vector.hpp (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index a29fac8..b0abaaf 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -9,7 +9,14 @@ target_sources("kstd" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES - "include/kstd/mutex.hpp" + "include/kstd/bits/os.hpp" + "include/kstd/bits/shared_ptr.hpp" + "include/kstd/bits/unique_ptr.hpp" + + "include/kstd/memory" + "include/kstd/mutex" + "include/kstd/stack" + "include/kstd/vector" ) target_include_directories("kstd" PUBLIC diff --git a/libs/kstd/include/kstd/memory b/libs/kstd/include/kstd/memory new file mode 100644 index 0000000..cab2fba --- /dev/null +++ b/libs/kstd/include/kstd/memory @@ -0,0 +1,7 @@ +#ifndef KSTD_SHARED_POINTER_HPP +#define KSTD_SHARED_POINTER_HPP + +#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export +#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/memory.hpp b/libs/kstd/include/kstd/memory.hpp deleted file mode 100644 index cab2fba..0000000 --- a/libs/kstd/include/kstd/memory.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef KSTD_SHARED_POINTER_HPP -#define KSTD_SHARED_POINTER_HPP - -#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export -#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export - -#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/mutex b/libs/kstd/include/kstd/mutex new file mode 100644 index 0000000..cf8549f --- /dev/null +++ b/libs/kstd/include/kstd/mutex @@ -0,0 +1,60 @@ +#ifndef KSTD_MUTEX_HPP +#define KSTD_MUTEX_HPP + +#include + +namespace kstd +{ + /** + * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in + * use by another thread or not. + */ + struct mutex + { + /** + * @brief Defaulted constructor. + */ + mutex() = default; + + /** + * @brief Defaulted destructor. + */ + ~mutex() = default; + + /** + * @brief Deleted copy constructor. + */ + mutex(const mutex &) = delete; + + /** + * @brief Deleted assignment operator. + */ + mutex & operator=(const mutex &) = delete; + + /** + * @brief Lock the mutex (blocks for as long as it is not available). + */ + [[gnu::section(".stl_text")]] + auto lock() -> void; + + /** + * @brief Try to lock the mutex (non-blocking). + * + * @return True if lock has been acquired and false otherwise. + */ + [[gnu::section(".stl_text")]] + auto try_lock() -> bool; + + /** + * @brief Unlock the mutex. + */ + [[gnu::section(".stl_text")]] + auto unlock() -> void; + + private: + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. + }; + +} // namespace kstd + +#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/mutex.hpp b/libs/kstd/include/kstd/mutex.hpp deleted file mode 100644 index cf8549f..0000000 --- a/libs/kstd/include/kstd/mutex.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef KSTD_MUTEX_HPP -#define KSTD_MUTEX_HPP - -#include - -namespace kstd -{ - /** - * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in - * use by another thread or not. - */ - struct mutex - { - /** - * @brief Defaulted constructor. - */ - mutex() = default; - - /** - * @brief Defaulted destructor. - */ - ~mutex() = default; - - /** - * @brief Deleted copy constructor. - */ - mutex(const mutex &) = delete; - - /** - * @brief Deleted assignment operator. - */ - mutex & operator=(const mutex &) = delete; - - /** - * @brief Lock the mutex (blocks for as long as it is not available). - */ - [[gnu::section(".stl_text")]] - auto lock() -> void; - - /** - * @brief Try to lock the mutex (non-blocking). - * - * @return True if lock has been acquired and false otherwise. - */ - [[gnu::section(".stl_text")]] - auto try_lock() -> bool; - - /** - * @brief Unlock the mutex. - */ - [[gnu::section(".stl_text")]] - auto unlock() -> void; - - private: - std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. - }; - -} // namespace kstd - -#endif \ No newline at end of file diff --git a/libs/kstd/include/kstd/stack b/libs/kstd/include/kstd/stack new file mode 100644 index 0000000..8c702cf --- /dev/null +++ b/libs/kstd/include/kstd/stack @@ -0,0 +1,213 @@ +#ifndef KSTD_STACK_HPP +#define KSTD_STACK_HPP + +#include "kstd/vector.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the stack instance should contain. + * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires + * access to pop_back(), push_back(), back(), size(), empty() and emplace_back() + */ + template> + struct stack + { + using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. + using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. + using size_type = Container::size_type; ///< Type of the size in the underlying container. + using reference = Container::reference; ///< Type of reference to the elements. + using const_reference = Container::const_reference; ///< Type of constant reference to the elements. + + /** + * @brief Default Constructor. + */ + stack() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + [[gnu::section(".stl_text")]] + explicit stack(size_type n, value_type initial = value_type{}) + : _container(n, initial) + { + // Nothing to do. + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + [[gnu::section(".stl_text")]] + explicit stack(InputIterator first, InputIterator last) + : _container(first, last) + { + // Nothing to do. + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + [[gnu::section(".stl_text")]] + explicit stack(std::initializer_list initalizer_list) + : _container(initalizer_list) + { + // Nothing to do. + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all + * elements from it. + * + * @param other Other instance of stack we want to copy the data from. + */ + [[gnu::section(".stl_text")]] + stack(stack const & other) + : _container(other) + { + // Nothing to do. + } + + /** + * @brief Copy assignment operator. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + * @return Newly created copy. + */ + [[gnu::section(".stl_text")]] + stack & operator=(stack const & other) + { + _container = other; + } + + /** + * @brief Destructor. + */ + ~stack() = default; + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _container.size(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() -> reference + { + return _container.back(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto top() const -> const_reference + { + return _container.back(); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push(U && value) -> void + { + _container.push_back(std::forward(value)); + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace(Args &&... args) -> reference + { + _container.emplace_back(std::forward(args)...); + } + + /** + * @brief Removes the last element of the container. + * + * @note Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop() -> void + { + _container.pop_back(); + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _container.empty(); + } + + private: + container_type _container = {}; ///< Underlying container used by the stack to actually save the data. + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/include/kstd/stack.hpp b/libs/kstd/include/kstd/stack.hpp deleted file mode 100644 index 8c702cf..0000000 --- a/libs/kstd/include/kstd/stack.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef KSTD_STACK_HPP -#define KSTD_STACK_HPP - -#include "kstd/vector.hpp" - -#include - -namespace kstd -{ - /** - * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the stack instance should contain. - * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires - * access to pop_back(), push_back(), back(), size(), empty() and emplace_back() - */ - template> - struct stack - { - using container_type = Container; ///< Type of the underlying container used to implement stack-like interface. - using value_type = Container::value_type; ///< Type of the elements contained in the underlying container. - using size_type = Container::size_type; ///< Type of the size in the underlying container. - using reference = Container::reference; ///< Type of reference to the elements. - using const_reference = Container::const_reference; ///< Type of constant reference to the elements. - - /** - * @brief Default Constructor. - */ - stack() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - [[gnu::section(".stl_text")]] - explicit stack(size_type n, value_type initial = value_type{}) - : _container(n, initial) - { - // Nothing to do. - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - [[gnu::section(".stl_text")]] - explicit stack(InputIterator first, InputIterator last) - : _container(first, last) - { - // Nothing to do. - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - [[gnu::section(".stl_text")]] - explicit stack(std::initializer_list initalizer_list) - : _container(initalizer_list) - { - // Nothing to do. - } - - /** - * @brief Copy constructor. - * - * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all - * elements from it. - * - * @param other Other instance of stack we want to copy the data from. - */ - [[gnu::section(".stl_text")]] - stack(stack const & other) - : _container(other) - { - // Nothing to do. - } - - /** - * @brief Copy assignment operator. - * - * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all - * elements from it. - * - * @param other Other instance of vector we want to copy the data from. - * @return Newly created copy. - */ - [[gnu::section(".stl_text")]] - stack & operator=(stack const & other) - { - _container = other; - } - - /** - * @brief Destructor. - */ - ~stack() = default; - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _container.size(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() -> reference - { - return _container.back(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto top() const -> const_reference - { - return _container.back(); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push(U && value) -> void - { - _container.push_back(std::forward(value)); - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace(Args &&... args) -> reference - { - _container.emplace_back(std::forward(args)...); - } - - /** - * @brief Removes the last element of the container. - * - * @note Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop() -> void - { - _container.pop_back(); - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _container.empty(); - } - - private: - container_type _container = {}; ///< Underlying container used by the stack to actually save the data. - }; - -} // namespace kstd - -#endif diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector new file mode 100644 index 0000000..1009e81 --- /dev/null +++ b/libs/kstd/include/kstd/vector @@ -0,0 +1,596 @@ +#ifndef KSTD_VECTOR_HPP +#define KSTD_VECTOR_HPP + +#include "bits/os.hpp" + +#include + +namespace kstd +{ + /** + * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our + * custom memory management. + * + * @tparam T Element the vector instance should contain. + */ + template + struct vector + { + using value_type = T; ///< Type of the elements contained in the container. + using size_type = std::size_t; ///< Type of the size in the container. + using reference = value_type &; ///< Type of reference to the elements. + using const_reference = value_type const &; ///< Type of constant reference to the elements. + using pointer = value_type *; ///< Type of pointer to the elements. + using const_pointer = value_type const *; ///< Type of constant pointer to the elements. + + /** + * @brief Default Constructor. + */ + vector() = default; + + /** + * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * constructed value. + * + * @param n Amount of elements we want to create and set the given value for. + * @param initial Inital value of all elements in the underlying data array. + */ + explicit vector(size_type n, value_type initial = value_type{}) + : _size(n) + , _capacity(n) + , _data(new value_type[_capacity]{}) + { + std::ranges::fill(*this, initial); + } + + /** + * @brief Constructs data by copying all element from the given exclusive range. + * + * @tparam InputIterator Template that should have atleast input iterator characteristics. + * @param first Input iterator to the first element in the range we want to copy from. + * @param last Input iterator to one past the last element in the range we want to copy from. + */ + template + explicit vector(InputIterator first, InputIterator last) + : _size(std::distance(first, last)) + , _capacity(std::distance(first, last)) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(first, last, _data); + } + + /** + * @brief Construct data by copying all elements from the initializer list. + * + * @param initalizer_list List we want to copy all elements from. + */ + explicit vector(std::initializer_list initalizer_list) + : _size(initalizer_list.size()) + , _capacity(initalizer_list.size()) + , _data(new value_type[_capacity]{}) + { + std::ranges::copy(initalizer_list, _data); + } + + /** + * @brief Copy constructor. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + */ + vector(vector const & other) + : _size(other._size) + , _capacity(other._capacity) + { + delete[] _data; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + } + + /** + * @brief Copy assignment operator. + * + * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all + * elements from it. + * + * @param other Other instance of vector we want to copy the data from. + * @return Newly created copy. + */ + [[gnu::section(".stl_text")]] + vector & operator=(vector const & other) + { + delete[] _data; + _size = other._size; + _capacity = other._capacity; + _data = new value_type[_capacity]{}; + std::ranges::copy(other, _data); + return *this; + } + + /** + * @brief Destructor. + */ + ~vector() { delete[] _data; } + + /** + * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If + * that is the case the capacity is increased automatically. + * + * @return Current amount of elements. + */ + [[gnu::section(".stl_text")]] + auto size() const -> size_type + { + return _size; + } + + /** + * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we + * exactly require to decrease the amount of allocations and deallocation to improve speed. + * + * @return Current amount of space the vector has for elements. + */ + [[gnu::section(".stl_text")]] + auto capacity() const -> size_type + { + return _capacity; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) -> reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Does not do any bounds checks use at() for that. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto operator[](size_type index) const -> const_reference + { + return _data[index]; + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) -> reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Array indexing operator. Allowing to access element at the given index. + * + * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. + * + * @param index Index we want to access elements at. + * @return Reference to the underlying element. + */ + [[gnu::section(".stl_text")]] + auto at(size_type index) const -> const_reference + { + throw_if_out_of_range(index); + return this->operator[](index); + } + + /** + * @brief Appends the given element value to the end of the container. The element is assigned through the + * assignment operator of the template type. The value is forwarded to the constructor as + * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). + * + * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, + * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. + * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @param value The value of the element to append. + */ + template + [[gnu::section(".stl_text")]] + auto push_back(U && value) -> void + { + increase_capacity_if_full(); + _data[_size] = std::forward(value); + (void)_size++; + } + + /** + * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the + * template type. The arguments args... are forwarded to the constructor as std::forward(args).... + * + * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case + * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only + * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which + * allows the template method to be used by both lvalue and rvalues and compile a different implementation. + * + * @tparam Args + * @param args Arguments to forward to the constructor of the element + * @return value_type& + */ + template + [[gnu::section(".stl_text")]] + auto emplace_back(Args &&... args) -> value_type & + { + increase_capacity_if_full(); + _data[_size] = value_type{std::forward(args)...}; + auto const index = _size++; + return _data[index]; + } + + /** + * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the + * further execution. Iterators and references to the last element are invalidated. The end() + * iterator is also invalidated. + */ + [[gnu::section(".stl_text")]] + auto pop_back() -> void + { + throw_if_empty(); + (void)_size--; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() noexcept -> pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto begin() const noexcept -> const_pointer + { + return _data; + } + + /** + * @brief Returns an iterator to the first element of the vector. + * If the vector is empty, the returned iterator will be equal to end(). + * + * @return Iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto cbegin() const noexcept -> const_pointer + { + return begin(); + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() noexcept -> pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto rbegin() const noexcept -> const_pointer + { + return _data + _size - 1; + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element + * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). + * + * @return Reverse iterator to the first element. + */ + [[gnu::section(".stl_text")]] + auto crbegin() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() noexcept -> pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto end() const noexcept -> const_pointer + { + return _data + _size; + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto cend() const noexcept -> const_pointer + { + return end(); + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() noexcept -> pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto rend() const noexcept -> const_pointer + { + return _data + size() - 1; + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It + * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a + * placeholder, attempting to access it results in undefined behavior. + * + * @return Reverse iterator to the element following the last element. + */ + [[gnu::section(".stl_text")]] + auto crend() const noexcept -> const_pointer + { + return rbegin(); + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() -> pointer + { + return _data; + } + + /** + * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range + * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable + * in that case). + * + * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal + * to the address of the first element. + */ + [[gnu::section(".stl_text")]] + auto data() const -> const_pointer + { + return _data; + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() -> reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the first element in the container. Calling front on an empty container causes + * undefined behavior. + * + * @return Reference to the first element. + */ + [[gnu::section(".stl_text")]] + auto front() const -> const_reference + { + throw_if_empty(); + return *begin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() -> reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Returns a reference to the last element in the container. Calling back on an empty container causes + * undefined behavior. + * + * @return Reference to the last element. + */ + [[gnu::section(".stl_text")]] + auto back() const -> const_reference + { + throw_if_empty(); + return *rbegin(); + } + + /** + * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without + * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current + * capacity(), new storage is allocated, otherwise the function does nothing. + * + * reserve() does not change the size of the vector. + * + * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the + * elements are invalidated. Otherwise, no iterators or references are invalidated. + * + * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of + * the vector greater than the value of capacity(). + * + * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for + * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing + * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and + * decreased performance. For example, a function that receives an arbitrary vector by reference and appends + * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage + * characteristics. + * + * When inserting a range, the range version of insert() is generally preferable as it preserves the correct + * capacity growth behavior, unlike reserve() followed by a series of push_back()s. + * + * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. + * + * @param new_capacity New capacity of the vector, in number of elements + */ + [[gnu::section(".stl_text")]] + auto reserve(size_type new_capacity) -> void + { + if (new_capacity <= _capacity) + { + return; + } + + _capacity = new_capacity; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). + * + * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are + * invalidated. If no reallocation occurs, no iterators or references are invalidated. + */ + [[gnu::section(".stl_text")]] + auto shrink_to_fit() -> void + { + if (_size == _capacity) + { + return; + } + + _capacity = _size; + value_type * temp = new value_type[_capacity]{}; + std::ranges::copy(begin(), end(), temp); + delete[] _data; + _data = temp; + } + + /** + * @brief Wheter there are currently any items this container or not. + * + * @return True if there are no elements, false if there are. + */ + [[gnu::section(".stl_text")]] + auto empty() const -> bool + { + return _size <= 0; + } + + private: + /** + * @brief Halts the execution of the application if the data container is currently empty. + */ + auto throw_if_empty() const -> void + { + if (empty()) + { + os::panic("[Vector] Attempted to access element of currently empty vector"); + } + } + + auto throw_if_out_of_range(size_type index) const -> void + { + if (index >= _size) + { + os::panic("[Vector] Attempted to read element at invalid index"); + } + } + + /** + * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential + * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is + * normally perferable for the cache. + */ + auto increase_capacity_if_full() -> void + { + if (_size == _capacity) + { + reserve(_capacity == 0U ? 1U : _capacity * 2U); + } + } + + size_type _size = {}; ///< Amount of elements in the underlying data container + size_type _capacity = {}; ///< Amount of space for elements in the underlying data container + value_type * _data = {}; ///< Pointer to the first element in the underlying data container + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/include/kstd/vector.hpp b/libs/kstd/include/kstd/vector.hpp deleted file mode 100644 index 1009e81..0000000 --- a/libs/kstd/include/kstd/vector.hpp +++ /dev/null @@ -1,596 +0,0 @@ -#ifndef KSTD_VECTOR_HPP -#define KSTD_VECTOR_HPP - -#include "bits/os.hpp" - -#include - -namespace kstd -{ - /** - * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our - * custom memory management. - * - * @tparam T Element the vector instance should contain. - */ - template - struct vector - { - using value_type = T; ///< Type of the elements contained in the container. - using size_type = std::size_t; ///< Type of the size in the container. - using reference = value_type &; ///< Type of reference to the elements. - using const_reference = value_type const &; ///< Type of constant reference to the elements. - using pointer = value_type *; ///< Type of pointer to the elements. - using const_pointer = value_type const *; ///< Type of constant pointer to the elements. - - /** - * @brief Default Constructor. - */ - vector() = default; - - /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default - * constructed value. - * - * @param n Amount of elements we want to create and set the given value for. - * @param initial Inital value of all elements in the underlying data array. - */ - explicit vector(size_type n, value_type initial = value_type{}) - : _size(n) - , _capacity(n) - , _data(new value_type[_capacity]{}) - { - std::ranges::fill(*this, initial); - } - - /** - * @brief Constructs data by copying all element from the given exclusive range. - * - * @tparam InputIterator Template that should have atleast input iterator characteristics. - * @param first Input iterator to the first element in the range we want to copy from. - * @param last Input iterator to one past the last element in the range we want to copy from. - */ - template - explicit vector(InputIterator first, InputIterator last) - : _size(std::distance(first, last)) - , _capacity(std::distance(first, last)) - , _data(new value_type[_capacity]{}) - { - std::ranges::copy(first, last, _data); - } - - /** - * @brief Construct data by copying all elements from the initializer list. - * - * @param initalizer_list List we want to copy all elements from. - */ - explicit vector(std::initializer_list initalizer_list) - : _size(initalizer_list.size()) - , _capacity(initalizer_list.size()) - , _data(new value_type[_capacity]{}) - { - std::ranges::copy(initalizer_list, _data); - } - - /** - * @brief Copy constructor. - * - * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all - * elements from it. - * - * @param other Other instance of vector we want to copy the data from. - */ - vector(vector const & other) - : _size(other._size) - , _capacity(other._capacity) - { - delete[] _data; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - } - - /** - * @brief Copy assignment operator. - * - * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all - * elements from it. - * - * @param other Other instance of vector we want to copy the data from. - * @return Newly created copy. - */ - [[gnu::section(".stl_text")]] - vector & operator=(vector const & other) - { - delete[] _data; - _size = other._size; - _capacity = other._capacity; - _data = new value_type[_capacity]{}; - std::ranges::copy(other, _data); - return *this; - } - - /** - * @brief Destructor. - */ - ~vector() { delete[] _data; } - - /** - * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If - * that is the case the capacity is increased automatically. - * - * @return Current amount of elements. - */ - [[gnu::section(".stl_text")]] - auto size() const -> size_type - { - return _size; - } - - /** - * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we - * exactly require to decrease the amount of allocations and deallocation to improve speed. - * - * @return Current amount of space the vector has for elements. - */ - [[gnu::section(".stl_text")]] - auto capacity() const -> size_type - { - return _capacity; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) -> reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Does not do any bounds checks use at() for that. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto operator[](size_type index) const -> const_reference - { - return _data[index]; - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) -> reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Array indexing operator. Allowing to access element at the given index. - * - * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted. - * - * @param index Index we want to access elements at. - * @return Reference to the underlying element. - */ - [[gnu::section(".stl_text")]] - auto at(size_type index) const -> const_reference - { - throw_if_out_of_range(index); - return this->operator[](index); - } - - /** - * @brief Appends the given element value to the end of the container. The element is assigned through the - * assignment operator of the template type. The value is forwarded to the constructor as - * std::forward(value), meaning it is either moved (rvalue) or copied (lvalue). - * - * @note If after the operation the new size() is greater than old capacity() a reallocation takes place, - * in which case all iterators (including the end() iterator) and all references to the elements are invalidated. - * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @param value The value of the element to append. - */ - template - [[gnu::section(".stl_text")]] - auto push_back(U && value) -> void - { - increase_capacity_if_full(); - _data[_size] = std::forward(value); - (void)_size++; - } - - /** - * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the - * template type. The arguments args... are forwarded to the constructor as std::forward(args).... - * - * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case - * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only - * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which - * allows the template method to be used by both lvalue and rvalues and compile a different implementation. - * - * @tparam Args - * @param args Arguments to forward to the constructor of the element - * @return value_type& - */ - template - [[gnu::section(".stl_text")]] - auto emplace_back(Args &&... args) -> value_type & - { - increase_capacity_if_full(); - _data[_size] = value_type{std::forward(args)...}; - auto const index = _size++; - return _data[index]; - } - - /** - * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the - * further execution. Iterators and references to the last element are invalidated. The end() - * iterator is also invalidated. - */ - [[gnu::section(".stl_text")]] - auto pop_back() -> void - { - throw_if_empty(); - (void)_size--; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() noexcept -> pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto begin() const noexcept -> const_pointer - { - return _data; - } - - /** - * @brief Returns an iterator to the first element of the vector. - * If the vector is empty, the returned iterator will be equal to end(). - * - * @return Iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto cbegin() const noexcept -> const_pointer - { - return begin(); - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() noexcept -> pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto rbegin() const noexcept -> const_pointer - { - return _data + _size - 1; - } - - /** - * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element - * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend(). - * - * @return Reverse iterator to the first element. - */ - [[gnu::section(".stl_text")]] - auto crbegin() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() noexcept -> pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto end() const noexcept -> const_pointer - { - return _data + _size; - } - - /** - * @brief Returns an iterator to the element following the last element of the vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto cend() const noexcept -> const_pointer - { - return end(); - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() noexcept -> pointer - { - return _data + size() - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto rend() const noexcept -> const_pointer - { - return _data + size() - 1; - } - - /** - * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It - * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a - * placeholder, attempting to access it results in undefined behavior. - * - * @return Reverse iterator to the element following the last element. - */ - [[gnu::section(".stl_text")]] - auto crend() const noexcept -> const_pointer - { - return rbegin(); - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() -> pointer - { - return _data; - } - - /** - * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range - * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable - * in that case). - * - * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal - * to the address of the first element. - */ - [[gnu::section(".stl_text")]] - auto data() const -> const_pointer - { - return _data; - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() -> reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the first element in the container. Calling front on an empty container causes - * undefined behavior. - * - * @return Reference to the first element. - */ - [[gnu::section(".stl_text")]] - auto front() const -> const_reference - { - throw_if_empty(); - return *begin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() -> reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Returns a reference to the last element in the container. Calling back on an empty container causes - * undefined behavior. - * - * @return Reference to the last element. - */ - [[gnu::section(".stl_text")]] - auto back() const -> const_reference - { - throw_if_empty(); - return *rbegin(); - } - - /** - * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without - * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current - * capacity(), new storage is allocated, otherwise the function does nothing. - * - * reserve() does not change the size of the vector. - * - * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the - * elements are invalidated. Otherwise, no iterators or references are invalidated. - * - * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of - * the vector greater than the value of capacity(). - * - * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for - * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing - * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and - * decreased performance. For example, a function that receives an arbitrary vector by reference and appends - * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage - * characteristics. - * - * When inserting a range, the range version of insert() is generally preferable as it preserves the correct - * capacity growth behavior, unlike reserve() followed by a series of push_back()s. - * - * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided. - * - * @param new_capacity New capacity of the vector, in number of elements - */ - [[gnu::section(".stl_text")]] - auto reserve(size_type new_capacity) -> void - { - if (new_capacity <= _capacity) - { - return; - } - - _capacity = new_capacity; - value_type * temp = new value_type[_capacity]{}; - std::ranges::copy(begin(), end(), temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size(). - * - * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are - * invalidated. If no reallocation occurs, no iterators or references are invalidated. - */ - [[gnu::section(".stl_text")]] - auto shrink_to_fit() -> void - { - if (_size == _capacity) - { - return; - } - - _capacity = _size; - value_type * temp = new value_type[_capacity]{}; - std::ranges::copy(begin(), end(), temp); - delete[] _data; - _data = temp; - } - - /** - * @brief Wheter there are currently any items this container or not. - * - * @return True if there are no elements, false if there are. - */ - [[gnu::section(".stl_text")]] - auto empty() const -> bool - { - return _size <= 0; - } - - private: - /** - * @brief Halts the execution of the application if the data container is currently empty. - */ - auto throw_if_empty() const -> void - { - if (empty()) - { - os::panic("[Vector] Attempted to access element of currently empty vector"); - } - } - - auto throw_if_out_of_range(size_type index) const -> void - { - if (index >= _size) - { - os::panic("[Vector] Attempted to read element at invalid index"); - } - } - - /** - * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential - * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is - * normally perferable for the cache. - */ - auto increase_capacity_if_full() -> void - { - if (_size == _capacity) - { - reserve(_capacity == 0U ? 1U : _capacity * 2U); - } - } - - size_type _size = {}; ///< Amount of elements in the underlying data container - size_type _capacity = {}; ///< Amount of space for elements in the underlying data container - value_type * _data = {}; ///< Pointer to the first element in the underlying data container - }; - -} // namespace kstd - -#endif diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp index cfb1c84..137ebc0 100644 --- a/libs/kstd/src/mutex.cpp +++ b/libs/kstd/src/mutex.cpp @@ -1,4 +1,4 @@ -#include "kstd/mutex.hpp" +#include "kstd/mutex" namespace kstd { -- cgit v1.2.3 From 14ed096fc5de6844cb116f3319c0d03043d26ea2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Jul 2025 21:09:02 +0000 Subject: x86-64: prepare new architecture --- libs/multiboot2/include/multiboot2/impl/data.hpp | 6 +++--- libs/multiboot2/include/multiboot2/impl/iterator.hpp | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index 367e8cb..a5f2e14 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -99,17 +99,17 @@ namespace multiboot2::impl /** * @brief Start address of this region */ - std::uint64_t const base; + std::uint64_t base; /** * @brief Size of this region in bytes. */ - std::uint64_t const size_in_B; + std::uint64_t size_in_B; /** * @brief Type of this region. */ - memory_type const type; + memory_type type; std::uint32_t : 0; }; diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index b84ef2c..e82326d 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -40,7 +40,10 @@ namespace multiboot2::impl { m_current = next; } - m_current.reset(); + else + { + m_current.reset(); + } } return *this; } -- cgit v1.2.3 From e97e86d169849527190cef1913efdd247e6f68df Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:21:32 +0000 Subject: libs: move asm_ptr to kstd --- libs/kstd/CMakeLists.txt | 1 + libs/kstd/include/kstd/asm_ptr | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 libs/kstd/include/kstd/asm_ptr (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index b0abaaf..ac9e78f 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -13,6 +13,7 @@ target_sources("kstd" PUBLIC "include/kstd/bits/shared_ptr.hpp" "include/kstd/bits/unique_ptr.hpp" + "include/kstd/asm_ptr" "include/kstd/memory" "include/kstd/mutex" "include/kstd/stack" diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr new file mode 100644 index 0000000..e9072e2 --- /dev/null +++ b/libs/kstd/include/kstd/asm_ptr @@ -0,0 +1,55 @@ +#ifndef KSTD_ASM_POINTER_HPP +#define KSTD_ASM_POINTER_HPP + +#include + +namespace kstd +{ + + /** + * @brief A pointer that is defined in some assembly source file. + * + * @tparam Type The type of the pointer + */ + template + struct asm_ptr + { + using value_type = Type; + using pointer = value_type *; + using const_pointer = value_type const *; + using reference = value_type &; + using const_reference = value_type const &; + + asm_ptr() = delete; + asm_ptr(asm_ptr const &) = delete; + asm_ptr(asm_ptr &&) = delete; + + auto constexpr operator=(asm_ptr const &) = delete; + auto constexpr operator=(asm_ptr &&) = delete; + + auto get() const noexcept -> pointer { return m_ptr; } + + auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer + { + return std::bit_cast(m_ptr) + offset; + } + + auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } + + auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } + + auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } + + auto constexpr operator->() noexcept -> pointer { return m_ptr; } + + auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } + + private: + pointer m_ptr; + }; + +} // namespace kstd + +#endif \ No newline at end of file -- cgit v1.2.3 From 12dedc7e2e51390fdf2caec3700e75db19be1cd4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 28 Oct 2025 18:31:39 +0100 Subject: kstd: don't rely on newlib --- libs/kstd/CMakeLists.txt | 8 ++++++++ libs/kstd/include/kstd/bits/os.hpp | 2 ++ libs/kstd/src/bits/os.cpp | 10 ++++++++++ libs/kstd/src/cstdlib.cpp | 18 ++++++++++++++++++ libs/kstd/src/cstring.cpp | 10 ++++++++++ 5 files changed, 48 insertions(+) create mode 100644 libs/kstd/src/bits/os.cpp create mode 100644 libs/kstd/src/cstdlib.cpp create mode 100644 libs/kstd/src/cstring.cpp (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index ac9e78f..666a5d7 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -2,6 +2,9 @@ add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") target_sources("kstd" PRIVATE + "src/bits/os.cpp" + "src/cstdlib.cpp" + "src/cstring.cpp" "src/mutex.cpp" ) @@ -23,3 +26,8 @@ target_sources("kstd" PUBLIC target_include_directories("kstd" PUBLIC "include" ) + +target_link_options("kstd" INTERFACE + "-Wl,--undefined=abort" + "-Wl,--undefined=strlen" +) \ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp index 0425b88..7f5fcc8 100644 --- a/libs/kstd/include/kstd/bits/os.hpp +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -6,6 +6,8 @@ namespace kstd::os { + auto abort() -> bool; + [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; } diff --git a/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp new file mode 100644 index 0000000..fb64202 --- /dev/null +++ b/libs/kstd/src/bits/os.cpp @@ -0,0 +1,10 @@ +#include "kstd/bits/os.hpp" + +namespace kstd::os +{ + [[gnu::weak]] + auto abort() -> bool + { + return false; + } +} // namespace kstd::os \ No newline at end of file diff --git a/libs/kstd/src/cstdlib.cpp b/libs/kstd/src/cstdlib.cpp new file mode 100644 index 0000000..8fb5f63 --- /dev/null +++ b/libs/kstd/src/cstdlib.cpp @@ -0,0 +1,18 @@ +#include "kstd/bits/os.hpp" + +namespace kstd +{ + + extern "C" + { + [[noreturn]] auto abort() -> void + { + if (!kstd::os::abort()) + { + os::panic("System abort handler returned."); + } + __builtin_trap(); + } + } + +} // namespace kstd \ No newline at end of file diff --git a/libs/kstd/src/cstring.cpp b/libs/kstd/src/cstring.cpp new file mode 100644 index 0000000..5419b7d --- /dev/null +++ b/libs/kstd/src/cstring.cpp @@ -0,0 +1,10 @@ +#include +#include + +extern "C" +{ + auto strlen(const char * string) -> std::size_t + { + return std::distance(string, std::ranges::find(string, nullptr, '\0')); + } +} -- cgit v1.2.3 From acabbacdee68ad80e829bda56ae5363d04646d2d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 10:39:30 +0100 Subject: kstd: clean up libc implementation --- libs/kstd/CMakeLists.txt | 16 ++++++++++------ libs/kstd/include/kstd/bits/os.hpp | 25 ++++++++++++++++++++++--- libs/kstd/src/bits/os.cpp | 6 +++--- libs/kstd/src/cstdlib.cpp | 18 ------------------ libs/kstd/src/cstring.cpp | 10 ---------- libs/kstd/src/libc/stdlib.cpp | 11 +++++++++++ libs/kstd/src/libc/string.cpp | 15 +++++++++++++++ 7 files changed, 61 insertions(+), 40 deletions(-) delete mode 100644 libs/kstd/src/cstdlib.cpp delete mode 100644 libs/kstd/src/cstring.cpp create mode 100644 libs/kstd/src/libc/stdlib.cpp create mode 100644 libs/kstd/src/libc/string.cpp (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 666a5d7..75c2315 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -1,10 +1,15 @@ add_library("kstd" STATIC) add_library("libs::kstd" ALIAS "kstd") +set(KSTD_LIBC_SYMBOLS + "abort" + "strlen" +) + target_sources("kstd" PRIVATE "src/bits/os.cpp" - "src/cstdlib.cpp" - "src/cstring.cpp" + "src/libc/stdlib.cpp" + "src/libc/string.cpp" "src/mutex.cpp" ) @@ -27,7 +32,6 @@ target_include_directories("kstd" PUBLIC "include" ) -target_link_options("kstd" INTERFACE - "-Wl,--undefined=abort" - "-Wl,--undefined=strlen" -) \ No newline at end of file +list(TRANSFORM KSTD_LIBC_SYMBOLS PREPEND "-Wl,--undefined=") + +target_link_options("kstd" INTERFACE ${KSTD_LIBC_SYMBOLS}) \ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp index 7f5fcc8..0474f16 100644 --- a/libs/kstd/include/kstd/bits/os.hpp +++ b/libs/kstd/include/kstd/bits/os.hpp @@ -6,10 +6,29 @@ namespace kstd::os { - auto abort() -> bool; + /** + * @brief Handle an unrecoverable library error. + * + * The operating system kernel may choose to implement this function in order to try to perform additional cleanup + * before terminating execution. If the kernel does not implement this function, the default implementation will be + * chosen. This default implementation doest nothing. + */ + [[noreturn]] + auto abort() -> void; + /** + * @brief Terminate execution of the operating system. + * + * The operating system must implement this function. This function must terminate the execution of the operating + * system kernel as is. It may choose to restart the kernel or to halt execution entirely. The implementation must + * guarantee that execution never return from this function. + * + * @param message A message describing the reason for termination of execution. + * @param where The source code location at which the panic was triggered. In general, no argument shall be provided + * for this parameter, thus implicitly capturing the location at which the call originates. + */ [[noreturn]] - auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; -} + auto panic(std::string_view message, std::source_location where = std::source_location::current()) -> void; +} // namespace kstd::os #endif \ No newline at end of file diff --git a/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp index fb64202..e6edbfd 100644 --- a/libs/kstd/src/bits/os.cpp +++ b/libs/kstd/src/bits/os.cpp @@ -2,9 +2,9 @@ namespace kstd::os { - [[gnu::weak]] - auto abort() -> bool + [[gnu::weak, noreturn]] + auto abort() -> void { - return false; + os::panic("Abort called."); } } // namespace kstd::os \ No newline at end of file diff --git a/libs/kstd/src/cstdlib.cpp b/libs/kstd/src/cstdlib.cpp deleted file mode 100644 index 8fb5f63..0000000 --- a/libs/kstd/src/cstdlib.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "kstd/bits/os.hpp" - -namespace kstd -{ - - extern "C" - { - [[noreturn]] auto abort() -> void - { - if (!kstd::os::abort()) - { - os::panic("System abort handler returned."); - } - __builtin_trap(); - } - } - -} // namespace kstd \ No newline at end of file diff --git a/libs/kstd/src/cstring.cpp b/libs/kstd/src/cstring.cpp deleted file mode 100644 index 5419b7d..0000000 --- a/libs/kstd/src/cstring.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -extern "C" -{ - auto strlen(const char * string) -> std::size_t - { - return std::distance(string, std::ranges::find(string, nullptr, '\0')); - } -} diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp new file mode 100644 index 0000000..fe1bc95 --- /dev/null +++ b/libs/kstd/src/libc/stdlib.cpp @@ -0,0 +1,11 @@ +#include "kstd/bits/os.hpp" + +namespace kstd::libc +{ + + extern "C" + { + [[noreturn]] auto abort() -> void { kstd::os::abort(); } + } + +} // namespace kstd::libc \ No newline at end of file diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp new file mode 100644 index 0000000..c6b3847 --- /dev/null +++ b/libs/kstd/src/libc/string.cpp @@ -0,0 +1,15 @@ +#include +#include + +namespace kstd::libc +{ + + extern "C" + { + auto strlen(const char * string) -> std::size_t + { + return std::distance(string, std::ranges::find(string, nullptr, '\0')); + } + } + +} // namespace kstd::libc \ No newline at end of file -- cgit v1.2.3 From b157e2c472d8bd67ac1656404a6a6ee821260f4b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 15:01:43 +0100 Subject: chore: reformat source code --- libs/kstd/include/kstd/bits/shared_ptr.hpp | 6 +- libs/kstd/include/kstd/bits/unique_ptr.hpp | 6 +- libs/kstd/src/libc/stdlib.cpp | 5 +- libs/kstd/src/libc/string.cpp | 2 +- libs/kstd/src/mutex.cpp | 10 +- libs/multiboot2/include/multiboot2/constants.hpp | 2 +- libs/multiboot2/include/multiboot2/impl/data.hpp | 7 +- .../include/multiboot2/impl/iterator.hpp | 19 ++-- libs/multiboot2/include/multiboot2/impl/tag.hpp | 34 +++---- libs/multiboot2/include/multiboot2/information.hpp | 102 ++++++++++++++++----- 10 files changed, 136 insertions(+), 57 deletions(-) (limited to 'libs') diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp index d41b165..251c187 100644 --- a/libs/kstd/include/kstd/bits/shared_ptr.hpp +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -39,7 +39,7 @@ namespace kstd * @param other The shared_ptr to copy from. */ [[gnu::section(".stl_text")]] - shared_ptr(const shared_ptr & other) + shared_ptr(shared_ptr const & other) : pointer(other.pointer) , ref_count(other.ref_count) { @@ -72,7 +72,7 @@ namespace kstd * @return Reference to this shared pointer. */ [[gnu::section(".stl_text")]] - shared_ptr & operator=(const shared_ptr & other) + shared_ptr & operator=(shared_ptr const & other) { if (this != &other) { @@ -216,7 +216,7 @@ namespace kstd * @brief Defaulted three-way comparator operator. */ [[gnu::section(".stl_text")]] - auto operator<=>(const shared_ptr & other) const = default; + auto operator<=>(shared_ptr const & other) const = default; private: /** diff --git a/libs/kstd/include/kstd/bits/unique_ptr.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp index 1932913..5f54848 100644 --- a/libs/kstd/include/kstd/bits/unique_ptr.hpp +++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp @@ -38,12 +38,12 @@ namespace kstd /** * @brief Deleted copy constructor to enforce unique ownership. */ - unique_ptr(const unique_ptr &) = delete; + unique_ptr(unique_ptr const &) = delete; /** * @brief Deleted copy assignment operator to enforce unique ownership. */ - auto operator=(const unique_ptr &) -> unique_ptr & = delete; + auto operator=(unique_ptr const &) -> unique_ptr & = delete; /** * @brief Move constructor. @@ -167,7 +167,7 @@ namespace kstd * @brief Defaulted three-way comparator operator. */ [[gnu::section(".stl_text")]] - auto operator<=>(const unique_ptr & other) const = default; + auto operator<=>(unique_ptr const & other) const = default; private: T * pointer; ///< The managed pointer. diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp index fe1bc95..752e616 100644 --- a/libs/kstd/src/libc/stdlib.cpp +++ b/libs/kstd/src/libc/stdlib.cpp @@ -5,7 +5,10 @@ namespace kstd::libc extern "C" { - [[noreturn]] auto abort() -> void { kstd::os::abort(); } + [[noreturn]] auto abort() -> void + { + kstd::os::abort(); + } } } // namespace kstd::libc \ No newline at end of file diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp index c6b3847..a42aedc 100644 --- a/libs/kstd/src/libc/string.cpp +++ b/libs/kstd/src/libc/string.cpp @@ -6,7 +6,7 @@ namespace kstd::libc extern "C" { - auto strlen(const char * string) -> std::size_t + auto strlen(char const * string) -> std::size_t { return std::distance(string, std::ranges::find(string, nullptr, '\0')); } diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp index 137ebc0..da1357f 100644 --- a/libs/kstd/src/mutex.cpp +++ b/libs/kstd/src/mutex.cpp @@ -10,7 +10,13 @@ namespace kstd } } - auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + auto mutex::try_lock() -> bool + { + return !locked.exchange(true, std::memory_order_acquire); + } - auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } + auto mutex::unlock() -> void + { + locked.store(false, std::memory_order_release); + } } // namespace kstd diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp index 30d52d0..0f6b82f 100644 --- a/libs/multiboot2/include/multiboot2/constants.hpp +++ b/libs/multiboot2/include/multiboot2/constants.hpp @@ -13,7 +13,7 @@ namespace multiboot2 using impl::memory_type; using impl::tag_id; - auto constexpr inline header_magic = std::uint32_t{0xe85250d6}; + constexpr auto inline header_magic = std::uint32_t{0xe852'50d6}; } // namespace multiboot2 diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index a5f2e14..3cda162 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -10,7 +10,7 @@ namespace multiboot2::impl template struct tag_data { - auto constexpr inline static id = Id; + constexpr auto static inline id = Id; }; /** @@ -94,7 +94,10 @@ namespace multiboot2::impl /** * @brief Check if the memory described by this region is available for use. */ - auto constexpr available() const noexcept { return type == memory_type::AVAILABLE; } + constexpr auto available() const noexcept + { + return type == memory_type::AVAILABLE; + } /** * @brief Start address of this region diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index e82326d..f8955cb 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -23,16 +23,21 @@ namespace multiboot2::impl constexpr explicit information_iterator(impl::tag_header const * offset) : m_current(offset) - { - } + {} - auto constexpr operator==(information_iterator const &) const noexcept -> bool = default; + constexpr auto operator==(information_iterator const &) const noexcept -> bool = default; - auto constexpr operator*() const noexcept -> reference { return *(m_current.value()); } + constexpr auto operator*() const noexcept -> reference + { + return *(m_current.value()); + } - auto constexpr operator->() const noexcept -> pointer { return m_current.value(); } + constexpr auto operator->() const noexcept -> pointer + { + return m_current.value(); + } - auto constexpr operator++() noexcept -> information_iterator & + constexpr auto operator++() noexcept -> information_iterator & { if (m_current) { @@ -48,7 +53,7 @@ namespace multiboot2::impl return *this; } - auto constexpr operator++(int) noexcept -> information_iterator + constexpr auto operator++(int) noexcept -> information_iterator { auto copy = *this; ++(*this); diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index f7471a4..f151b54 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -18,24 +18,31 @@ namespace multiboot2::impl tag_header() : m_id{} , m_size{} - { - } + {} tag_header(tag_header const * data) : tag_header{*data} + {} + + auto full_size() const noexcept -> std::size_t { + return (m_size + 7) & (~7); } - auto full_size() const noexcept -> std::size_t { return (m_size + 7) & (~7); } - - auto information_id() const noexcept -> impl::information_id const & { return m_id; } + auto information_id() const noexcept -> impl::information_id const & + { + return m_id; + } auto next() const noexcept -> tag_header const * { return std::bit_cast(std::bit_cast(this) + full_size()); } - auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } + auto unaligned_size() const noexcept -> std::uint32_t + { + return m_size; + } protected: impl::information_id const m_id; @@ -51,22 +58,19 @@ namespace multiboot2::impl tag() : tag_header{} , Data{} - { - } + {} explicit tag(tag_header const * header) requires(sizeof(tag) > sizeof(tag_header)) : tag_header{header} , Data{*std::bit_cast(header + 1)} - { - } + {} explicit tag(tag_header const * header) requires(sizeof(tag) == sizeof(tag_header)) : tag_header{header} , Data{} - { - } + {} }; /** @@ -80,14 +84,12 @@ namespace multiboot2::impl vla_tag() : tag{} , m_vla{} - { - } + {} explicit vla_tag(tag_header const * header) : tag{header} , m_vla{vla_start(header), vla_size(header)} - { - } + {} protected: auto static vla_start(tag_header const * header) noexcept -> VlaData * diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 04ba183..ac03069 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -41,7 +41,10 @@ namespace multiboot2 /** * @brief The command line string */ - auto string() const noexcept -> range_type { return m_vla; } + auto string() const noexcept -> range_type + { + return m_vla; + } }; /** @@ -53,7 +56,10 @@ namespace multiboot2 using iterator = range_type::iterator; - auto data() const noexcept -> range_type { return m_vla; } + auto data() const noexcept -> range_type + { + return m_vla; + } }; /** @@ -66,7 +72,10 @@ namespace multiboot2 /** * @brief The name of the bootloader */ - auto string() const noexcept -> std::string_view { return m_vla; } + auto string() const noexcept -> std::string_view + { + return m_vla; + } }; /** @@ -78,14 +87,23 @@ namespace multiboot2 using iterator = range_type::iterator; - auto begin() const noexcept -> iterator { return regions().begin(); } + auto begin() const noexcept -> iterator + { + return regions().begin(); + } - auto end() const noexcept -> iterator { return regions().end(); } + auto end() const noexcept -> iterator + { + return regions().end(); + } /** * @brief The available memory regions */ - auto regions() const noexcept -> range_type { return m_vla; } + auto regions() const noexcept -> range_type + { + return m_vla; + } }; struct information_view @@ -95,13 +113,22 @@ namespace multiboot2 using pointer = impl::information_iterator::pointer; using reference = impl::information_iterator::reference; - auto size_bytes() const noexcept -> std::size_t { return m_size; } + auto size_bytes() const noexcept -> std::size_t + { + return m_size; + } // Range access - auto begin() const noexcept -> iterator { return iterator{&m_tags}; } + auto begin() const noexcept -> iterator + { + return iterator{&m_tags}; + } - auto end() const noexcept -> iterator { return iterator{}; } + auto end() const noexcept -> iterator + { + return iterator{}; + } // Tag access @@ -111,36 +138,69 @@ namespace multiboot2 return get().has_value(); } - auto maybe_basic_memory() const noexcept -> std::optional { return get(); } + auto maybe_basic_memory() const noexcept -> std::optional + { + return get(); + } - auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } + auto basic_memory() const -> basic_memory + { + return maybe_basic_memory().value(); + } auto maybe_bios_boot_device() const noexcept -> std::optional { return get(); } - auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } + auto bios_boot_device() const -> bios_boot_device + { + return maybe_bios_boot_device().value(); + } - auto maybe_command_line() const noexcept -> std::optional { return get(); } + auto maybe_command_line() const noexcept -> std::optional + { + return get(); + } - auto command_line() const -> command_line { return maybe_command_line().value(); } + auto command_line() const -> command_line + { + return maybe_command_line().value(); + } - auto maybe_elf_symbols() const noexcept -> std::optional { return get(); } + auto maybe_elf_symbols() const noexcept -> std::optional + { + return get(); + } - auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } + auto elf_symbols() const -> elf_symbols + { + return maybe_elf_symbols().value(); + } - auto maybe_loader_name() const noexcept -> std::optional { return get(); } + auto maybe_loader_name() const noexcept -> std::optional + { + return get(); + } - auto loader_name() const -> loader_name { return maybe_loader_name().value(); } + auto loader_name() const -> loader_name + { + return maybe_loader_name().value(); + } - auto maybe_memory_map() const noexcept -> std::optional { return get(); } + auto maybe_memory_map() const noexcept -> std::optional + { + return get(); + } - auto memory_map() const -> memory_map { return maybe_memory_map().value(); } + auto memory_map() const -> memory_map + { + return maybe_memory_map().value(); + } private: template - auto constexpr get() const noexcept -> std::optional + constexpr auto get() const noexcept -> std::optional { if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); found != end()) -- cgit v1.2.3 From 7b9df8bec5038e0316540d2397df632fb14c9169 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 17:01:22 +0100 Subject: chore: configure clang-tidy --- libs/kstd/include/kstd/asm_ptr | 42 +++++++++++++++++++++++------- libs/kstd/include/kstd/bits/shared_ptr.hpp | 2 +- libs/kstd/include/kstd/mutex | 17 +++++++++--- libs/kstd/include/kstd/stack | 32 +++++++---------------- libs/kstd/include/kstd/vector | 9 ++++--- libs/kstd/src/libc/stdlib.cpp | 5 ++++ 6 files changed, 68 insertions(+), 39 deletions(-) (limited to 'libs') diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr index e9072e2..e8636c3 100644 --- a/libs/kstd/include/kstd/asm_ptr +++ b/libs/kstd/include/kstd/asm_ptr @@ -23,28 +23,50 @@ namespace kstd asm_ptr() = delete; asm_ptr(asm_ptr const &) = delete; asm_ptr(asm_ptr &&) = delete; + ~asm_ptr() = delete; - auto constexpr operator=(asm_ptr const &) = delete; - auto constexpr operator=(asm_ptr &&) = delete; + constexpr auto operator=(asm_ptr const &) = delete; + constexpr auto operator=(asm_ptr &&) = delete; - auto get() const noexcept -> pointer { return m_ptr; } + auto get() const noexcept -> pointer + { + return m_ptr; + } - auto constexpr operator+(std::ptrdiff_t offset) const noexcept -> pointer + constexpr auto operator+(std::ptrdiff_t offset) const noexcept -> pointer { return std::bit_cast(m_ptr) + offset; } - auto constexpr operator*() noexcept -> reference { return *(std::bit_cast(m_ptr)); } + constexpr auto operator*() noexcept -> reference + { + return *(std::bit_cast(m_ptr)); + } - auto constexpr operator*() const noexcept -> const_reference { return *(std::bit_cast(m_ptr)); } + constexpr auto operator*() const noexcept -> const_reference + { + return *(std::bit_cast(m_ptr)); + } - auto constexpr operator[](std::ptrdiff_t offset) noexcept -> reference { return *(*this + offset); } + constexpr auto operator[](std::ptrdiff_t offset) noexcept -> reference + { + return *(*this + offset); + } - auto constexpr operator[](std::ptrdiff_t offset) const noexcept -> const_reference { return *(*this + offset); } + constexpr auto operator[](std::ptrdiff_t offset) const noexcept -> const_reference + { + return *(*this + offset); + } - auto constexpr operator->() noexcept -> pointer { return m_ptr; } + constexpr auto operator->() noexcept -> pointer + { + return m_ptr; + } - auto constexpr operator->() const noexcept -> const_pointer { return m_ptr; } + constexpr auto operator->() const noexcept -> const_pointer + { + return m_ptr; + } private: pointer m_ptr; diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp index 251c187..4bcf499 100644 --- a/libs/kstd/include/kstd/bits/shared_ptr.hpp +++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp @@ -220,7 +220,7 @@ namespace kstd private: /** - * @brief Releases ownership and deletes the object if this was the last ereference to the owned managed object. + * @brief Releases ownership and deletes the object if this was the last reference to the owned managed object. */ [[gnu::section(".stl_text")]] auto cleanup() -> void diff --git a/libs/kstd/include/kstd/mutex b/libs/kstd/include/kstd/mutex index cf8549f..6ae3adf 100644 --- a/libs/kstd/include/kstd/mutex +++ b/libs/kstd/include/kstd/mutex @@ -24,12 +24,23 @@ namespace kstd /** * @brief Deleted copy constructor. */ - mutex(const mutex &) = delete; + mutex(mutex const &) = delete; /** - * @brief Deleted assignment operator. + * @brief Deleted move constructor. + * + */ + mutex(mutex &&) = delete; + + /** + * @brief Deleted copy assignment operator. + */ + auto operator=(mutex const &) -> mutex & = delete; + + /** + * @brief Deleted move assignment operator. */ - mutex & operator=(const mutex &) = delete; + auto operator=(mutex &&) -> mutex & = delete; /** * @brief Lock the mutex (blocks for as long as it is not available). diff --git a/libs/kstd/include/kstd/stack b/libs/kstd/include/kstd/stack index 8c702cf..8cd208a 100644 --- a/libs/kstd/include/kstd/stack +++ b/libs/kstd/include/kstd/stack @@ -1,8 +1,7 @@ #ifndef KSTD_STACK_HPP #define KSTD_STACK_HPP -#include "kstd/vector.hpp" - +#include "kstd/vector" #include namespace kstd @@ -29,8 +28,12 @@ namespace kstd */ stack() = default; + stack(stack const &) = delete; + stack(stack &&) = delete; + auto operator=(stack const &) -> stack & = delete; + auto operator=(stack &&) -> stack & = delete; /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * @brief Constructs data with the given amount of elements containing the given value or alternatively the default * constructed value. * * @param n Amount of elements we want to create and set the given value for. @@ -61,11 +64,11 @@ namespace kstd /** * @brief Construct data by copying all elements from the initializer list. * - * @param initalizer_list List we want to copy all elements from. + * @param elements List we want to copy all elements from. */ [[gnu::section(".stl_text")]] - explicit stack(std::initializer_list initalizer_list) - : _container(initalizer_list) + explicit stack(std::initializer_list elements) + : _container(elements) { // Nothing to do. } @@ -85,21 +88,6 @@ namespace kstd // Nothing to do. } - /** - * @brief Copy assignment operator. - * - * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all - * elements from it. - * - * @param other Other instance of vector we want to copy the data from. - * @return Newly created copy. - */ - [[gnu::section(".stl_text")]] - stack & operator=(stack const & other) - { - _container = other; - } - /** * @brief Destructor. */ @@ -194,7 +182,7 @@ namespace kstd } /** - * @brief Wheter there are currently any items this container or not. + * @brief Whether there are currently any items this container or not. * * @return True if there are no elements, false if there are. */ diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector index 1009e81..9d96eb8 100644 --- a/libs/kstd/include/kstd/vector +++ b/libs/kstd/include/kstd/vector @@ -29,7 +29,7 @@ namespace kstd vector() = default; /** - * @brief Constructs data with the given amount of elements containg the given value or alterantively the default + * @brief Constructs data with the given amount of elements containing the given value or alternatively the default * constructed value. * * @param n Amount of elements we want to create and set the given value for. @@ -99,7 +99,7 @@ namespace kstd * @return Newly created copy. */ [[gnu::section(".stl_text")]] - vector & operator=(vector const & other) + auto operator=(vector const & other) -> vector & { delete[] _data; _size = other._size; @@ -112,7 +112,10 @@ namespace kstd /** * @brief Destructor. */ - ~vector() { delete[] _data; } + ~vector() + { + delete[] _data; + } /** * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp index 752e616..a0f062a 100644 --- a/libs/kstd/src/libc/stdlib.cpp +++ b/libs/kstd/src/libc/stdlib.cpp @@ -9,6 +9,11 @@ namespace kstd::libc { kstd::os::abort(); } + + [[noreturn, gnu::weak]] auto free(void *) -> void + { + kstd::os::panic("Tried to call free."); + } } } // namespace kstd::libc \ No newline at end of file -- cgit v1.2.3 From 78f0df1cf849af8b0ade40a8ebcffd7fb53635cb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 30 Oct 2025 15:59:48 +0100 Subject: libs: begin ELF support implementation --- libs/CMakeLists.txt | 1 + libs/elf/CMakeLists.txt | 19 ++++++++++++++++ libs/elf/include/elf/format.hpp | 15 +++++++++++++ libs/elf/include/elf/section_header.hpp | 23 ++++++++++++++++++++ libs/multiboot2/CMakeLists.txt | 8 +++++++ libs/multiboot2/include/multiboot2/information.hpp | 25 ++++++++++++++-------- 6 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 libs/elf/CMakeLists.txt create mode 100644 libs/elf/include/elf/format.hpp create mode 100644 libs/elf/include/elf/section_header.hpp (limited to 'libs') diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index b2dbf86..58d9796 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory("elf" EXCLUDE_FROM_ALL SYSTEM) add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM) add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ No newline at end of file diff --git a/libs/elf/CMakeLists.txt b/libs/elf/CMakeLists.txt new file mode 100644 index 0000000..66e59ee --- /dev/null +++ b/libs/elf/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library("elf" INTERFACE) +add_library("libs::elf" ALIAS "elf") + +target_sources("elf" INTERFACE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/elf/format.hpp" + "include/elf/section_header.hpp" + +) + +target_include_directories("elf" INTERFACE + "include" +) + +set_target_properties("elf" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES +) \ No newline at end of file diff --git a/libs/elf/include/elf/format.hpp b/libs/elf/include/elf/format.hpp new file mode 100644 index 0000000..b3220f5 --- /dev/null +++ b/libs/elf/include/elf/format.hpp @@ -0,0 +1,15 @@ +#ifndef ELF_FORMAT_HPP +#define ELF_FORMAT_HPP + +namespace elf +{ + + enum struct format + { + elf32, + elf64, + }; + +} // namespace elf + +#endif \ No newline at end of file diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp new file mode 100644 index 0000000..0ff5e4b --- /dev/null +++ b/libs/elf/include/elf/section_header.hpp @@ -0,0 +1,23 @@ +#ifndef ELF_SECTION_HEADER_HPP +#define ELF_SECTION_HEADER_HPP + +#include "format.hpp" + +#include + +namespace elf +{ + + enum struct section_header_type : std::uint32_t + { + }; + + template + struct section_header + { + std::uint32_t name_offset; + section_header_type type; + }; +} // namespace elf + +#endif \ No newline at end of file diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index 7b9e58a..350a996 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -17,3 +17,11 @@ target_sources("multiboot2" INTERFACE target_include_directories("multiboot2" INTERFACE "include" ) + +target_link_libraries("multiboot2" INTERFACE + "libs::elf" +) + +set_target_properties("multiboot2" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES +) \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index ac03069..d2b4c98 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -5,6 +5,9 @@ #include "impl/iterator.hpp" #include "impl/tag.hpp" +#include +#include + #include #include #include @@ -50,15 +53,17 @@ namespace multiboot2 /** * @copydoc multiboot2::impl::elf_symbols_data */ - struct elf_symbols : impl::vla_tag + template + struct elf_symbols : impl::vla_tag const, std::span> { - using vla_tag::vla_tag; + using base = impl::vla_tag const, std::span>; + using base::base; - using iterator = range_type::iterator; + using iterator = base::range_type::iterator; - auto data() const noexcept -> range_type + auto data() const noexcept -> base::range_type { - return m_vla; + return this->m_vla; } }; @@ -168,14 +173,16 @@ namespace multiboot2 return maybe_command_line().value(); } - auto maybe_elf_symbols() const noexcept -> std::optional + template + auto maybe_elf_symbols() const noexcept -> std::optional> { - return get(); + return get>(); } - auto elf_symbols() const -> elf_symbols + template + auto elf_symbols() const -> elf_symbols { - return maybe_elf_symbols().value(); + return maybe_elf_symbols().value(); } auto maybe_loader_name() const noexcept -> std::optional -- cgit v1.2.3 From 31c5f011b2c7b4cc65d4017d92c2fe0bdf7f4ba6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 31 Oct 2025 11:16:12 +0100 Subject: libs/elf: implement section headers --- libs/elf/include/elf/section_header.hpp | 66 ++++++++++++++++++++-- libs/multiboot2/include/multiboot2/information.hpp | 12 +++- 2 files changed, 72 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp index 0ff5e4b..73e2e7b 100644 --- a/libs/elf/include/elf/section_header.hpp +++ b/libs/elf/include/elf/section_header.hpp @@ -4,20 +4,76 @@ #include "format.hpp" #include +#include +#include namespace elf { - enum struct section_header_type : std::uint32_t - { - }; + template + constexpr auto inline section_header_size = std::numeric_limits::max(); + + template<> + constexpr auto inline section_header_size = 40uz; + + template<> + constexpr auto inline section_header_size = 64uz; template struct section_header { - std::uint32_t name_offset; - section_header_type type; + using format_uint = std::conditional_t; + + enum struct header_type : std::uint32_t + { + null = 0, ///< Is inactive + program_data = 1, ///< Contains program data + symbol_table = 2, ///< Contains a symbol table + string_table = 3, ///< Contains a string table + relocation_entries_with_addends = 4, ///< Contains relocation information with addends + hash_table = 5, ///< Contains a symbol hash table + dynamic_linking_entries = 6, ///< Contains dynamic linking information + notes = 7, ///< Contains additional notes about the object file + no_content = 8, ///< Contains no data + relocation_entries_without_addends = 9, ///< Contains relocation information without addends + reserved = 10, ///< Reserved for future use + dynamic_linker_symbol_table = 11, ///< Contains the dynamic linker symbol table + init_array = 14, ///< Contains an array of constructor pointers + fini_array = 15, ///< Contains an array of destructor pointers + preinit_array = 16, ///< Contains an array of pre-constructor pointers + group_table = 17, ///< Defines a section group + extended_section_header_indices = 18, ///< Contains extended section header indices + }; + + enum struct header_flags : format_uint + { + writeable = 0x1, ///< Contains writable data + allocated = 0x2, ///< Occupies memory during execution + executable = 0x4, ///< Contains executable instructions + mergeable = 0x10, ///< Contained data may be merged for deduplication + strings = 0x20, ///< Contains null-terminated strings + info_link = 0x40, ///< Contains the section header index of linked section + link_order = 0x80, ///< Must respect linking location relative to linked section + os_specific = 0x100, ///< Must be handled in an OS specific way + group_member = 0x200, ///< Is a member of a section group + thread_local_storage = 0x400, ///< Contains thread local storage data + compressed = 0x800, ///< Is compressed + }; + + std::uint32_t name_offset; ///< Offset into the section header string table, defining the section name + header_type type; ///< Type of this section + header_flags flags; ///< Flags of this section + format_uint virtual_load_address; ///< Virtual address where this section is loaded + format_uint file_offset; ///< Offset of the start of this section's data in the file + format_uint size; ///< Size of this section in memory + std::uint32_t linked_section; ///< Index of a section this section is linked to + std::uint32_t extra_info; ///< Additional information for this section (type and flag dependent) + format_uint alignment; ///< Alignment requirement of this section in memory + format_uint entry_size; ///< Size of the entries inside this section (if any) }; + + static_assert(sizeof(section_header) == section_header_size); + static_assert(sizeof(section_header) == section_header_size); } // namespace elf #endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index d2b4c98..462528d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -176,7 +176,17 @@ namespace multiboot2 template auto maybe_elf_symbols() const noexcept -> std::optional> { - return get>(); + return get>().and_then( + [](auto x) -> std::optional> { + if (x.entry_size == elf::section_header_size) + { + return std::optional{x}; + } + else + { + return std::nullopt; + } + }); } template -- cgit v1.2.3 From c01073b04a6dcdf067342cf17fe5363a66d85eed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 14:48:31 +0100 Subject: multiboot2: add range support to VLA tags --- libs/multiboot2/include/multiboot2/impl/tag.hpp | 85 +++++++++++++++++++++- libs/multiboot2/include/multiboot2/information.hpp | 25 +------ 2 files changed, 84 insertions(+), 26 deletions(-) (limited to 'libs') diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index f151b54..5edcd6f 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace multiboot2::impl @@ -79,7 +80,18 @@ namespace multiboot2::impl template typename Range> struct vla_tag : tag { - using range_type = Range; + using range_type = Range; + + using iterator = range_type::const_iterator; + using const_iterator = range_type::const_iterator; + using reverse_iterator = range_type::const_reverse_iterator; + using const_reverse_iterator = range_type::const_reverse_iterator; + using size_type = range_type::size_type; + using difference_type = range_type::difference_type; + using reference = range_type::const_reference; + using const_reference = range_type::const_reference; + using pointer = range_type::const_pointer; + using const_pointer = range_type::const_pointer; vla_tag() : tag{} @@ -91,10 +103,75 @@ namespace multiboot2::impl , m_vla{vla_start(header), vla_size(header)} {} - protected: + [[nodiscard]] auto begin() const noexcept -> const_iterator + { + return m_vla.begin(); + } + + [[nodiscard]] auto end() const noexcept -> const_iterator + { + return m_vla.end(); + } + + [[nodiscard]] auto cbegin() const noexcept -> const_iterator + { + return begin(); + } + + [[nodiscard]] auto cend() const noexcept -> const_iterator + { + return end(); + } + + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator + { + return m_vla.rbegin(); + } + + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator + { + return m_vla.rend(); + } + + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + [[nodiscard]] auto front() const noexcept -> const_reference + { + return m_vla.front(); + } + + [[nodiscard]] auto back() const noexcept -> const_reference + { + return m_vla.back(); + } + + [[nodiscard]] auto size() const noexcept -> std::size_t + { + return m_vla.size(); + } + + [[nodiscard]] auto empty() const noexcept -> bool + { + return m_vla.empty(); + } + + [[nodiscard]] auto data() const noexcept -> const_pointer + { + return m_vla.data(); + } + + private: auto static vla_start(tag_header const * header) noexcept -> VlaData * { - auto raw = std::bit_cast(header); + auto raw = std::bit_cast(header); auto start = raw + sizeof(tag); return std::bit_cast(start); } @@ -107,7 +184,7 @@ namespace multiboot2::impl return size; } - range_type const m_vla; + range_type m_vla; }; } // namespace multiboot2::impl diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 462528d..4be32aa 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -46,7 +46,7 @@ namespace multiboot2 */ auto string() const noexcept -> range_type { - return m_vla; + return {data(), size()}; } }; @@ -58,13 +58,6 @@ namespace multiboot2 { using base = impl::vla_tag const, std::span>; using base::base; - - using iterator = base::range_type::iterator; - - auto data() const noexcept -> base::range_type - { - return this->m_vla; - } }; /** @@ -79,7 +72,7 @@ namespace multiboot2 */ auto string() const noexcept -> std::string_view { - return m_vla; + return {data(), size()}; } }; @@ -90,24 +83,12 @@ namespace multiboot2 { using vla_tag::vla_tag; - using iterator = range_type::iterator; - - auto begin() const noexcept -> iterator - { - return regions().begin(); - } - - auto end() const noexcept -> iterator - { - return regions().end(); - } - /** * @brief The available memory regions */ auto regions() const noexcept -> range_type { - return m_vla; + return {data(), size()}; } }; -- cgit v1.2.3 From 53402f496ee07351923945f523565f9aa618005a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 15:13:57 +0100 Subject: elf: add basic section_header flag tests --- libs/elf/include/elf/section_header.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'libs') diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp index 73e2e7b..3afe334 100644 --- a/libs/elf/include/elf/section_header.hpp +++ b/libs/elf/include/elf/section_header.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace elf { @@ -60,6 +61,24 @@ namespace elf compressed = 0x800, ///< Is compressed }; + //! Check if the section is allocated + [[nodiscard]] constexpr auto allocated() const noexcept -> bool + { + return std::to_underlying(flags) & std::to_underlying(header_flags::allocated); + } + + //! Check if the section is executable + [[nodiscard]] constexpr auto executable() const noexcept -> bool + { + return std::to_underlying(flags) & std::to_underlying(header_flags::executable); + } + + //! Check if the section is writeable + [[nodiscard]] constexpr auto writable() const noexcept -> bool + { + return std::to_underlying(flags) & std::to_underlying(header_flags::writeable); + } + std::uint32_t name_offset; ///< Offset into the section header string table, defining the section name header_type type; ///< Type of this section header_flags flags; ///< Flags of this section @@ -74,6 +93,7 @@ namespace elf static_assert(sizeof(section_header) == section_header_size); static_assert(sizeof(section_header) == section_header_size); + } // namespace elf #endif \ No newline at end of file -- cgit v1.2.3 From 1124eb4e0a88e7cd13d6ebd9820d6ddcde343110 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:22:53 +0100 Subject: multiboot2: implement section name reading --- libs/multiboot2/include/multiboot2/impl/tag.hpp | 20 ++++++++++++++++---- libs/multiboot2/include/multiboot2/information.hpp | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index 5edcd6f..a6e2678 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -82,16 +82,18 @@ namespace multiboot2::impl { using range_type = Range; + using value_type = range_type::value_type; + using reference = range_type::const_reference; + using const_reference = range_type::const_reference; + using pointer = range_type::const_pointer; + using const_pointer = range_type::const_pointer; + using iterator = range_type::const_iterator; using const_iterator = range_type::const_iterator; using reverse_iterator = range_type::const_reverse_iterator; using const_reverse_iterator = range_type::const_reverse_iterator; using size_type = range_type::size_type; using difference_type = range_type::difference_type; - using reference = range_type::const_reference; - using const_reference = range_type::const_reference; - using pointer = range_type::const_pointer; - using const_pointer = range_type::const_pointer; vla_tag() : tag{} @@ -168,6 +170,16 @@ namespace multiboot2::impl return m_vla.data(); } + [[nodiscard]] auto at() const -> const_reference + { + return m_vla.at(); + } + + [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference + { + return m_vla[index]; + } + private: auto static vla_start(tag_header const * header) noexcept -> VlaData * { diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 4be32aa..25f034d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,19 @@ namespace multiboot2 { using base = impl::vla_tag const, std::span>; using base::base; + + [[nodiscard]] auto name(elf::section_header const & section) const noexcept -> std::string_view + { + if (!this->string_table_index) + { + std::abort(); + } + + auto string_table = this->begin()[this->string_table_index]; + auto name_offset = section.name_offset; + auto name_array = std::bit_cast(string_table.virtual_load_address); + return name_array + name_offset; + } }; /** -- cgit v1.2.3 From 178d566278f580ed5625d2d34831b4d263ee09af Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:33:01 +0100 Subject: multiboot2: silence some warnings --- libs/multiboot2/include/multiboot2/impl/data.hpp | 12 +++--- libs/multiboot2/include/multiboot2/impl/ids.hpp | 8 ++-- .../include/multiboot2/impl/iterator.hpp | 2 + libs/multiboot2/include/multiboot2/impl/tag.hpp | 21 ++++++----- libs/multiboot2/include/multiboot2/information.hpp | 44 +++++++++++----------- 5 files changed, 48 insertions(+), 39 deletions(-) (limited to 'libs') diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index 3cda162..733ce3a 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_DATA_HPP #define MULTIBOOT2_IMPL_DATA_HPP +// IWYU pragma: private + #include "multiboot2/impl/ids.hpp" #include @@ -23,14 +25,14 @@ namespace multiboot2::impl * * The maximum possible value for this field is 640 KiB. */ - std::uint32_t const lower_KiB; + std::uint32_t lower_KiB; /** * @brief Amount of upper memory (above 1MiB) available to the system. * * The maximum possible value for this field is the address of the first upper memory hole minus 1MiB. */ - std::uint32_t const upper_KiB; + std::uint32_t upper_KiB; }; /** @@ -94,7 +96,7 @@ namespace multiboot2::impl /** * @brief Check if the memory described by this region is available for use. */ - constexpr auto available() const noexcept + [[nodiscard]] constexpr auto available() const noexcept { return type == memory_type::AVAILABLE; } @@ -120,12 +122,12 @@ namespace multiboot2::impl /** * @brief Size of each entry present in the map */ - std::uint32_t const entry_size; + std::uint32_t entry_size; /** * @brief Version of each entry present in the map */ - std::uint32_t const entry_version; + std::uint32_t entry_version; }; } // namespace multiboot2::impl diff --git a/libs/multiboot2/include/multiboot2/impl/ids.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp index 3a7215e..98bc1f2 100644 --- a/libs/multiboot2/include/multiboot2/impl/ids.hpp +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_IDS_HPP #define MULTIBOOT2_IMPL_IDS_HPP +// IWYU pragma: private + #include namespace multiboot2::impl @@ -24,14 +26,14 @@ namespace multiboot2::impl APM_INFO, ///< Advanced Power Management information. EFI32, ///< EFI 32 bit system table pointer. EFI64, ///< EFI 64 bit system table pointer. - SMBIOS, ///< Contains copy of all Sytem Management BIOS tables. + SMBIOS, ///< Contains copy of all System Management BIOS tables. ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification. ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification. NETWORK, ///< Contains network information specified specified as DHCP. EFI_MEMORY_MAP, ///< Contains EFI memory map. - EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called. + EFI_BS_NOT_TERMINATED, ///< Indicates ExitBootServices wasn't called. EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. - EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit image handle pointer. LOAD_BASE_ADDRESS ///< Contains image load base physical address. }; diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index f8955cb..5651f22 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP #define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP +// IWYU pragma: private + #include "multiboot2/impl/ids.hpp" #include "multiboot2/impl/tag.hpp" diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp index a6e2678..3d0cea5 100644 --- a/libs/multiboot2/include/multiboot2/impl/tag.hpp +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -1,6 +1,8 @@ #ifndef MULTIBOOT2_IMPL_TAG_HPP #define MULTIBOOT2_IMPL_TAG_HPP +// IWYU pragma: private + #include "multiboot2/impl/ids.hpp" #include @@ -25,29 +27,30 @@ namespace multiboot2::impl : tag_header{*data} {} - auto full_size() const noexcept -> std::size_t + [[nodiscard]] auto full_size() const noexcept -> std::size_t { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) return (m_size + 7) & (~7); } - auto information_id() const noexcept -> impl::information_id const & + [[nodiscard]] auto information_id() const noexcept -> impl::information_id const & { return m_id; } - auto next() const noexcept -> tag_header const * + [[nodiscard]] auto next() const noexcept -> tag_header const * { - return std::bit_cast(std::bit_cast(this) + full_size()); + return std::bit_cast(std::bit_cast(this) + full_size()); } - auto unaligned_size() const noexcept -> std::uint32_t + [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } - protected: - impl::information_id const m_id; - std::uint32_t const m_size; + private: + impl::information_id m_id; + std::uint32_t m_size; }; /** @@ -64,7 +67,7 @@ namespace multiboot2::impl explicit tag(tag_header const * header) requires(sizeof(tag) > sizeof(tag_header)) : tag_header{header} - , Data{*std::bit_cast(header + 1)} + , Data{*std::bit_cast(header + 1)} // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) {} explicit tag(tag_header const * header) diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp index 25f034d..2d60a6d 100644 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -45,7 +45,7 @@ namespace multiboot2 /** * @brief The command line string */ - auto string() const noexcept -> range_type + [[nodiscard]] auto string() const noexcept -> range_type { return {data(), size()}; } @@ -84,7 +84,7 @@ namespace multiboot2 /** * @brief The name of the bootloader */ - auto string() const noexcept -> std::string_view + [[nodiscard]] auto string() const noexcept -> std::string_view { return {data(), size()}; } @@ -100,7 +100,7 @@ namespace multiboot2 /** * @brief The available memory regions */ - auto regions() const noexcept -> range_type + [[nodiscard]] auto regions() const noexcept -> range_type { return {data(), size()}; } @@ -113,19 +113,19 @@ namespace multiboot2 using pointer = impl::information_iterator::pointer; using reference = impl::information_iterator::reference; - auto size_bytes() const noexcept -> std::size_t + [[nodiscard]] auto size_bytes() const noexcept -> std::size_t { return m_size; } // Range access - auto begin() const noexcept -> iterator + [[nodiscard]] auto begin() const noexcept -> iterator { return iterator{&m_tags}; } - auto end() const noexcept -> iterator + [[nodiscard]] auto end() const noexcept -> iterator { return iterator{}; } @@ -133,43 +133,43 @@ namespace multiboot2 // Tag access template - auto has() const noexcept -> bool + [[nodiscard]] auto has() const noexcept -> bool { return get().has_value(); } - auto maybe_basic_memory() const noexcept -> std::optional + [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional { return get(); } - auto basic_memory() const -> basic_memory + [[nodiscard]] auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } - auto maybe_bios_boot_device() const noexcept -> std::optional + [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional { return get(); } - auto bios_boot_device() const -> bios_boot_device + [[nodiscard]] auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } - auto maybe_command_line() const noexcept -> std::optional + [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional { return get(); } - auto command_line() const -> command_line + [[nodiscard]] auto command_line() const -> command_line { return maybe_command_line().value(); } template - auto maybe_elf_symbols() const noexcept -> std::optional> + [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional> { return get>().and_then( [](auto x) -> std::optional> { @@ -185,34 +185,34 @@ namespace multiboot2 } template - auto elf_symbols() const -> elf_symbols + [[nodiscard]] auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } - auto maybe_loader_name() const noexcept -> std::optional + [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional { return get(); } - auto loader_name() const -> loader_name + [[nodiscard]] auto loader_name() const -> loader_name { return maybe_loader_name().value(); } - auto maybe_memory_map() const noexcept -> std::optional + [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional { return get(); } - auto memory_map() const -> memory_map + [[nodiscard]] auto memory_map() const -> memory_map { return maybe_memory_map().value(); } private: template - constexpr auto get() const noexcept -> std::optional + [[nodiscard]] constexpr auto get() const noexcept -> std::optional { if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); found != end()) @@ -222,9 +222,9 @@ namespace multiboot2 return std::nullopt; } - [[maybe_unused]] uint32_t const m_size{}; + uint32_t m_size{}; uint32_t : 32; - impl::tag_header const m_tags{}; + impl::tag_header m_tags{}; }; } // namespace multiboot2 -- cgit v1.2.3 From fc6d44be383213b7609b5e3c4778e235fb6b00c3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 5 Dec 2025 18:48:44 +0100 Subject: kstd: implement memcmp --- libs/kstd/CMakeLists.txt | 1 + libs/kstd/src/libc/string.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 75c2315..e0c551c 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -4,6 +4,7 @@ add_library("libs::kstd" ALIAS "kstd") set(KSTD_LIBC_SYMBOLS "abort" "strlen" + "memcmp" ) target_sources("kstd" PRIVATE diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp index a42aedc..a9b85fc 100644 --- a/libs/kstd/src/libc/string.cpp +++ b/libs/kstd/src/libc/string.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace kstd::libc { @@ -10,6 +11,20 @@ namespace kstd::libc { return std::distance(string, std::ranges::find(string, nullptr, '\0')); } + + auto memcmp(void const * lhs, void const * rhs, std::size_t size) -> std::size_t + { + auto left_span = std::span{static_cast(lhs), size}; + auto right_span = std::span{static_cast(rhs), size}; + auto mismatched = std::ranges::mismatch(left_span, right_span); + + if (mismatched.in1 == left_span.end()) + { + return 0; + } + + return std::bit_cast(*mismatched.in1) - std::bit_cast(*mismatched.in2); + } } } // namespace kstd::libc \ No newline at end of file -- cgit v1.2.3 From f0c5ac3c8222d4d89b8e2d2a726427a7ec64e538 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 17:20:14 +0100 Subject: kstd: extract bitwise enum operations --- libs/kstd/CMakeLists.txt | 2 + libs/kstd/include/kstd/ext/bitfield_enum | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 libs/kstd/include/kstd/ext/bitfield_enum (limited to 'libs') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index e0c551c..d83e704 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -22,6 +22,8 @@ target_sources("kstd" PUBLIC "include/kstd/bits/shared_ptr.hpp" "include/kstd/bits/unique_ptr.hpp" + "include/kstd/ext/bitfield_enum" + "include/kstd/asm_ptr" "include/kstd/memory" "include/kstd/mutex" diff --git a/libs/kstd/include/kstd/ext/bitfield_enum b/libs/kstd/include/kstd/ext/bitfield_enum new file mode 100644 index 0000000..327af45 --- /dev/null +++ b/libs/kstd/include/kstd/ext/bitfield_enum @@ -0,0 +1,64 @@ +#ifndef KSTD_EXT_BITFIELD_ENUM_HPP +#define KSTD_EXT_BITFIELD_ENUM_HPP + +#include +#include +#include + +namespace kstd::ext +{ + + template + requires std::is_enum_v + struct is_bitfield_enum : std::false_type + { + }; + + template + concept bitfield_enum = is_bitfield_enum::value; + +}; // namespace kstd::ext + +template +constexpr auto operator|(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); +} + +template +constexpr auto operator|=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs | rhs; +} + +template +constexpr auto operator&(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) & std::to_underlying(rhs)); +} + +template +constexpr auto operator&=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs & rhs; +} + +template +constexpr auto operator^(EnumType lhs, EnumType rhs) -> EnumType +{ + return std::bit_cast(std::to_underlying(lhs) ^ std::to_underlying(rhs)); +} + +template +constexpr auto operator^=(EnumType & lhs, EnumType rhs) -> EnumType & +{ + return lhs = lhs ^ rhs; +} + +template +constexpr auto operator~(EnumType lhs) -> EnumType +{ + return std::bit_cast(~std::to_underlying(lhs)); +} + +#endif \ No newline at end of file -- cgit v1.2.3 From 998a001fc621ca0e7560ca09a8acd29469ae3373 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 17:46:02 +0100 Subject: docs: improve documentation --- libs/kstd/include/kstd/ext/bitfield_enum | 1 + libs/kstd/kstd.dox | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 libs/kstd/kstd.dox (limited to 'libs') diff --git a/libs/kstd/include/kstd/ext/bitfield_enum b/libs/kstd/include/kstd/ext/bitfield_enum index 327af45..80fe9d2 100644 --- a/libs/kstd/include/kstd/ext/bitfield_enum +++ b/libs/kstd/include/kstd/ext/bitfield_enum @@ -14,6 +14,7 @@ namespace kstd::ext { }; + //! @concept Specifies that an enum is to be used to define bits in a bitfield. template concept bitfield_enum = is_bitfield_enum::value; diff --git a/libs/kstd/kstd.dox b/libs/kstd/kstd.dox new file mode 100644 index 0000000..5920a3c --- /dev/null +++ b/libs/kstd/kstd.dox @@ -0,0 +1,14 @@ +//! @namespace kstd +//! The TeachOS Standard Library. +//! +//! This namespace provides implementation for Standard Library functionality that is not usually provided in a +//! freestanding environment, since it relies on operating system support (e.g. memory allocation). The implementations +//! found here, aim to be reasonably close to the specifications found in the C++ language standard (ISO14482). +//! However, some differences exists, for example the lack of exceptions. + +//! @namespace kstd::ext +//! Extensions to the Standard Library. +//! +//! This namespace includes custom extensions to what is defined for the C++ Standard Library. These extensions not +//! portable per-se, since they are not implemented by other Standard Library implementations. Whenever possible, +//! Standard Library conformant types, functions, etc. should be used throughout the TeachOS codebase. -- cgit v1.2.3 From 1945dd16716392e70e74efacd19e779f121bd1da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 16:46:51 +0100 Subject: chore: fix missing includes --- libs/kstd/src/libc/string.cpp | 2 ++ libs/kstd/src/mutex.cpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'libs') diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp index a9b85fc..319f6fd 100644 --- a/libs/kstd/src/libc/string.cpp +++ b/libs/kstd/src/libc/string.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include namespace kstd::libc diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp index da1357f..5a26154 100644 --- a/libs/kstd/src/mutex.cpp +++ b/libs/kstd/src/mutex.cpp @@ -1,5 +1,7 @@ #include "kstd/mutex" +#include + namespace kstd { auto mutex::lock() -> void -- cgit v1.2.3