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