xref: /haiku/headers/private/netservices2/ExclusiveBorrow.h (revision 958b83c3ed45e0e599e7dc0bc7f5841d4d9c03e5)
1 /*
2  * Copyright 2022 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #ifndef _B_EXCLUSIVE_BORROW_H
7 #define _B_EXCLUSIVE_BORROW_H
8 
9 #include <atomic>
10 #include <memory>
11 
12 #include <ErrorsExt.h>
13 
14 namespace BPrivate {
15 
16 namespace Network {
17 
18 
19 class BBorrowError : public BError
20 {
21 public:
22 	BBorrowError(const char* origin)
23 		:
24 		BError(origin)
25 	{
26 	}
27 
28 	virtual const char* Message() const noexcept override { return "BBorrowError"; }
29 };
30 
31 
32 class BorrowAdmin
33 {
34 private:
35 	static constexpr uint8 kOwned = 0x1;
36 	static constexpr uint8 kBorrowed = 0x2;
37 	std::atomic<uint8> fState = kOwned;
38 
39 protected:
40 	virtual ~BorrowAdmin() = default;
41 
42 	virtual void Cleanup() noexcept {};
43 	virtual void ReleasePointer() noexcept {};
44 
45 public:
46 	BorrowAdmin() noexcept {}
47 
48 
49 	void Borrow()
50 	{
51 		auto alreadyBorrowed = (fState.fetch_or(kBorrowed) & kBorrowed) == kBorrowed;
52 		if (alreadyBorrowed) {
53 			throw BBorrowError(__PRETTY_FUNCTION__);
54 		}
55 	}
56 
57 
58 	void Return() noexcept
59 	{
60 		auto cleanup = (fState.fetch_and(~kBorrowed) & kOwned) != kOwned;
61 		if (cleanup)
62 			this->Cleanup();
63 	}
64 
65 
66 	void Forfeit() noexcept
67 	{
68 		auto cleanup = (fState.fetch_and(~kOwned) & kBorrowed) != kBorrowed;
69 		if (cleanup)
70 			this->Cleanup();
71 	}
72 
73 
74 	bool IsBorrowed() noexcept { return (fState.load() & kBorrowed) == kBorrowed; }
75 
76 
77 	void Release()
78 	{
79 		if ((fState.load() & kBorrowed) == kBorrowed)
80 			throw BBorrowError(__PRETTY_FUNCTION__);
81 		this->ReleasePointer();
82 		this->Cleanup();
83 	}
84 };
85 
86 
87 template<typename T> class BorrowPointer : public BorrowAdmin
88 {
89 public:
90 	BorrowPointer(T* object) noexcept
91 		:
92 		fPtr(object)
93 	{
94 	}
95 
96 	virtual ~BorrowPointer() { delete fPtr; }
97 
98 protected:
99 	virtual void Cleanup() noexcept override { delete this; }
100 
101 	virtual void ReleasePointer() noexcept override { fPtr = nullptr; }
102 
103 private:
104 	T* fPtr;
105 };
106 
107 
108 template<typename T> class BExclusiveBorrow
109 {
110 	template<typename P> friend class BBorrow;
111 
112 	T* fPtr = nullptr;
113 	BorrowAdmin* fAdminBlock = nullptr;
114 
115 public:
116 	BExclusiveBorrow() noexcept {}
117 
118 
119 	BExclusiveBorrow(nullptr_t) noexcept {}
120 
121 
122 	BExclusiveBorrow(T* object)
123 	{
124 		fAdminBlock = new BorrowPointer<T>(object);
125 		fPtr = object;
126 	}
127 
128 	~BExclusiveBorrow()
129 	{
130 		if (fAdminBlock)
131 			fAdminBlock->Forfeit();
132 	}
133 
134 	BExclusiveBorrow(const BExclusiveBorrow&) = delete;
135 
136 
137 	BExclusiveBorrow& operator=(const BExclusiveBorrow&) = delete;
138 
139 
140 	BExclusiveBorrow(BExclusiveBorrow&& other) noexcept
141 	{
142 		if (fAdminBlock)
143 			fAdminBlock->Forfeit();
144 		fAdminBlock = other.fAdminBlock;
145 		fPtr = other.fPtr;
146 		other.fAdminBlock = nullptr;
147 		other.fPtr = nullptr;
148 	}
149 
150 
151 	BExclusiveBorrow& operator=(BExclusiveBorrow&& other) noexcept
152 	{
153 		if (fAdminBlock)
154 			fAdminBlock->Forfeit();
155 		fAdminBlock = other.fAdminBlock;
156 		fPtr = other.fPtr;
157 		other.fAdminBlock = nullptr;
158 		other.fPtr = nullptr;
159 		return *this;
160 	}
161 
162 
163 	bool HasValue() const noexcept { return bool(fPtr); }
164 
165 
166 	T& operator*() const
167 	{
168 		if (fAdminBlock && !fAdminBlock->IsBorrowed())
169 			return *fPtr;
170 		throw BBorrowError(__PRETTY_FUNCTION__);
171 	}
172 
173 
174 	T* operator->() const
175 	{
176 		if (fAdminBlock && !fAdminBlock->IsBorrowed())
177 			return fPtr;
178 		throw BBorrowError(__PRETTY_FUNCTION__);
179 	}
180 
181 
182 	std::unique_ptr<T> Release()
183 	{
184 		if (!fAdminBlock)
185 			throw BBorrowError(__PRETTY_FUNCTION__);
186 		fAdminBlock->Release();
187 		auto retval = std::unique_ptr<T>(fPtr);
188 		fPtr = nullptr;
189 		fAdminBlock = nullptr;
190 		return retval;
191 	}
192 };
193 
194 
195 template<typename T> class BBorrow
196 {
197 	T* fPtr = nullptr;
198 	BorrowAdmin* fAdminBlock = nullptr;
199 
200 public:
201 	BBorrow() noexcept {}
202 
203 
204 	BBorrow(nullptr_t) noexcept {}
205 
206 
207 	template<typename P>
208 	explicit BBorrow(BExclusiveBorrow<P>& owner)
209 		:
210 		fPtr(owner.fPtr),
211 		fAdminBlock(owner.fAdminBlock)
212 	{
213 		fAdminBlock->Borrow();
214 	}
215 
216 
217 	BBorrow(const BBorrow&) = delete;
218 
219 
220 	BBorrow& operator=(const BBorrow&) = delete;
221 
222 
223 	BBorrow(BBorrow&& other) noexcept
224 		:
225 		fPtr(other.fPtr),
226 		fAdminBlock(other.fAdminBlock)
227 	{
228 		other.fPtr = nullptr;
229 		other.fAdminBlock = nullptr;
230 	}
231 
232 
233 	BBorrow& operator=(BBorrow&& other) noexcept
234 	{
235 		if (fAdminBlock)
236 			fAdminBlock->Return();
237 
238 		fPtr = other.fPtr;
239 		fAdminBlock = other.fAdminBlock;
240 		other.fPtr = nullptr;
241 		other.fAdminBlock = nullptr;
242 		return *this;
243 	}
244 
245 
246 	~BBorrow()
247 	{
248 		if (fAdminBlock)
249 			fAdminBlock->Return();
250 	}
251 
252 
253 	bool HasValue() const noexcept { return bool(fPtr); }
254 
255 
256 	T& operator*() const
257 	{
258 		if (fPtr)
259 			return *fPtr;
260 		throw BBorrowError(__PRETTY_FUNCTION__);
261 	}
262 
263 
264 	T* operator->() const
265 	{
266 		if (fPtr)
267 			return fPtr;
268 		throw BBorrowError(__PRETTY_FUNCTION__);
269 	}
270 
271 
272 	void Return() noexcept
273 	{
274 		if (fAdminBlock)
275 			fAdminBlock->Return();
276 		fAdminBlock = nullptr;
277 		fPtr = nullptr;
278 	}
279 };
280 
281 
282 template<class T, class... _Args>
283 BExclusiveBorrow<T>
284 make_exclusive_borrow(_Args&&... __args)
285 {
286 	auto guardedObject = std::make_unique<T>(std::forward<_Args>(__args)...);
287 	auto retval = BExclusiveBorrow<T>(guardedObject.get());
288 	guardedObject.release();
289 	return retval;
290 }
291 
292 
293 } // namespace Network
294 
295 } // namespace BPrivate
296 
297 #endif // _B_EXCLUSIVE_BORROW_H
298