summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-12-08 01:16:06 -0500
committerAmlal El Mahrouss <amlal@nekernel.org>2025-12-08 01:16:26 -0500
commit1380e3c5ab92f38a72fad8f06b41b81c453a9a32 (patch)
treeebb2df97abd6a11561a0af84de977340339b238b /include
parenta2987feb8cb486c2ff124669190c1abd4e80a8f9 (diff)
feat: introduce `tracked_ptr.hpp` back to the OCL.Core. and new `smart_ptr.hpp`.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'include')
-rw-r--r--include/ocl/smart_ptr.hpp (renamed from include/ocl/unique_ptr.hpp)5
-rw-r--r--include/ocl/tracked_ptr.hpp235
2 files changed, 238 insertions, 2 deletions
diff --git a/include/ocl/unique_ptr.hpp b/include/ocl/smart_ptr.hpp
index 253fc0a..adab5aa 100644
--- a/include/ocl/unique_ptr.hpp
+++ b/include/ocl/smart_ptr.hpp
@@ -9,12 +9,13 @@
#define __OCL_UNIQUE_PTR
#include <ocl/detail/config.hpp>
+#include <ocl/tracked_ptr.hpp>
#include <memory>
namespace ocl
{
- template<class T, class Del>
- using unique_ptr = std::unique_ptr<T, Del>;
+ template <class T, class Del>
+ using unique_ptr = std::unique_ptr<T, Del>;
}
#endif // ifndef __OCL_UNIQUE_PTR \ No newline at end of file
diff --git a/include/ocl/tracked_ptr.hpp b/include/ocl/tracked_ptr.hpp
new file mode 100644
index 0000000..5a1b94e
--- /dev/null
+++ b/include/ocl/tracked_ptr.hpp
@@ -0,0 +1,235 @@
+/*
+ * File: ocl/tracked_ptr.hpp
+ * Purpose: Strict pointer type implementation in C++
+ * Author: Amlal El Mahrouss (amlal@nekernel.org)
+ * Copyright 2025, Amlal El Mahrouss, licensed under the Boost Software License.
+ */
+
+#pragma once
+
+#include <exception>
+#include <ocl/detail/config.hpp>
+#include <atomic>
+#include <stdexcept>
+
+namespace ocl
+{
+ template <typename Type>
+ class tracked_allocator
+ {
+ public:
+ std::atomic<std::size_t> allocated_count_{0};
+ std::atomic<std::size_t> deallocated_count_{0};
+
+ public:
+ explicit tracked_allocator() = default;
+ virtual ~tracked_allocator() = default;
+
+ tracked_allocator& operator=(const tracked_allocator&) = default;
+ tracked_allocator(const tracked_allocator&) = default;
+
+ public:
+ using pointer_type = Type*;
+ using type = Type;
+
+ template <typename... U>
+ void retain(pointer_type& ptr, U&&... args)
+ {
+ ptr = new type(std::forward<U>(args)...);
+
+ if (ptr)
+ {
+ ++allocated_count_;
+ return;
+ }
+
+ throw std::bad_alloc();
+ }
+
+ void dispose(pointer_type& ptr)
+ {
+ if (ptr)
+ {
+ if (allocated_count_)
+ --allocated_count_;
+
+ ++deallocated_count_;
+
+ delete ptr;
+ ptr = nullptr;
+ }
+ }
+ };
+
+ template <typename Type>
+ class tracked_mgr
+ {
+ private:
+ tracked_allocator<Type> allocator_;
+
+ public:
+ explicit tracked_mgr() = default;
+ virtual ~tracked_mgr() = default;
+
+ tracked_mgr& operator=(const tracked_mgr&) = default;
+ tracked_mgr(const tracked_mgr&) = default;
+
+ public:
+ using pointer_type = Type*;
+ using type = Type;
+
+ const tracked_allocator<Type>& allocator() noexcept
+ {
+ return allocator_;
+ }
+
+ template <typename... U>
+ pointer_type retain(U&&... args)
+ {
+ pointer_type ptr = nullptr;
+ allocator_.retain(ptr, std::forward<U>(args)...);
+
+ return ptr;
+ }
+
+ template <typename... U>
+ [[maybe_unused]] pointer_type must_retain(U&&... args)
+ {
+ try
+ {
+ return this->retain(std::forward<U>(args)...);
+ }
+ catch (...)
+ {
+ std::terminate();
+ }
+ }
+
+ void dispose(pointer_type& ptr) noexcept
+ {
+ allocator_.dispose(ptr);
+ }
+ };
+
+ template <typename Type, typename Mgr = tracked_mgr<Type>>
+ class tracked_ptr
+ {
+ public:
+ static Mgr& manager() noexcept
+ {
+ static Mgr mgr;
+ return mgr;
+ }
+
+ public:
+ template <typename... U>
+ tracked_ptr(U&&... args)
+ : ptr_(nullptr)
+ {
+ ptr_ = tracked_ptr::manager().retain(std::forward<U>(args)...);
+ }
+
+ virtual ~tracked_ptr() noexcept
+ {
+ this->reset();
+ }
+
+ tracked_ptr(const tracked_ptr&) = delete;
+ tracked_ptr& operator=(const tracked_ptr&) = delete;
+
+ public:
+ using pointer_type = Type*;
+ using type = Type;
+
+ void reset()
+ {
+ if (ptr_)
+ {
+ tracked_ptr::manager().dispose(ptr_);
+ }
+ }
+
+ pointer_type get() const
+ {
+ return ptr_;
+ }
+
+ type& operator*() const
+ {
+ return *ptr_;
+ }
+
+ pointer_type operator->() const
+ {
+ return ptr_;
+ }
+
+ explicit operator bool() const
+ {
+ return ptr_ != nullptr;
+ }
+
+ void swap(tracked_ptr& other)
+ {
+ std::swap(ptr_, other.ptr_);
+ }
+
+ public:
+ tracked_ptr(tracked_ptr&& other) noexcept
+ : ptr_(other.ptr_)
+ {
+ other.ptr_ = nullptr;
+ }
+
+ tracked_ptr& operator=(tracked_ptr&& other) noexcept
+ {
+ if (this != &other)
+ {
+ this->reset();
+ ptr_ = other.ptr_;
+ other.ptr_ = nullptr;
+ }
+
+ return *this;
+ }
+
+ private:
+ pointer_type ptr_{nullptr};
+ };
+
+ template <typename Type>
+ inline auto make_tracked() -> tracked_ptr<Type>
+ {
+ return tracked_ptr<Type>();
+ }
+
+ template <typename U, typename... Type>
+ inline auto make_tracked(Type&&... arg) -> tracked_ptr<U>
+ {
+ return tracked_ptr<U>(std::forward<Type>(arg)...);
+ }
+
+ template <typename Type>
+ inline void swap(tracked_ptr<Type>& a, tracked_ptr<Type>& b)
+ {
+ a.swap(b);
+ }
+
+ namespace detail
+ {
+ inline void throw_tracked_error()
+ {
+ throw std::runtime_error("tracked_error: memory leak detected.");
+ }
+ } // namespace detail
+
+ /// @brief a Must Pass function is a standard way to verify a container' validity, inspired from NeKernel/VMKernel.
+ template <typename Type>
+ inline void must_pass(tracked_ptr<Type>& ptr)
+ {
+ if (ptr.manager().allocator().allocated_count_ < ptr.manager().allocator().deallocated_count_)
+ {
+ detail::throw_tracked_error();
+ }
+ }
+} // namespace ocl