|
#pragma once |
|
|
|
#include <c10/macros/Macros.h> |
|
#include <c10/util/Exception.h> |
|
#include <c10/util/in_place.h> |
|
|
|
#include <type_traits> |
|
|
|
namespace c10 { |
|
|
|
|
|
|
|
|
|
template <typename T> |
|
struct MaybeOwnedTraitsGenericImpl { |
|
using owned_type = T; |
|
using borrow_type = const T*; |
|
|
|
static borrow_type createBorrow(const owned_type& from) { |
|
return &from; |
|
} |
|
|
|
static void assignBorrow(borrow_type& lhs, borrow_type rhs) { |
|
lhs = rhs; |
|
} |
|
|
|
static void destroyBorrow(borrow_type& ) {} |
|
|
|
static const owned_type& referenceFromBorrow(const borrow_type& borrow) { |
|
return *borrow; |
|
} |
|
|
|
static const owned_type* pointerFromBorrow(const borrow_type& borrow) { |
|
return borrow; |
|
} |
|
|
|
static bool debugBorrowIsValid(const borrow_type& borrow) { |
|
return borrow != nullptr; |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
struct MaybeOwnedTraits; |
|
|
|
|
|
|
|
template <typename T> |
|
struct MaybeOwnedTraits<std::shared_ptr<T>> |
|
: public MaybeOwnedTraitsGenericImpl<std::shared_ptr<T>> {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T> |
|
class MaybeOwned final { |
|
using borrow_type = typename MaybeOwnedTraits<T>::borrow_type; |
|
using owned_type = typename MaybeOwnedTraits<T>::owned_type; |
|
|
|
bool isBorrowed_; |
|
union { |
|
borrow_type borrow_; |
|
owned_type own_; |
|
}; |
|
|
|
|
|
explicit MaybeOwned(const owned_type& t) |
|
: isBorrowed_(true), borrow_(MaybeOwnedTraits<T>::createBorrow(t)) {} |
|
|
|
|
|
explicit MaybeOwned(T&& t) noexcept( |
|
std::is_nothrow_move_constructible<T>::value) |
|
: isBorrowed_(false), own_(std::move(t)) {} |
|
|
|
|
|
template <class... Args> |
|
explicit MaybeOwned(in_place_t, Args&&... args) |
|
: isBorrowed_(false), own_(std::forward<Args>(args)...) {} |
|
|
|
public: |
|
explicit MaybeOwned() : isBorrowed_(true), borrow_() {} |
|
|
|
|
|
|
|
|
|
|
|
MaybeOwned(const MaybeOwned& rhs) : isBorrowed_(rhs.isBorrowed_) { |
|
if (C10_LIKELY(rhs.isBorrowed_)) { |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
} else { |
|
new (&own_) T(rhs.own_); |
|
} |
|
} |
|
|
|
MaybeOwned& operator=(const MaybeOwned& rhs) { |
|
if (this == &rhs) { |
|
return *this; |
|
} |
|
if (C10_UNLIKELY(!isBorrowed_)) { |
|
if (rhs.isBorrowed_) { |
|
own_.~T(); |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
isBorrowed_ = true; |
|
} else { |
|
own_ = rhs.own_; |
|
} |
|
} else { |
|
if (C10_LIKELY(rhs.isBorrowed_)) { |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
} else { |
|
MaybeOwnedTraits<T>::destroyBorrow(borrow_); |
|
new (&own_) T(rhs.own_); |
|
isBorrowed_ = false; |
|
} |
|
} |
|
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(isBorrowed_ == rhs.isBorrowed_); |
|
return *this; |
|
} |
|
|
|
MaybeOwned(MaybeOwned&& rhs) noexcept( |
|
std::is_nothrow_move_constructible<T>::value) |
|
: isBorrowed_(rhs.isBorrowed_) { |
|
if (C10_LIKELY(rhs.isBorrowed_)) { |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
} else { |
|
new (&own_) T(std::move(rhs.own_)); |
|
} |
|
} |
|
|
|
MaybeOwned& operator=(MaybeOwned&& rhs) noexcept( |
|
std::is_nothrow_move_assignable<T>::value) { |
|
if (this == &rhs) { |
|
return *this; |
|
} |
|
if (C10_UNLIKELY(!isBorrowed_)) { |
|
if (rhs.isBorrowed_) { |
|
own_.~T(); |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
isBorrowed_ = true; |
|
} else { |
|
own_ = std::move(rhs.own_); |
|
} |
|
} else { |
|
if (C10_LIKELY(rhs.isBorrowed_)) { |
|
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_); |
|
} else { |
|
MaybeOwnedTraits<T>::destroyBorrow(borrow_); |
|
new (&own_) T(std::move(rhs.own_)); |
|
isBorrowed_ = false; |
|
} |
|
} |
|
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(isBorrowed_ == rhs.isBorrowed_); |
|
return *this; |
|
} |
|
|
|
static MaybeOwned borrowed(const T& t) { |
|
return MaybeOwned(t); |
|
} |
|
|
|
static MaybeOwned owned(T&& t) noexcept( |
|
std::is_nothrow_move_constructible<T>::value) { |
|
return MaybeOwned(std::move(t)); |
|
} |
|
|
|
template <class... Args> |
|
static MaybeOwned owned(in_place_t, Args&&... args) { |
|
return MaybeOwned(in_place, std::forward<Args>(args)...); |
|
} |
|
|
|
~MaybeOwned() { |
|
if (C10_UNLIKELY(!isBorrowed_)) { |
|
own_.~T(); |
|
} else { |
|
MaybeOwnedTraits<T>::destroyBorrow(borrow_); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
bool unsafeIsBorrowed() const { |
|
return isBorrowed_; |
|
} |
|
|
|
const T& operator*() const& { |
|
if (isBorrowed_) { |
|
TORCH_INTERNAL_ASSERT_DEBUG_ONLY( |
|
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_)); |
|
} |
|
return C10_LIKELY(isBorrowed_) |
|
? MaybeOwnedTraits<T>::referenceFromBorrow(borrow_) |
|
: own_; |
|
} |
|
|
|
const T* operator->() const { |
|
if (isBorrowed_) { |
|
TORCH_INTERNAL_ASSERT_DEBUG_ONLY( |
|
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_)); |
|
} |
|
return C10_LIKELY(isBorrowed_) |
|
? MaybeOwnedTraits<T>::pointerFromBorrow(borrow_) |
|
: &own_; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
T operator*() && { |
|
if (isBorrowed_) { |
|
TORCH_INTERNAL_ASSERT_DEBUG_ONLY( |
|
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_)); |
|
return MaybeOwnedTraits<T>::referenceFromBorrow(borrow_); |
|
} else { |
|
return std::move(own_); |
|
} |
|
} |
|
}; |
|
|
|
} |
|
|