xref: /aosp_15_r20/external/pytorch/c10/util/ExclusivelyOwned.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
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