xref: /haiku/docs/user/netservices/ExclusiveBorrow.dox (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
1/*
2 * Copyright 2021 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Niels Sascha Reedijk, niels.reedijk@gmail.com
7 *
8 * Corresponds to:
9 *		headers/private/netservices2/ExclusiveBorrow.h	hrev?????
10 */
11
12
13#if __cplusplus >= 201703L
14
15
16/*!
17	\file ExclusiveBorrow.h
18	\ingroup netservices
19	\brief Provides the BExclusiveBorrow smart pointer.
20*/
21
22namespace BPrivate {
23
24namespace Network {
25
26
27/*!
28	\class BBorrowError
29	\ingroup netservices
30	\brief Error while handling a BExclusiveBorrow or BBorrow object.
31
32	\since Haiku R1
33*/
34
35
36/*!
37	\fn BBorrowError::BBorrowError(const char* origin)
38	\brief Constructor that sets the \a origin.
39
40	\since Haiku R1
41*/
42
43
44/*!
45	\fn virtual const char* BBorrowError::Message() const noexcept override
46	\brief Get a pointer to the message describing the borrow error.
47
48	\since Haiku R1
49*/
50
51
52//! \cond INTERNAL
53
54
55/*!
56	\class BorrowAdmin
57	\brief Internal class that provides admin block for BExclusiveBorrow and BBorrow.
58
59	This base class provides the admin functions to deal with the underlying objects that are
60	managed by this smart pointers. It is implemented in such a way that it provides type erasure
61	for the actual smart objects, to enable them to allow for a BExclusiveBorrow<Derived> to have a
62	BBorrow<Base> higher up in the class inheritance.
63
64	\since Haiku R1
65*/
66
67
68/*!
69	\fn BorrowAdmin::~BorrowAdmin()
70	\brief Destructor
71
72	\since Haiku R1
73*/
74
75
76/*!
77	\fn virtual void BorrowAdmin::Cleanup() noexcept
78	\brief Hook function that triggers the cleanup of the underlying object.
79
80	Implemented by BorrowPointer<T>
81
82	\since Haiku R1
83*/
84
85
86/*!
87	\fn virtual void BorrowAdmin::ReleasePointer() noexcept
88	\brief Hook function to relinquish ownership of the underlying pointer.
89
90	When BExclusiveBorrow<T>::Release() is called, ownership of the pointer is transferred to the
91	caller. This hook function allows the BorrowPointer<T> to release the object so that there will
92	not be a double delete when the BExclusiveBorrow<T> is cleaned up.
93
94	\since Haiku R1
95*/
96
97
98/*!
99	\fn BorrowAdmin::BorrowAdmin()
100	\brief Constructor
101
102	\since Haiku R1
103*/
104
105
106/*!
107	\fn void BorrowAdmin::Borrow()
108	\brief Register that a BBorrow<T> object is created
109
110	\exception BBorrowError In case the object already is borrowed.
111
112	\since Haiku R1
113*/
114
115
116/*!
117	\fn void BorrowAdmin::Return() noexcept
118	\brief Register that the BBorrow<T> object no longer borrows the object.
119
120	This also cleans up the internal object if the corresponding BExclusiveBorrow<T> no longer
121	exists.
122
123	\since Haiku R1
124*/
125
126
127/*!
128	\fn void BorrowAdmin::Forfeit() noexcept
129	\brief Register that the BExclusiveBorrow<T> object no longer wants to own the object.
130
131	This also cleans up the internal object if there is no BBorrow<T> object.
132
133	\since Haiku R1
134*/
135
136
137/*!
138	\fn bool BorrowAdmin::IsBorrowed() noexcept
139	\brief Check if the current object is borrowed.
140
141	\since Haiku R1
142*/
143
144
145/*!
146	\fn void BorrowAdmin::Release()
147	\brief Cleanup the BorrowAdmin object without cleaning up the underlying object.
148
149	This method is called by BExclusiveBorrow<T>::Release(), where the smart pointer is emptied and
150	the ownership of the object is transferred to the caller.
151
152	\exception BBorrowError The ownership cannot be released if the object is borrowed.
153
154	\since Haiku R1
155*/
156
157
158/*!
159	\class BorrowPointer
160	\ingroup netservices
161	\brief Type derived from BorrowAdmin, which administrates the type-specific pointer.
162
163	In order to accomplish type erasure in BExclusiveBorrow and BBorrow, this derived type handles
164	the actual owned pointer.
165
166	\tparam T The type of the object that the BExclusiveBorrow<T> instance owns.
167
168	\since Haiku R1
169*/
170
171
172/*!
173	\fn BorrowPointer<T>::BorrowPointer(T* object) noexcept
174	\brief Construct a new admin block to manage the \a object.
175
176	\since Haiku R1
177*/
178
179
180/*!
181	\fn BorrowPointer<T>::~BorrowPointer()
182	\brief Destructor that deletes the owned object.
183
184	\since Haiku R1
185*/
186
187
188/*!
189	\fn virtual void BorrowPointer<T>::Cleanup() noexcept override
190	\brief Implementation of the Cleanup() hook function to delete the admin block and free
191		resources.
192
193	\since Haiku R1
194*/
195
196
197/*!
198	\fn virtual void BorrowPointer<T>::ReleasePointer() noexcept override
199	\brief Implementation of the ReleasePointer() hook function to make sure that the pointer
200		will not be freed when the object is destroyed.
201
202	\since Haiku R1
203*/
204
205
206//! \endcond
207
208
209/*!
210	\class BExclusiveBorrow
211	\ingroup netservices
212	\brief Smart pointer that allows shared ownership of an object with exclusive access.
213
214	This smart pointer was designed to support the particular pattern where a non-threadsafe or
215	non-lockable needs to be shared between two threads, where only one can have access to the
216	underlying object at the time.
217
218	When creating a new object, the underlying object can be accessed using the dereference
219	operator overloads as if with any other smart pointer. This ownership can then be borrowed
220	by creating a \ref BBorrow object. At that stage, the original owner can no longer access the
221	underlying object, until the borrow is returned. The borrow can access the object as long as
222	they retain the borrow. The borrow is returned by the borrow object going out of scope, or by
223	the borrow object being assigned a \c nullptr object. At that stage, the original owner regains
224	access.
225
226	\code
227	// Create a newly owned string object.
228	BExclusiveBorrow<BString> owner = make_exclusive_borrow<BString>("Initial value");
229
230	// Access the exclusively accessibe object and set it to a different value
231	owner->SetTo("New value set by owner");
232
233	// Create a borrow.
234	BBorrow<BString> borrow = BBorrow<BString>(owner);
235
236	try {
237		owner->SetTo("Another value set by owner");
238	} catch (const BorrowError& e) {
239		// This error will be thrown because the `owner` cannot access the object while borrowed.
240	}
241
242	try {
243		BBorrow<BString> secondBorrow = BBorrow<BString>(owner);
244	} catch (const BorrowError& e) {
245		// This error will be thrown because there cannot be more than one borrow at a time.
246	}
247
248	// The `borrow` has exclusive access to the underlying BString object
249	borrow->SetTo("A value set by the borrower");
250
251	// The borrow is returned by explicitly setting it to `nullptr` or by having the object go out
252	// of scope.
253	borrow = nullptr;
254
255	// The owner can access the object again
256	assert(*owner == "A value set by the borrower");
257	\endcode
258
259	\par Object Lifetime Management
260	The BExclusiveBorrow and BBorrow pair manage the lifetime of the underlying object, meaning
261	the memory will be freed when the object is no longer referenced by either the owner or the
262	borrower. It is possible to get the ownership of the underlying object through the
263	\ref BExclusiveBorrow::Release() method. This returns a \c unique_ptr.
264
265	\par Creating New Objects
266	When creating a BExclusiveBorrow object, you can use the \ref BExclusiveBorrow(T* object)
267	constructor to create a new smart pointer that takes an \em existing underlying object. Note
268	that the smart pointer will assume ownership, meaning that you should also have ownership of
269	that object. If you want to create a BExclusiveBorrow object for a new object, then you can use
270	the \ref make_exclusive_borrow() function to create a new object.
271
272	\par Move Semantics and Empty Objects
273	The template class is designed around having an underlying object value, and in most cases will
274	have an underlying object. However, there may be cases where a BExclusiveOwner or BBorrow
275	object will not have an internal value. This either happens when it is explicitly assigned an
276	empty value, or after the object has been moved. You can check whether the object has a value
277	through the \ref HasValue() method. Trying to access an empty object will throw a
278	\ref BBorrowError.
279
280	\par Checked Access
281	The semantics of the exclusive ownership are enforced by this class. The rules are:
282	 - There can only be one owner. The object cannot be copied, only moved.
283	 - There can only be one borrower at a time. The borrow object cannot be copied, only moved.
284	 - If one tries to create an additional borrow, an exception is thrown.
285	 - If an object is borrowed, accessing it through the owner will throw exceptions.
286
287	\par Casting Pointers between Owner and Borrower
288	For some design patterns, you may want to be able to cast the type of the owner to a related
289	type for the borrower. For example, the Network Services kit accepts a \c BBorrow<BDataIO> type
290	in order to allow the user to specify where to write the content of a network request to. The
291	\ref BDataIO itself is an abstract interface to read and write data from an object. A user
292	will most likely use a \ref BFile or \ref BMallocIO as underlying objects, both of which
293	have \ref BDataIO as their base class.
294
295	\par
296	Due to the specialized constructor of \ref BBorrow, it is possible to cast between compatible
297	pointer types, without loosing the advantages of properly cleaning up the object when the
298	borrow and the owner go out of scope. In the internals of the template, a type erasure
299	technique similar to that of \c std::shared_ptr is used.
300
301	\code
302	// Create a new BFile object, which inherits the BDataIO class.
303	BExclusiveBorrow<BFile> owner = make_exclusive_borrow<BFile>("path/to/file", B_READ_WRITE);
304	// The following succeeds because a BFile pointer can be assigned to a BDataIO pointer.
305	BBorrow<BDataIO> borrow = BBorrow<BDataIO>(owner);
306	\endcode
307
308	\par Multithread Safety, and Performance Cost
309	This smart object uses atomics to synchronize the ownership and borrows of the object, and to
310	enforce all the checks that were mentioned previously. The atomics guarantee that when you
311	want to access the object in BExclusiveBorrow, that this only succeeds after any outstanding
312	borrow is completed, otherwise an exception is thrown. While atomics can be used as a method of
313	synchronization, this templace class is \em not designed for that and it does not have the
314	tools to help doing that. If you need to synchronize object access between through threads, you
315	should use semaphores or thread joins instead.
316
317	\tparam T The type of object for this smart pointer.
318
319	\since Haiku R1
320*/
321
322/*!
323	\fn BExclusiveBorrow<T>::BExclusiveBorrow() noexcept
324	\brief Create a new smart pointer with no value.
325
326	\since Haiku R1
327*/
328
329
330/*!
331	\fn BExclusiveBorrow<T>::BExclusiveBorrow(nullptr_t) noexcept
332	\brief Special constructor that creates a new smart pointer with no value.
333
334	\since Haiku R1
335*/
336
337
338/*!
339	\fn BExclusiveBorrow<T>::BExclusiveBorrow(T* object)
340	\brief Create a new smart pointer that takes ownership of the \a object.
341
342	\param object The object to wrap inside this smart pointer.
343
344	\exception std::bad_alloc In case there are issues allocating memory for the internals of
345		the smart pointer.
346
347	\since Haiku R1
348*/
349
350
351/*!
352	\fn BExclusiveBorrow<T>::~BExclusiveBorrow()
353	\brief Destructor.
354
355	If the smart pointer is not empty, the underlying object will be deleted if there no longer
356	is a borrow accessing it.
357
358	\since Haiku R1
359*/
360
361
362/*!
363	\fn BExclusiveBorrow<T>::BExclusiveBorrow(BExclusiveBorrow&& other) noexcept
364	\brief Move constructor.
365
366	\param other The object to move from. It will be left empty after the move.
367
368	\since Haiku R1
369*/
370
371
372/*!
373	\fn BExclusiveBorrow& BExclusiveBorrow<T>::operator=(BExclusiveBorrow&& other) noexcept
374	\brief Move assignment.
375
376	\param other The object to move from. It will be left empty after the move.
377
378	\since Haiku R1
379*/
380
381
382/*!
383	\fn bool BExclusiveBorrow<T>::HasValue() const noexcept
384	\brief Check if the object has a value or is empty.
385
386	\since Haiku R1
387*/
388
389
390/*!
391	\fn T& BExclusiveBorrow<T>::operator*() const
392	\brief Dereferences the pointer.
393
394	\exception BBorrowError This exception is raised if the object is borrowed, or if it is empty.
395
396	\since Haiku R1
397*/
398
399
400/*!
401	\fn T* BExclusiveBorrow<T>::operator->() const
402	\brief Dereferences the pointer.
403
404	\exception BBorrowError This exception is raised if the object is borrowed, or if it is empty.
405
406	\since Haiku R1
407*/
408
409
410/*!
411	\fn std::unique_ptr<T> BExclusiveBorrow<T>::Release()
412	\brief Returns a unique_ptr of the inner object and releases the ownership.
413
414	\exception BBorrowError This exception is raised if the object is borrowed, or if it is empty.
415
416	\since Haiku R1
417*/
418
419
420/*!
421	\class BBorrow
422	\ingroup netservices
423	\brief Smart pointer that borrows an object from a \ref BExclusiveBorrow owner.
424
425	The BBorrow smart pointer is the accompanyment to the \ref BExclusiveBorrow owner object. See
426	the documentation on that template class on how to use the smart pointer pairs to express and
427	enforce exclusive ownership between the owner and the borrower.
428
429	Like a BExclusiveBorrow object, a BBorrow object can either have a borrow or be empty. When it
430	is empty, it means the current object is not borrowing anything at that moment. Any calls to
431	access the underlying data will fail in that case.
432
433	\tparam T The type of object that is owned by this smart pointer.
434
435	\since Haiku R1
436*/
437
438
439/*!
440	\fn BBorrow<T>::BBorrow() noexcept
441	\brief Create a new smart pointer with no value.
442
443	\since Haiku R1
444*/
445
446
447/*!
448	\fn BBorrow<T>::BBorrow(nullptr_t) noexcept
449	\brief Special constructor that builds an empty borrow object.
450
451	\since Haiku R1
452*/
453
454
455/*!
456	\fn BBorrow<T>::BBorrow(BExclusiveBorrow<P>& owner)
457	\brief Construct a borrowed object from the \a owner.
458
459	\param owner The owner to borrow from.
460
461	\exception BBorrowError In case the \a owner already borrowed their object, or in case the
462		\a owner is an empty object, as you cannot borrow something that is not there.
463
464	\tparam T The type of object for this BBorrow object.
465	\tparam P The type of objedt for the BExclusiveBorrow object. This allows you to have different
466		types between the owner and the borrower, with the requirement that a pointer to type P can
467		be cast to a pointer of type T without issue.
468
469	\since Haiku R1
470*/
471
472
473/*!
474	\fn BBorrow<T>::BBorrow(BBorrow&& other) noexcept
475	\brief Move constructor.
476
477	\param other The object to move from. It will be left empty after the move.
478
479	\since Haiku R1
480*/
481
482
483/*!
484	\fn BBorrow& BBorrow<T>::operator=(BBorrow&& other) noexcept
485	\brief Move assignment.
486
487	\param other The object to move from. It will be left empty after the move.
488
489	\since Haiku R1
490*/
491
492
493/*!
494	\fn BBorrow<T>::~BBorrow()
495	\brief Destructor that returns the object to the original owner.
496
497	If the original owner no longer exists, the underlying object will be deleted.
498
499	\since Haiku R1
500*/
501
502
503/*!
504	\fn bool BBorrow<T>::HasValue() const noexcept
505	\brief Check if the object has a value or is empty.
506
507	\since Haiku R1
508*/
509
510
511/*!
512	\fn T& BBorrow<T>::operator*() const
513	\brief Dereference operator.
514
515	\exception BBorrowError When the smart pointer is empty and there is no object to access.
516
517	\since Haiku R1
518*/
519
520
521/*!
522	\fn T* BBorrow<T>::operator->() const
523	\brief Dereference operator.
524
525	\exception BBorrowError When the smart pointer is empty and there is no object to access.
526
527	\since Haiku R1
528*/
529
530
531/*!
532	\fn void BBorrow<T>::Return() noexcept
533	\brief Return object to the owner.
534
535	The current object will be set to be an empty object after this call. If the object is already
536	empty, this call will not do anything. If the owner no longer exists, the object will be
537	disposed off.
538
539	\since Haiku R1
540*/
541
542
543/*!
544	\fn BExclusiveBorrow<T> make_exclusive_borrow(_Args&& ...__args)
545	\ingroup netservices
546	\brief Create a new object that is managed by a BExclusiveBorrow smart pointer.
547
548	This is a convenience template function to the likes of \c std::make_unique(). It allows you to
549	directly create the \ref BExclusiveBorrow smart pointer around a newly allocated object.
550
551	\tparam T The type of the object that will be created.
552	\tparam _Args Arguments to be passed to the constructor of T.
553
554	\exception std::bad_alloc In case there are issues allocating the new object.
555	\exception ... Any other exception that is thrown by the constructor of the object T.
556
557	\since Haiku R1
558*/
559
560
561} // namespace Network
562
563} // namespace BPrivate
564
565# endif
566