diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-04-02 17:46:49 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-04-02 17:47:03 +0200 |
| commit | b2c3f25b453f1b71552fd93de8d11efbda36fcd1 (patch) | |
| tree | b9f097cbcf14e264a6818103a73c48a31830ffe4 /libs/kstd/include | |
| parent | 1f010078983e6ab4e74ee3d1efcfb3284620b002 (diff) | |
| parent | c5afb5c1ce1c084c840dbb58d73af6fe2b235ec7 (diff) | |
| download | teachos-b2c3f25b453f1b71552fd93de8d11efbda36fcd1.tar.xz teachos-b2c3f25b453f1b71552fd93de8d11efbda36fcd1.zip | |
Merge branch 'fmorgner/develop-BA-FS26/pit-device' into develop-BA-FS26
This changeset introduces a central device management system. The system
comprises the following components:
- kapi::devices::bus (type)
A bus can be both a real (physically present inside the machine) or
virtual (purely conceptual) bus. Busses form a hierarchy rooted in the
virtual root_bus (accessible via `kapi::devices::get_root_bus`).
Busses are derived from `kapi::devices::device`, and own devices. This
means that a bus can be attached to another bus. This facilitates a
uniform structure for device ownership. Each device needs to be
attached to exactly one bus. Virtual devices, e.g. RAM disks, should
be attached to the root root bus (via the `add_child` member
function).
Once a device, or bus, has been attached to a bus, it will be
initialized (by means of a call to the `init` member function). Busses
are responsible to initialize their children. If a bus has already
been initialized, any newly attached children will automatically be
initialized.
During initialization, the `probe` member function of the bus under
initialization weill be invoked. This allows a bus implementation to
determine if the hardware, if any, is ready to be initialized and to
also perform any required initialization steps.
IMPORTANT: busses take ownership of their children in the form of a
`unique_ptr`.
- kapi::devices (namespace)
The functions `allocate_major_number`, `register_device`,
`unregister_device`, and `find_device` form the device manager.
The device manager is responsible for keeping a record of active
devices, allowing O(log n) lookup of devices by major and minor, and
O(n) lookup by name. Additionally, the device manager is responsible
for handing out major numbers (via `allocate_major_number`) and
keeping track of active devices. When a child is attached to a bus, it
will also automatically be registered with the device manager.
Lookup of devices via the device manager can be achieved by means of
either overload of `find_device`.
Devices should never ask the manager directly for a major number.
Instead, a controller should be used, which requests a major number
per device "class" (as in kind, not language class). For example, a
RAM disk controller may request a single major number for all RAM
disks it is going to create. When the controller creates a new device
of a given "class", e.g. a RAM disk, it should then supply that major
number to the new device instance.
IMPORTANT: the device manager does not own the active devices. Rather
it holds a `flat_map` indexed by `pair{major, minor}` and resolving to
`kstd::observer_ptr<device>`.
- kstd::observer_ptr (type)
An observer pointer is a simple vocabulary type to express the concept
of having no ownership of the pointed-to object. In essence it is
equivalent to a standard C-style pointer, but expresses semantics by
virtue of being a separate type.
Diffstat (limited to 'libs/kstd/include')
| -rw-r--r-- | libs/kstd/include/kstd/bits/flat_map.hpp | 2 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/observer_ptr.hpp | 163 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/unique_ptr.hpp | 25 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/memory | 9 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/string | 13 |
5 files changed, 196 insertions, 16 deletions
diff --git a/libs/kstd/include/kstd/bits/flat_map.hpp b/libs/kstd/include/kstd/bits/flat_map.hpp index 9455549..fe46203 100644 --- a/libs/kstd/include/kstd/bits/flat_map.hpp +++ b/libs/kstd/include/kstd/bits/flat_map.hpp @@ -45,7 +45,7 @@ namespace kstd::bits template<std::size_t Index> requires(Index >= 0 && Index <= 1) - constexpr auto get() const noexcept -> decltype(auto) + [[nodiscard]] constexpr auto get() const noexcept -> decltype(auto) { if constexpr (Index == 0) { diff --git a/libs/kstd/include/kstd/bits/observer_ptr.hpp b/libs/kstd/include/kstd/bits/observer_ptr.hpp new file mode 100644 index 0000000..1c5da15 --- /dev/null +++ b/libs/kstd/include/kstd/bits/observer_ptr.hpp @@ -0,0 +1,163 @@ +#ifndef KSTD_OBSERVER_PTR_HPP +#define KSTD_OBSERVER_PTR_HPP + +// IWYU pragma: private, include <kstd/memory> + +#include "kstd/os/error.hpp" + +#include <compare> +#include <concepts> +#include <cstddef> +#include <type_traits> +#include <utility> + +namespace kstd +{ + + template<typename ElementType> + struct observer_ptr + { + //! The type of the element being pointed to. + using element_type = ElementType; + + //! Construct an empty observer pointer. + constexpr observer_ptr() noexcept = default; + + //! Construct an empty observer pointer from a null pointer. + constexpr observer_ptr(std::nullptr_t) noexcept {} + + //! Construct an observer pointer from a raw pointer. + constexpr explicit observer_ptr(element_type * pointer) + : m_ptr{pointer} + {} + + //! Construct an observer pointer from another observer pointer. + template<typename OtherElementType> + requires std::convertible_to<OtherElementType *, ElementType *> + constexpr observer_ptr(observer_ptr<OtherElementType> other) noexcept + : m_ptr{other.get()} + {} + + //! Copy construct an observer pointer. + constexpr observer_ptr(observer_ptr const & other) noexcept = default; + + //! Move construct an observer pointer. + constexpr observer_ptr(observer_ptr && other) noexcept = default; + + //! Copy assign an observer pointer. + constexpr auto operator=(observer_ptr const & other) noexcept -> observer_ptr & = default; + + //! Move assign an observer pointer. + constexpr auto operator=(observer_ptr && other) noexcept -> observer_ptr & = default; + + //! Stop watching the the watched object. + //! + //! @return The currently watched object, or nullptr if no object is being watched. + [[nodiscard]] constexpr auto release() noexcept -> element_type * + { + return std::exchange(m_ptr, nullptr); + } + + //! Reset the observer pointer. + //! + //! @param pointer The new object to watch. + constexpr auto reset(element_type * pointer = nullptr) noexcept -> void + { + m_ptr = pointer; + } + + //! Swap the observer pointer with another observer pointer. + //! + //! @param other The other observer pointer to swap with. + constexpr auto swap(observer_ptr & other) noexcept -> void + { + std::swap(m_ptr, other.m_ptr); + } + + //! Get the currently watched object. + //! + //! @return The currently watched object, or nullptr if no object is being watched. + [[nodiscard]] constexpr auto get() const noexcept -> element_type * + { + return m_ptr; + } + + //! Check if the observer pointer is watching an object. + //! + //! @return True if the observer pointer is watching an object, false otherwise. + [[nodiscard]] constexpr explicit operator bool() const noexcept + { + return m_ptr != nullptr; + } + + //! Get the currently watched object. + //! + //! @return A reference to the currently watched object. + [[nodiscard]] constexpr auto operator*() const -> std::add_lvalue_reference_t<element_type> + { + throw_on_null(); + return *m_ptr; + } + + //! Get the currently watched object. + //! + //! @return A pointer to the currently watched object. + [[nodiscard]] constexpr auto operator->() const -> element_type * + { + throw_on_null(); + return m_ptr; + } + + //! Convert the observer pointer to a raw pointer. + //! + //! @return A pointer to the currently watched object. + constexpr explicit operator element_type *() const noexcept + { + return m_ptr; + } + + //! Compare the observer pointer with another observer pointer. + //!> + //! @param other The other observer pointer to compare with. + //! @return The result of the comparison. + constexpr auto operator<=>(observer_ptr const & other) const noexcept -> std::strong_ordering = default; + + private: + //! Throw an exception if the observer pointer is null. + //! + //! @throws std::runtime_error if the observer pointer is null. + constexpr auto throw_on_null() const -> void + { + if (m_ptr == nullptr) + { + os::panic("[kstd:observer_ptr] Dereferencing a null observer pointer"); + } + } + + //! The raw pointer to the watched object. + ElementType * m_ptr{}; + }; + + //! Swap two observer pointers. + //! + //! @param lhs The first observer pointer to swap. + //! @param rhs The second observer pointer to swap. + template<typename ElementType> + constexpr auto swap(observer_ptr<ElementType> & lhs, observer_ptr<ElementType> & rhs) noexcept -> void + { + lhs.swap(rhs); + } + + //! Create an observer pointer from a raw pointer. + //! + //! @param pointer The raw pointer to create an observer pointer from. + //! @return An observer pointer to the given raw pointer. + template<typename ElementType> + constexpr auto make_observer(ElementType * pointer) noexcept -> observer_ptr<ElementType> + { + return observer_ptr<ElementType>{pointer}; + } + +} // 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 index e0870b1..3d803b4 100644 --- a/libs/kstd/include/kstd/bits/unique_ptr.hpp +++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp @@ -16,6 +16,9 @@ namespace kstd template<typename T> struct unique_ptr { + template<typename U> + friend struct unique_ptr; + /** * @brief Constructor. * @@ -40,6 +43,12 @@ namespace kstd */ unique_ptr(unique_ptr const &) = delete; + template<typename U> + requires(std::is_convertible_v<U *, T *>) + unique_ptr(unique_ptr<U> && other) noexcept + : pointer{std::exchange(other.pointer, nullptr)} + {} + /** * @brief Deleted copy assignment operator to enforce unique ownership. */ @@ -51,10 +60,8 @@ namespace kstd * @param other Unique pointer to move from. */ unique_ptr(unique_ptr && other) noexcept - : pointer(other.pointer) - { - other.pointer = nullptr; - } + : pointer{std::exchange(other.pointer, nullptr)} + {} /** * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()). @@ -67,8 +74,7 @@ namespace kstd if (this != &other) { delete pointer; - pointer = other.pointer; - other.pointer = nullptr; + pointer = std::exchange(other.pointer, nullptr); } return *this; } @@ -123,9 +129,7 @@ namespace kstd */ auto release() -> T * { - T * temp = pointer; - pointer = nullptr; - return temp; + return std::exchange(pointer, nullptr); } /** @@ -139,8 +143,7 @@ namespace kstd */ auto reset(T * ptr = nullptr) -> void { - delete pointer; - pointer = ptr; + delete std::exchange(pointer, ptr); } /** diff --git a/libs/kstd/include/kstd/memory b/libs/kstd/include/kstd/memory index cab2fba..493f49a 100644 --- a/libs/kstd/include/kstd/memory +++ b/libs/kstd/include/kstd/memory @@ -1,7 +1,8 @@ -#ifndef KSTD_SHARED_POINTER_HPP -#define KSTD_SHARED_POINTER_HPP +#ifndef KSTD_MEMORY_HPP +#define KSTD_MEMORY_HPP -#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export -#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export +#include "kstd/bits/observer_ptr.hpp" // IWYU pragma: export +#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/string b/libs/kstd/include/kstd/string index 075422e..4ce19ce 100644 --- a/libs/kstd/include/kstd/string +++ b/libs/kstd/include/kstd/string @@ -1,6 +1,10 @@ #ifndef KSTD_STRING_HPP #define KSTD_STRING_HPP +#include "kstd/bits/format/context.hpp" +#include "kstd/bits/format/formatter.hpp" +#include "kstd/bits/format/formatter/string_view.hpp" + #include <kstd/cstring> #include <kstd/os/error.hpp> #include <kstd/vector> @@ -343,6 +347,15 @@ namespace kstd return !(lhs == rhs); } + template<> + struct formatter<string> : formatter<std::string_view> + { + auto format(string const & str, format_context & context) const -> void + { + formatter<std::string_view>::format(str.view(), context); + } + }; + } // namespace kstd #endif
\ No newline at end of file |
