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
14namespace BPrivate {
15
16namespace Network {
17
18
19class BBorrowError : public BError
20{
21public:
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
32class BorrowAdmin
33{
34private:
35	static constexpr uint8 kOwned = 0x1;
36	static constexpr uint8 kBorrowed = 0x2;
37	std::atomic<uint8> fState = kOwned;
38
39protected:
40	virtual ~BorrowAdmin() = default;
41
42	virtual void Cleanup() noexcept {};
43	virtual void ReleasePointer() noexcept {};
44
45public:
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
87template<typename T> class BorrowPointer : public BorrowAdmin
88{
89public:
90	BorrowPointer(T* object) noexcept
91		:
92		fPtr(object)
93	{
94	}
95
96	virtual ~BorrowPointer() { delete fPtr; }
97
98protected:
99	virtual void Cleanup() noexcept override { delete this; }
100
101	virtual void ReleasePointer() noexcept override { fPtr = nullptr; }
102
103private:
104	T* fPtr;
105};
106
107
108template<typename T> class BExclusiveBorrow
109{
110	template<typename P> friend class BBorrow;
111
112	T* fPtr = nullptr;
113	BorrowAdmin* fAdminBlock = nullptr;
114
115public:
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
195template<typename T> class BBorrow
196{
197	T* fPtr = nullptr;
198	BorrowAdmin* fAdminBlock = nullptr;
199
200public:
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
282template<class T, class... _Args>
283BExclusiveBorrow<T>
284make_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