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