Open C++ Libraries.org develop
Loading...
Searching...
No Matches
tracked_ptr.hpp
1// SPDX-License-Identifier: BSL-1.0
2// Copyright 2025-2026, Amlal El Mahrouss (amlal@nekernel.org)
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5// Official repository: https://github.com/open-cpp-libraries/core
6
7#ifndef OCL_TRACKED_PTR
8#define OCL_TRACKED_PTR
9
10#include <ocl/detail/config.hpp>
11#include <atomic>
12#include <stdexcept>
13
15
16namespace ocl::smart_ptr
17{
18
19 template <typename Type>
21 {
22 public:
23 std::atomic<std::size_t> allocated_count_{0};
24 std::atomic<std::size_t> deallocated_count_{0};
25
26 public:
27 explicit tracked_allocator() = default;
28 virtual ~tracked_allocator() = default;
29
30 tracked_allocator& operator=(const tracked_allocator&) = default;
31 tracked_allocator(const tracked_allocator&) = default;
32
33 public:
34 using pointer_type = Type*;
35 using type = Type;
36
37 template <typename... Args>
38 void retain(pointer_type& ptr, Args&&... args)
39 {
40 ptr = new type(std::forward<Args>(args)...);
41
42 if (ptr)
43 {
44 ++allocated_count_;
45 return;
46 }
47
48 throw std::bad_alloc();
49 }
50
51 void dispose(pointer_type& ptr)
52 {
53 if (ptr)
54 {
55 if (allocated_count_)
56 --allocated_count_;
57
58 ++deallocated_count_;
59
60 delete ptr;
61 ptr = nullptr;
62 }
63 }
64 };
65
66 template <typename Type>
68 {
69 private:
70 tracked_allocator<Type> allocator_;
71
72 public:
73 explicit tracked_mgr() = default;
74 virtual ~tracked_mgr() = default;
75
76 tracked_mgr& operator=(const tracked_mgr&) = default;
77 tracked_mgr(const tracked_mgr&) = default;
78
79 public:
80 using pointer_type = Type*;
81 using type = Type;
82
83 const tracked_allocator<Type>& allocator() noexcept
84 {
85 return allocator_;
86 }
87
88 template <typename... Args>
89 pointer_type retain(Args&&... args)
90 {
91 pointer_type ptr = nullptr;
92 allocator_.retain(ptr, std::forward<Args>(args)...);
93
94 return ptr;
95 }
96
97 template <typename... Args>
98 [[maybe_unused]] pointer_type must_retain(Args&&... args)
99 {
100 try
101 {
102 return this->retain(std::forward<Args>(args)...);
103 }
104 catch (...)
105 {
106 std::terminate();
107 }
108 }
109
110 void dispose(pointer_type& ptr) noexcept
111 {
112 allocator_.dispose(ptr);
113 }
114 };
115
116 template <typename Type, typename Mgr = tracked_mgr<Type>>
118 {
119 using manager = Mgr;
120
121 manager mgr_;
122
123 public:
124 template <typename... Args>
125 tracked_ptr(Args&&... args)
126 : ptr_(nullptr)
127 {
128 ptr_ = mgr_.retain(std::forward<Args>(args)...);
129 }
130
131 virtual ~tracked_ptr() noexcept
132 {
133 this->reset();
134 }
135
136 tracked_ptr(const tracked_ptr&) = delete;
137 tracked_ptr& operator=(const tracked_ptr&) = delete;
138
139 public:
140 using pointer_type = Type*;
141 using type = Type;
142 using reference_type = Type&;
143 using const_reference_type = const Type&;
144 using manager_type = tracked_mgr<manager>;
145 using pointer = pointer_type;
146 using reference = reference_type;
147
148 void reset()
149 {
150 if (ptr_)
151 {
152 mgr_.dispose(ptr_);
153 }
154 }
155
156 pointer_type get() const
157 {
158 return ptr_;
159 }
160
161 type& operator*() const
162 {
163 return *ptr_;
164 }
165
166 pointer_type operator->() const
167 {
168 return ptr_;
169 }
170
171 explicit operator bool() const
172 {
173 return ptr_ != nullptr;
174 }
175
176 void swap(tracked_ptr& other)
177 {
178 std::swap(ptr_, other.ptr_);
179 }
180
181 public:
182 tracked_ptr(tracked_ptr&& other) noexcept
183 : ptr_(other.ptr_)
184 {
185 other.ptr_ = nullptr;
186 }
187
188 tracked_ptr& operator=(tracked_ptr&& other) noexcept
189 {
190 if (this != &other)
191 {
192 ptr_ = other.ptr_;
193 other.ptr_ = nullptr;
194 }
195
196 return *this;
197 }
198
199 private:
200 pointer_type ptr_{nullptr};
201 };
202
203 template <typename Type>
204 inline auto make_tracked() -> tracked_ptr<Type>
205 {
206 return tracked_ptr<Type>();
207 }
208
209 template <typename RetType, typename... Type>
210 inline auto make_tracked(Type&&... arg) -> tracked_ptr<RetType>
211 {
212 return tracked_ptr<RetType>(std::forward<Type>(arg)...);
213 }
214
215 template <typename Type>
216 inline void swap(tracked_ptr<Type>& a, tracked_ptr<Type>& b)
217 {
218 a.swap(b);
219 }
220
221 namespace detail
222 {
223 using tracked_error = std::runtime_error;
224
225 inline void throw_tracked_error(const boost::source_location& loc = BOOST_CURRENT_LOCATION)
226 {
227 ::boost::throw_exception(tracked_error(""), loc);
228 }
229 } // namespace detail
230
232 template <typename Type>
233 inline void try_throw(tracked_ptr<Type>& ptr)
234 {
235 if (ptr.manager().allocator().allocated_count_ < ptr.manager().allocator().deallocated_count_)
236 {
237 detail::throw_tracked_error();
238 }
239 }
240
241} // namespace ocl
242
243#endif // ifndef OCL_TRACKED_PTR
Allocator operations structure. Takes care of memory mgmt within a pool.
Definition allocator_fwd.hpp:103
Definition tracked_ptr.hpp:21
Definition tracked_ptr.hpp:68
Definition tracked_ptr.hpp:118
Support for the smart pointer file for the OCL.
Definition smart_ptr.hpp:18
void try_throw(tracked_ptr< Type > &ptr)
This function is a standard way to verify a container' validity, inspired from NeKernel/VMKernel.
Definition tracked_ptr.hpp:233