aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-03-31 22:22:25 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-02 11:28:08 +0200
commit77473afe9d5acb9450443b07b56d3dbc2f0639a6 (patch)
treea314bedf8ec1f59aa7bc1f49309fa87bdf22329a
parente7abfb7bf87ac605b2168891973d7e04a84d627e (diff)
downloadteachos-77473afe9d5acb9450443b07b56d3dbc2f0639a6.tar.xz
teachos-77473afe9d5acb9450443b07b56d3dbc2f0639a6.zip
kstd: introduce observer_ptr
-rw-r--r--kapi/include/kapi/devices/bus.hpp3
-rw-r--r--libs/kstd/include/kstd/observer_ptr154
2 files changed, 156 insertions, 1 deletions
diff --git a/kapi/include/kapi/devices/bus.hpp b/kapi/include/kapi/devices/bus.hpp
index cf8d090..0b25ac1 100644
--- a/kapi/include/kapi/devices/bus.hpp
+++ b/kapi/include/kapi/devices/bus.hpp
@@ -4,6 +4,7 @@
#include "kapi/devices/device.hpp"
#include <kstd/memory>
+#include <kstd/observer_ptr>
#include <kstd/string>
#include <kstd/vector>
@@ -33,7 +34,7 @@ namespace kapi::devices
//! Get a list of all child devices attached to this bus.
//!
//! @return A reference to list of child devices of this bus.
- [[nodiscard]] virtual auto children() const -> kstd::vector<device *> const & = 0;
+ [[nodiscard]] virtual auto children() const -> kstd::vector<kstd::observer_ptr<device>> const & = 0;
};
} // namespace kapi::devices
diff --git a/libs/kstd/include/kstd/observer_ptr b/libs/kstd/include/kstd/observer_ptr
new file mode 100644
index 0000000..d3d24b4
--- /dev/null
+++ b/libs/kstd/include/kstd/observer_ptr
@@ -0,0 +1,154 @@
+#ifndef KSTD_OBSERVER_PTR_HPP
+#define KSTD_OBSERVER_PTR_HPP
+
+#include "kstd/os/error.hpp"
+
+#include <compare>
+#include <concepts>
+#include <cstddef>
+#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;
+
+ //! 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) 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 noexcept -> 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 noexcept -> 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 noexcept -> 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