diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-07-14 20:18:45 +0000 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-07-14 20:18:45 +0000 |
| commit | f12fa671ccadfdeaca1529157c3bd458f9e37c30 (patch) | |
| tree | d2fdbef28e2db631093db1b8987a25d833234939 /libs | |
| parent | 576935b6448802138639a324535614e0a966ead1 (diff) | |
| download | teachos-f12fa671ccadfdeaca1529157c3bd458f9e37c30.tar.xz teachos-f12fa671ccadfdeaca1529157c3bd458f9e37c30.zip | |
libs: move shared_pointer to kstd
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/kstd/include/kstd/shared_pointer.hpp | 269 |
1 files changed, 269 insertions, 0 deletions
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 <atomic> + +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<typename T> + 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<std::size_t>(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<T>(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<T>(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<std::size_t>(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<std::size_t> * 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<typename T> + auto swap(shared_pointer<T> & lhs, shared_pointer<T> & 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<T>(new T(std::forward<Args>(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<typename T, typename... Args> + auto make_shared(Args &&... args) -> shared_pointer<T> + { + return shared_pointer<T>(new T(std::forward<Args>(args)...)); + } +} // namespace kstd + +#endif
\ No newline at end of file |
