namespace c10 { | |
// See example implementation in TensorBase.h and TensorBody.h. | |
// Synopsis: | |
// | |
// repr_type -- type to use to store an owned T in ExclusivelyOwned. | |
// | |
// pointer_type -- pointer-esque type to return from | |
// ExclusivelyOwned's get() and operator*() methods. | |
// | |
// const_pointer_type -- similar to pointer_type, used for the const methods. | |
// | |
// static repr_type nullRepr() -- return a null instance of repr_type. | |
// | |
// template <class... Args> | |
// static repr_type createInPlace(Args&&... args) -- used by the in-place | |
// ExclusivelyOwned constructor. | |
// | |
// static repr_type moveToRepr(T&& x) -- move the given x into an | |
// instance of repr_type. used by the ExclusivelyOwned(T&&) | |
// constructor. | |
// | |
// static void destroyOwned(repr_type x) -- free memory for a | |
// known-exclusively-owned instance of x. Replaces calling repr_type's | |
// destructor. Being able to implement this more efficiently than | |
// repr_type's destructor is the main reason to use ExclusivelyOwned | |
// for a type. | |
// | |
// static T take(repr_type&) -- move out of the given repr_type into an owned T. | |
// | |
// static pointer_type getImpl(const repr_type&) -- return a pointer | |
// to the given repr_type. May take repr_type by value if that is more | |
// efficient. | |
template <typename T> | |
struct ExclusivelyOwnedTraits; | |
/// ExclusivelyOwned is a smart-pointer-like wrapper around an | |
/// exclusively-owned instance of some type T that normally has | |
/// mandatory reference counting (currently just Tensor). If you have | |
/// an isolated piece of code that knows that it has sole ownership of | |
/// an object of one of these types (i.e., because you created it | |
/// directly or using a factory function) and that object will not | |
/// escape from that isolated piece of code, then moving the object | |
/// into an ExclusivelyOwned will avoid an atomic reference count | |
/// decrement at destruction time. | |
/// | |
/// If you directly create the Tensor in the first | |
/// place, you can use the in_place constructor of ExclusivelyOwned to | |
/// additionally avoid doing any stores to initialize the refcount & | |
/// weakcount. | |
template <typename T> | |
class ExclusivelyOwned { | |
using EOT = ExclusivelyOwnedTraits<T>; | |
union { | |
char dummy_; | |
typename ExclusivelyOwnedTraits<T>::repr_type repr_; | |
}; | |
public: | |
ExclusivelyOwned() : repr_(EOT::nullRepr()) {} | |
explicit ExclusivelyOwned(T&& t) : repr_(EOT::moveToRepr(std::move(t))) {} | |
template <class... Args> | |
explicit ExclusivelyOwned(in_place_t, Args&&... args) | |
: repr_(EOT::createInPlace(std::forward<Args>(args)...)) {} | |
ExclusivelyOwned(const ExclusivelyOwned&) = delete; | |
ExclusivelyOwned(ExclusivelyOwned&& rhs) noexcept | |
: repr_(std::move(rhs.repr_)) { | |
rhs.repr_ = EOT::nullRepr(); | |
} | |
ExclusivelyOwned& operator=(const ExclusivelyOwned&) = delete; | |
ExclusivelyOwned& operator=(ExclusivelyOwned&& rhs) noexcept { | |
EOT::destroyOwned(repr_); | |
repr_ = std::move(rhs.repr_); | |
rhs.repr_ = EOT::nullRepr(); | |
return *this; | |
} | |
ExclusivelyOwned& operator=(T&& rhs) noexcept { | |
EOT::destroyOwned(repr_); | |
repr_ = EOT::moveToRepr(std::move(rhs)); | |
return *this; | |
} | |
~ExclusivelyOwned() { | |
EOT::destroyOwned(repr_); | |
// Don't bother to call the destructor of repr_, since we already | |
// did specialized destruction for the exclusively-owned case in | |
// destroyOwned! | |
} | |
// We don't provide this because it would require us to be able to | |
// differentiate an owned-but-empty T from a lack of T. This is | |
// particularly problematic for Tensor, which wants to use an | |
// undefined Tensor as its null state. | |
explicit operator bool() const noexcept = delete; | |
operator T() && { | |
return take(); | |
} | |
// NOTE: the equivalent operation on MaybeOwned is a moving | |
// operator*. For ExclusivelyOwned, take() and operator*() may well | |
// have different return types, so they are different functions. | |
T take() && { | |
return EOT::take(repr_); | |
} | |
typename EOT::const_pointer_type operator->() const { | |
return get(); | |
} | |
typename EOT::const_pointer_type get() const { | |
return EOT::getImpl(repr_); | |
} | |
typename EOT::pointer_type operator->() { | |
return get(); | |
} | |
typename EOT::pointer_type get() { | |
return EOT::getImpl(repr_); | |
} | |
std::remove_pointer_t<typename EOT::const_pointer_type>& operator*() const { | |
return *get(); | |
} | |
std::remove_pointer_t<typename EOT::pointer_type>& operator*() { | |
return *get(); | |
} | |
}; | |
} // namespace c10 | |