2022-08-30 08:52:56 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2022 Haiku Inc. All rights reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _B_EXCLUSIVE_BORROW_H
|
|
|
|
#define _B_EXCLUSIVE_BORROW_H
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <ErrorsExt.h>
|
|
|
|
|
|
|
|
namespace BPrivate {
|
|
|
|
|
|
|
|
namespace Network {
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
class BBorrowError : public BError
|
|
|
|
{
|
2022-08-30 08:52:56 +03:00
|
|
|
public:
|
|
|
|
BBorrowError(const char* origin)
|
2022-10-30 00:45:39 +03:00
|
|
|
:
|
|
|
|
BError(origin)
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual const char* Message() const noexcept override { return "BBorrowError"; }
|
2022-08-30 08:52:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
class BorrowAdmin
|
|
|
|
{
|
2022-08-30 08:52:56 +03:00
|
|
|
private:
|
|
|
|
static constexpr uint8 kOwned = 0x1;
|
|
|
|
static constexpr uint8 kBorrowed = 0x2;
|
2022-10-30 00:45:39 +03:00
|
|
|
std::atomic<uint8> fState = kOwned;
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
protected:
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual ~BorrowAdmin() = default;
|
2022-08-30 08:52:56 +03:00
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual void Cleanup() noexcept {};
|
|
|
|
virtual void ReleasePointer() noexcept {};
|
2022-08-30 08:52:56 +03:00
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
public:
|
|
|
|
BorrowAdmin() noexcept {}
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
void Borrow()
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
auto alreadyBorrowed = (fState.fetch_or(kBorrowed) & kBorrowed) == kBorrowed;
|
|
|
|
if (alreadyBorrowed) {
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
void Return() noexcept
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
auto cleanup = (fState.fetch_and(~kBorrowed) & kOwned) != kOwned;
|
|
|
|
if (cleanup)
|
|
|
|
this->Cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
void Forfeit() noexcept
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
auto cleanup = (fState.fetch_and(~kOwned) & kBorrowed) != kBorrowed;
|
|
|
|
if (cleanup)
|
|
|
|
this->Cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
bool IsBorrowed() noexcept { return (fState.load() & kBorrowed) == kBorrowed; }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
void Release()
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if ((fState.load() & kBorrowed) == kBorrowed)
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
this->ReleasePointer();
|
|
|
|
this->Cleanup();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
template<typename T> class BorrowPointer : public BorrowAdmin
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
BorrowPointer(T* object) noexcept
|
2022-10-30 00:45:39 +03:00
|
|
|
:
|
|
|
|
fPtr(object)
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual ~BorrowPointer() { delete fPtr; }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
protected:
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual void Cleanup() noexcept override { delete this; }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
virtual void ReleasePointer() noexcept override { fPtr = nullptr; }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
private:
|
2022-10-30 00:45:39 +03:00
|
|
|
T* fPtr;
|
2022-08-30 08:52:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
template<typename T> class BExclusiveBorrow
|
|
|
|
{
|
|
|
|
template<typename P> friend class BBorrow;
|
2022-08-30 08:52:56 +03:00
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
T* fPtr = nullptr;
|
|
|
|
BorrowAdmin* fAdminBlock = nullptr;
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
public:
|
2022-10-30 00:45:39 +03:00
|
|
|
BExclusiveBorrow() noexcept {}
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
BExclusiveBorrow(nullptr_t) noexcept {}
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
|
|
|
BExclusiveBorrow(T* object)
|
|
|
|
{
|
|
|
|
fAdminBlock = new BorrowPointer<T>(object);
|
|
|
|
fPtr = object;
|
|
|
|
}
|
|
|
|
|
|
|
|
~BExclusiveBorrow()
|
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Forfeit();
|
|
|
|
}
|
|
|
|
|
|
|
|
BExclusiveBorrow(const BExclusiveBorrow&) = delete;
|
|
|
|
|
|
|
|
|
|
|
|
BExclusiveBorrow& operator=(const BExclusiveBorrow&) = delete;
|
|
|
|
|
|
|
|
|
|
|
|
BExclusiveBorrow(BExclusiveBorrow&& other) noexcept
|
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Forfeit();
|
|
|
|
fAdminBlock = other.fAdminBlock;
|
|
|
|
fPtr = other.fPtr;
|
|
|
|
other.fAdminBlock = nullptr;
|
|
|
|
other.fPtr = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
BExclusiveBorrow& operator=(BExclusiveBorrow&& other) noexcept
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Forfeit();
|
|
|
|
fAdminBlock = other.fAdminBlock;
|
|
|
|
fPtr = other.fPtr;
|
|
|
|
other.fAdminBlock = nullptr;
|
|
|
|
other.fPtr = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
bool HasValue() const noexcept { return bool(fPtr); }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
T& operator*() const
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fAdminBlock && !fAdminBlock->IsBorrowed())
|
|
|
|
return *fPtr;
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
T* operator->() const
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fAdminBlock && !fAdminBlock->IsBorrowed())
|
|
|
|
return fPtr;
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
std::unique_ptr<T> Release()
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (!fAdminBlock)
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
fAdminBlock->Release();
|
|
|
|
auto retval = std::unique_ptr<T>(fPtr);
|
|
|
|
fPtr = nullptr;
|
|
|
|
fAdminBlock = nullptr;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
template<typename T> class BBorrow
|
|
|
|
{
|
|
|
|
T* fPtr = nullptr;
|
|
|
|
BorrowAdmin* fAdminBlock = nullptr;
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
public:
|
2022-10-30 00:45:39 +03:00
|
|
|
BBorrow() noexcept {}
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
BBorrow(nullptr_t) noexcept {}
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
|
|
|
template<typename P>
|
|
|
|
explicit BBorrow(BExclusiveBorrow<P>& owner)
|
2022-10-30 00:45:39 +03:00
|
|
|
:
|
|
|
|
fPtr(owner.fPtr),
|
|
|
|
fAdminBlock(owner.fAdminBlock)
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
fAdminBlock->Borrow();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BBorrow(const BBorrow&) = delete;
|
|
|
|
|
|
|
|
|
|
|
|
BBorrow& operator=(const BBorrow&) = delete;
|
|
|
|
|
|
|
|
|
|
|
|
BBorrow(BBorrow&& other) noexcept
|
2022-10-30 00:45:39 +03:00
|
|
|
:
|
|
|
|
fPtr(other.fPtr),
|
|
|
|
fAdminBlock(other.fAdminBlock)
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
other.fPtr = nullptr;
|
|
|
|
other.fAdminBlock = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
BBorrow& operator=(BBorrow&& other) noexcept
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Return();
|
|
|
|
|
|
|
|
fPtr = other.fPtr;
|
|
|
|
fAdminBlock = other.fAdminBlock;
|
|
|
|
other.fPtr = nullptr;
|
|
|
|
other.fAdminBlock = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~BBorrow()
|
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Return();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
bool HasValue() const noexcept { return bool(fPtr); }
|
2022-08-30 08:52:56 +03:00
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
T& operator*() const
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fPtr)
|
|
|
|
return *fPtr;
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
T* operator->() const
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fPtr)
|
|
|
|
return fPtr;
|
|
|
|
throw BBorrowError(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
void Return() noexcept
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
if (fAdminBlock)
|
|
|
|
fAdminBlock->Return();
|
|
|
|
fAdminBlock = nullptr;
|
|
|
|
fPtr = nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-10-30 00:45:39 +03:00
|
|
|
template<class T, class... _Args>
|
2022-08-30 08:52:56 +03:00
|
|
|
BExclusiveBorrow<T>
|
2022-10-30 00:45:39 +03:00
|
|
|
make_exclusive_borrow(_Args&&... __args)
|
2022-08-30 08:52:56 +03:00
|
|
|
{
|
|
|
|
auto guardedObject = std::make_unique<T>(std::forward<_Args>(__args)...);
|
|
|
|
auto retval = BExclusiveBorrow<T>(guardedObject.get());
|
|
|
|
guardedObject.release();
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Network
|
|
|
|
|
|
|
|
} // namespace BPrivate
|
|
|
|
|
|
|
|
#endif // _B_EXCLUSIVE_BORROW_H
|