1*da0073e9SAndroid Build Coastguard Worker #pragma once 2*da0073e9SAndroid Build Coastguard Worker 3*da0073e9SAndroid Build Coastguard Worker #include <utility> 4*da0073e9SAndroid Build Coastguard Worker 5*da0073e9SAndroid Build Coastguard Worker namespace c10 { 6*da0073e9SAndroid Build Coastguard Worker 7*da0073e9SAndroid Build Coastguard Worker // See example implementation in TensorBase.h and TensorBody.h. 8*da0073e9SAndroid Build Coastguard Worker // Synopsis: 9*da0073e9SAndroid Build Coastguard Worker // 10*da0073e9SAndroid Build Coastguard Worker // repr_type -- type to use to store an owned T in ExclusivelyOwned. 11*da0073e9SAndroid Build Coastguard Worker // 12*da0073e9SAndroid Build Coastguard Worker // pointer_type -- pointer-esque type to return from 13*da0073e9SAndroid Build Coastguard Worker // ExclusivelyOwned's get() and operator*() methods. 14*da0073e9SAndroid Build Coastguard Worker // 15*da0073e9SAndroid Build Coastguard Worker // const_pointer_type -- similar to pointer_type, used for the const methods. 16*da0073e9SAndroid Build Coastguard Worker // 17*da0073e9SAndroid Build Coastguard Worker // static repr_type nullRepr() -- return a null instance of repr_type. 18*da0073e9SAndroid Build Coastguard Worker // 19*da0073e9SAndroid Build Coastguard Worker // template <class... Args> 20*da0073e9SAndroid Build Coastguard Worker // static repr_type createInPlace(Args&&... args) -- used by the in-place 21*da0073e9SAndroid Build Coastguard Worker // ExclusivelyOwned constructor. 22*da0073e9SAndroid Build Coastguard Worker // 23*da0073e9SAndroid Build Coastguard Worker // static repr_type moveToRepr(T&& x) -- move the given x into an 24*da0073e9SAndroid Build Coastguard Worker // instance of repr_type. used by the ExclusivelyOwned(T&&) 25*da0073e9SAndroid Build Coastguard Worker // constructor. 26*da0073e9SAndroid Build Coastguard Worker // 27*da0073e9SAndroid Build Coastguard Worker // static void destroyOwned(repr_type x) -- free memory for a 28*da0073e9SAndroid Build Coastguard Worker // known-exclusively-owned instance of x. Replaces calling repr_type's 29*da0073e9SAndroid Build Coastguard Worker // destructor. Being able to implement this more efficiently than 30*da0073e9SAndroid Build Coastguard Worker // repr_type's destructor is the main reason to use ExclusivelyOwned 31*da0073e9SAndroid Build Coastguard Worker // for a type. 32*da0073e9SAndroid Build Coastguard Worker // 33*da0073e9SAndroid Build Coastguard Worker // static T take(repr_type&) -- move out of the given repr_type into an owned T. 34*da0073e9SAndroid Build Coastguard Worker // 35*da0073e9SAndroid Build Coastguard Worker // static pointer_type getImpl(const repr_type&) -- return a pointer 36*da0073e9SAndroid Build Coastguard Worker // to the given repr_type. May take repr_type by value if that is more 37*da0073e9SAndroid Build Coastguard Worker // efficient. 38*da0073e9SAndroid Build Coastguard Worker template <typename T> 39*da0073e9SAndroid Build Coastguard Worker struct ExclusivelyOwnedTraits; 40*da0073e9SAndroid Build Coastguard Worker 41*da0073e9SAndroid Build Coastguard Worker /// ExclusivelyOwned is a smart-pointer-like wrapper around an 42*da0073e9SAndroid Build Coastguard Worker /// exclusively-owned instance of some type T that normally has 43*da0073e9SAndroid Build Coastguard Worker /// mandatory reference counting (currently just Tensor). If you have 44*da0073e9SAndroid Build Coastguard Worker /// an isolated piece of code that knows that it has sole ownership of 45*da0073e9SAndroid Build Coastguard Worker /// an object of one of these types (i.e., because you created it 46*da0073e9SAndroid Build Coastguard Worker /// directly or using a factory function) and that object will not 47*da0073e9SAndroid Build Coastguard Worker /// escape from that isolated piece of code, then moving the object 48*da0073e9SAndroid Build Coastguard Worker /// into an ExclusivelyOwned will avoid an atomic reference count 49*da0073e9SAndroid Build Coastguard Worker /// decrement at destruction time. 50*da0073e9SAndroid Build Coastguard Worker /// 51*da0073e9SAndroid Build Coastguard Worker /// If you directly create the Tensor in the first 52*da0073e9SAndroid Build Coastguard Worker /// place, you can use the in_place constructor of ExclusivelyOwned to 53*da0073e9SAndroid Build Coastguard Worker /// additionally avoid doing any stores to initialize the refcount & 54*da0073e9SAndroid Build Coastguard Worker /// weakcount. 55*da0073e9SAndroid Build Coastguard Worker template <typename T> 56*da0073e9SAndroid Build Coastguard Worker class ExclusivelyOwned { 57*da0073e9SAndroid Build Coastguard Worker using EOT = ExclusivelyOwnedTraits<T>; 58*da0073e9SAndroid Build Coastguard Worker typename ExclusivelyOwnedTraits<T>::repr_type repr_; 59*da0073e9SAndroid Build Coastguard Worker 60*da0073e9SAndroid Build Coastguard Worker public: ExclusivelyOwned()61*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned() : repr_(EOT::nullRepr()) {} 62*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned(T && t)63*da0073e9SAndroid Build Coastguard Worker explicit ExclusivelyOwned(T&& t) : repr_(EOT::moveToRepr(std::move(t))) {} 64*da0073e9SAndroid Build Coastguard Worker 65*da0073e9SAndroid Build Coastguard Worker template <class... Args> ExclusivelyOwned(std::in_place_t,Args &&...args)66*da0073e9SAndroid Build Coastguard Worker explicit ExclusivelyOwned(std::in_place_t, Args&&... args) 67*da0073e9SAndroid Build Coastguard Worker : repr_(EOT::createInPlace(std::forward<Args>(args)...)) {} 68*da0073e9SAndroid Build Coastguard Worker 69*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned(const ExclusivelyOwned&) = delete; 70*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned(ExclusivelyOwned && rhs)71*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned(ExclusivelyOwned&& rhs) noexcept 72*da0073e9SAndroid Build Coastguard Worker : repr_(std::move(rhs.repr_)) { 73*da0073e9SAndroid Build Coastguard Worker rhs.repr_ = EOT::nullRepr(); 74*da0073e9SAndroid Build Coastguard Worker } 75*da0073e9SAndroid Build Coastguard Worker 76*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned& operator=(const ExclusivelyOwned&) = delete; 77*da0073e9SAndroid Build Coastguard Worker 78*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned& operator=(ExclusivelyOwned&& rhs) noexcept { 79*da0073e9SAndroid Build Coastguard Worker EOT::destroyOwned(repr_); 80*da0073e9SAndroid Build Coastguard Worker repr_ = std::move(rhs.repr_); 81*da0073e9SAndroid Build Coastguard Worker rhs.repr_ = EOT::nullRepr(); 82*da0073e9SAndroid Build Coastguard Worker return *this; 83*da0073e9SAndroid Build Coastguard Worker } 84*da0073e9SAndroid Build Coastguard Worker 85*da0073e9SAndroid Build Coastguard Worker ExclusivelyOwned& operator=(T&& rhs) noexcept { 86*da0073e9SAndroid Build Coastguard Worker EOT::destroyOwned(repr_); 87*da0073e9SAndroid Build Coastguard Worker repr_ = EOT::moveToRepr(std::move(rhs)); 88*da0073e9SAndroid Build Coastguard Worker return *this; 89*da0073e9SAndroid Build Coastguard Worker } 90*da0073e9SAndroid Build Coastguard Worker ~ExclusivelyOwned()91*da0073e9SAndroid Build Coastguard Worker ~ExclusivelyOwned() { 92*da0073e9SAndroid Build Coastguard Worker EOT::destroyOwned(repr_); 93*da0073e9SAndroid Build Coastguard Worker // Don't bother to call the destructor of repr_, since we already 94*da0073e9SAndroid Build Coastguard Worker // did specialized destruction for the exclusively-owned case in 95*da0073e9SAndroid Build Coastguard Worker // destroyOwned! 96*da0073e9SAndroid Build Coastguard Worker } 97*da0073e9SAndroid Build Coastguard Worker 98*da0073e9SAndroid Build Coastguard Worker // We don't provide this because it would require us to be able to 99*da0073e9SAndroid Build Coastguard Worker // differentiate an owned-but-empty T from a lack of T. This is 100*da0073e9SAndroid Build Coastguard Worker // particularly problematic for Tensor, which wants to use an 101*da0073e9SAndroid Build Coastguard Worker // undefined Tensor as its null state. 102*da0073e9SAndroid Build Coastguard Worker explicit operator bool() const noexcept = delete; 103*da0073e9SAndroid Build Coastguard Worker T()104*da0073e9SAndroid Build Coastguard Worker operator T() && { 105*da0073e9SAndroid Build Coastguard Worker return take(); 106*da0073e9SAndroid Build Coastguard Worker } 107*da0073e9SAndroid Build Coastguard Worker 108*da0073e9SAndroid Build Coastguard Worker // NOTE: the equivalent operation on MaybeOwned is a moving 109*da0073e9SAndroid Build Coastguard Worker // operator*. For ExclusivelyOwned, take() and operator*() may well 110*da0073e9SAndroid Build Coastguard Worker // have different return types, so they are different functions. take()111*da0073e9SAndroid Build Coastguard Worker T take() && { 112*da0073e9SAndroid Build Coastguard Worker return EOT::take(repr_); 113*da0073e9SAndroid Build Coastguard Worker } 114*da0073e9SAndroid Build Coastguard Worker 115*da0073e9SAndroid Build Coastguard Worker typename EOT::const_pointer_type operator->() const { 116*da0073e9SAndroid Build Coastguard Worker return get(); 117*da0073e9SAndroid Build Coastguard Worker } 118*da0073e9SAndroid Build Coastguard Worker get()119*da0073e9SAndroid Build Coastguard Worker typename EOT::const_pointer_type get() const { 120*da0073e9SAndroid Build Coastguard Worker return EOT::getImpl(repr_); 121*da0073e9SAndroid Build Coastguard Worker } 122*da0073e9SAndroid Build Coastguard Worker 123*da0073e9SAndroid Build Coastguard Worker typename EOT::pointer_type operator->() { 124*da0073e9SAndroid Build Coastguard Worker return get(); 125*da0073e9SAndroid Build Coastguard Worker } 126*da0073e9SAndroid Build Coastguard Worker get()127*da0073e9SAndroid Build Coastguard Worker typename EOT::pointer_type get() { 128*da0073e9SAndroid Build Coastguard Worker return EOT::getImpl(repr_); 129*da0073e9SAndroid Build Coastguard Worker } 130*da0073e9SAndroid Build Coastguard Worker 131*da0073e9SAndroid Build Coastguard Worker std::remove_pointer_t<typename EOT::const_pointer_type>& operator*() const { 132*da0073e9SAndroid Build Coastguard Worker return *get(); 133*da0073e9SAndroid Build Coastguard Worker } 134*da0073e9SAndroid Build Coastguard Worker 135*da0073e9SAndroid Build Coastguard Worker std::remove_pointer_t<typename EOT::pointer_type>& operator*() { 136*da0073e9SAndroid Build Coastguard Worker return *get(); 137*da0073e9SAndroid Build Coastguard Worker } 138*da0073e9SAndroid Build Coastguard Worker }; 139*da0073e9SAndroid Build Coastguard Worker 140*da0073e9SAndroid Build Coastguard Worker } // namespace c10 141