forked from pytorch/pytorch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExclusivelyOwned.h
143 lines (120 loc) · 4.39 KB
/
ExclusivelyOwned.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#pragma once
#include <c10/util/in_place.h>
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