Caffe2 - C++ API
A deep learning, cross platform ML framework
intrusive_ptr.h
1 #pragma once
2 
3 #include <c10/util/C++17.h>
4 #include <c10/util/Exception.h>
5 #include <atomic>
6 #include <stdexcept>
7 
8 namespace c10 {
9 
18 // Note [Stack allocated intrusive_ptr_target safety]
19 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 // A well known problem with std::enable_shared_from_this is that it
21 // allows you to create a std::shared_ptr from a stack allocated object,
22 // which is totally bogus because the object will die once you return
23 // from the stack. In intrusive_ptr, we can detect that this has occurred,
24 // because we set the refcount/weakcount of objects which inherit from
25 // intrusive_ptr_target to zero, *unless* we can prove that the object
26 // was dynamically allocated (e.g., via make_intrusive).
27 //
28 // Thus, whenever you transmute a T* into a intrusive_ptr<T>, we check
29 // and make sure that the refcount isn't zero (or, a more subtle
30 // test for weak_intrusive_ptr<T>, for which the refcount may validly
31 // be zero, but the weak refcount better not be zero), because that
32 // tells us if the object was allocated by us. If it wasn't, no
33 // intrusive_ptr for you!
34 
35 class C10_API intrusive_ptr_target {
36  // Note [Weak references for intrusive refcounting]
37  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38  // Here's the scheme:
39  //
40  // - refcount == number of strong references to the object
41  // weakcount == number of weak references to the object,
42  // plus one more if refcount > 0
43  // An invariant: refcount > 0 => weakcount > 0
44  //
45  // - THStorage stays live as long as there are any strong
46  // or weak pointers to it (weakcount > 0, since strong
47  // references count as a +1 to weakcount)
48  //
49  // - finalizers are called and data_ptr is deallocated when refcount == 0
50  //
51  // - Once refcount == 0, it can never again be > 0 (the transition
52  // from > 0 to == 0 is monotonic)
53  //
54  // - When you access THStorage via a weak pointer, you must
55  // atomically increment the use count, if it is greater than 0.
56  // If it is not, you must report that the storage is dead.
57  //
58  mutable std::atomic<size_t> refcount_;
59  mutable std::atomic<size_t> weakcount_;
60 
61  template <typename T, typename NullType>
62  friend class intrusive_ptr;
63  template <typename T, typename NullType>
64  friend class weak_intrusive_ptr;
65 
66  protected:
67  // protected destructor. We never want to destruct intrusive_ptr_target*
68  // directly.
69  virtual ~intrusive_ptr_target() {
70 // Disable -Wterminate and -Wexceptions so we're allowed to use assertions
71 // (i.e. throw exceptions) in a destructor.
72 // We also have to disable -Wunknown-warning-option and -Wpragmas, because
73 // some other compilers don't know about -Wterminate or -Wexceptions and
74 // will show a warning about unknown warning options otherwise.
75 #ifdef _MSC_VER
76 # pragma warning(push)
77 # pragma warning(disable: 4297) // function assumed not to throw an exception but does
78 #else
79 # pragma GCC diagnostic push
80 # pragma GCC diagnostic ignored "-Wpragmas"
81 # pragma GCC diagnostic ignored "-Wunknown-warning-option"
82 # pragma GCC diagnostic ignored "-Wterminate"
83 # pragma GCC diagnostic ignored "-Wexceptions"
84 #endif
85  AT_ASSERTM(
86  refcount_.load() == 0,
87  "Tried to destruct an intrusive_ptr_target that still has intrusive_ptr to it");
88  AT_ASSERTM(
89  weakcount_.load() == 0,
90  "Tried to destruct an intrusive_ptr_target that still has weak_intrusive_ptr to it");
91 #ifdef _MSC_VER
92 # pragma warning(pop)
93 #else
94 # pragma GCC diagnostic pop
95 #endif
96  }
97 
98  constexpr intrusive_ptr_target() noexcept : refcount_(0), weakcount_(0) {}
99 
100  // intrusive_ptr_target supports copy and move: but refcount and weakcount don't
101  // participate (since they are intrinsic properties of the memory location)
103  intrusive_ptr_target& operator=(intrusive_ptr_target&& other) noexcept { return *this; }
105  intrusive_ptr_target& operator=(const intrusive_ptr_target& other) noexcept { return *this; }
106 
107  private:
122  virtual void release_resources() {}
123 };
124 
125 namespace detail {
126 template <class TTarget>
128  static constexpr TTarget* singleton() noexcept {
129  return nullptr;
130  }
131 };
132 
133 template<class TTarget, class ToNullType, class FromNullType>
134 TTarget* assign_ptr_(TTarget* rhs) {
135  if (FromNullType::singleton() == rhs) {
136  return ToNullType::singleton();
137  } else {
138  return rhs;
139  }
140 }
141 } // namespace detail
142 
143 template <class TTarget, class NullType>
145 
146 template <
147  class TTarget,
149 class intrusive_ptr final {
150  private:
151 // the following static assert would be nice to have but it requires
152 // the target class T to be fully defined when intrusive_ptr<T> is instantiated
153 // this is a problem for classes that contain pointers to themselves
154 // static_assert(
155 // std::is_base_of<intrusive_ptr_target, TTarget>::value,
156 // "intrusive_ptr can only be used for classes that inherit from intrusive_ptr_target.");
157 #ifndef _WIN32
158  // This static_assert triggers on MSVC
159  // error C2131: expression did not evaluate to a constant
160  static_assert(
161  NullType::singleton() == NullType::singleton(),
162  "NullType must have a constexpr singleton() method");
163 #endif
164  static_assert(
165  std::is_same<TTarget*, decltype(NullType::singleton())>::value,
166  "NullType::singleton() must return a element_type* pointer");
167 
168  TTarget* target_;
169 
170  template <class TTarget2, class NullType2>
171  friend class intrusive_ptr;
172  friend class weak_intrusive_ptr<TTarget, NullType>;
173 
174  void retain_() {
175  if (target_ != NullType::singleton()) {
176  size_t new_refcount = ++target_->refcount_;
177  AT_ASSERTM(
178  new_refcount != 1,
179  "intrusive_ptr: Cannot increase refcount after it reached zero.");
180  }
181  }
182 
183  void reset_() noexcept {
184  if (target_ != NullType::singleton() && --target_->refcount_ == 0) {
185  // See comment above about weakcount. As long as refcount>0,
186  // weakcount is one larger than the actual number of weak references.
187  // So we need to decrement it here.
188  auto weak_count = --target_->weakcount_;
189  // justification for const_cast: release_resources is basically a destructor
190  // and a destructor always mutates the object, even for const objects.
191  const_cast<c10::guts::remove_const_t<TTarget>*>(target_)->release_resources();
192  if (weak_count == 0) {
193  delete target_;
194  }
195  }
196  target_ = NullType::singleton();
197  }
198 
199  // This constructor will not increase the ref counter for you.
200  // This is not public because we shouldn't make intrusive_ptr out of raw
201  // pointers except from inside the make_intrusive() and
202  // weak_intrusive_ptr::lock() implementations
203  explicit intrusive_ptr(TTarget* target) noexcept : target_(target) {}
204 
205  public:
206  using element_type = TTarget;
207 
208  intrusive_ptr() noexcept : intrusive_ptr(NullType::singleton()) {}
209 
210  intrusive_ptr(intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
211  rhs.target_ = NullType::singleton();
212  }
213 
214  template <class From, class FromNullType>
215  /* implicit */ intrusive_ptr(intrusive_ptr<From, FromNullType>&& rhs) noexcept
216  : target_(detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
217  static_assert(
218  std::is_convertible<From*, TTarget*>::value,
219  "Type mismatch. intrusive_ptr move constructor got pointer of wrong type.");
220  rhs.target_ = FromNullType::singleton();
221  }
222 
223  intrusive_ptr(const intrusive_ptr& rhs) : target_(rhs.target_) {
224  retain_();
225  }
226 
227  template <class From, class FromNullType>
228  /* implicit */ intrusive_ptr(
230  : target_(detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
231  static_assert(
232  std::is_convertible<From*, TTarget*>::value,
233  "Type mismatch. intrusive_ptr copy constructor got pointer of wrong type.");
234  retain_();
235  }
236 
237  ~intrusive_ptr() noexcept {
238  reset_();
239  }
240 
241  intrusive_ptr& operator=(intrusive_ptr&& rhs) & noexcept {
242  return operator=<TTarget, NullType>(std::move(rhs));
243  }
244 
245  template <class From, class FromNullType>
247  noexcept {
248  static_assert(
249  std::is_convertible<From*, TTarget*>::value,
250  "Type mismatch. intrusive_ptr move assignment got pointer of wrong type.");
251  intrusive_ptr tmp = std::move(rhs);
252  swap(tmp);
253  return *this;
254  }
255 
256  intrusive_ptr& operator=(const intrusive_ptr& rhs) & noexcept {
257  return operator=<TTarget, NullType>(rhs);
258  }
259 
260  template <class From, class FromNullType>
261  intrusive_ptr& operator=(const intrusive_ptr<From, NullType>& rhs) & {
262  static_assert(
263  std::is_convertible<From*, TTarget*>::value,
264  "Type mismatch. intrusive_ptr copy assignment got pointer of wrong type.");
265  intrusive_ptr tmp = rhs;
266  swap(tmp);
267  return *this;
268  }
269 
270  TTarget* get() const noexcept {
271  return target_;
272  }
273 
274  const TTarget& operator*() const noexcept {
275  return *target_;
276  }
277 
278  TTarget& operator*() noexcept {
279  return *target_;
280  }
281 
282  const TTarget* operator->() const noexcept {
283  return target_;
284  }
285 
286  TTarget* operator->() noexcept {
287  return target_;
288  }
289 
290  operator bool() const noexcept {
291  return target_ != NullType::singleton();
292  }
293 
294  void reset() noexcept {
295  reset_();
296  }
297 
298  void swap(intrusive_ptr& rhs) noexcept {
299  TTarget* tmp = target_;
300  target_ = rhs.target_;
301  rhs.target_ = tmp;
302  }
303 
304  // We do a lot of null-pointer checks in our code, good to have this be cheap.
305  bool defined() const noexcept {
306  return target_ != NullType::singleton();
307  }
308 
309  size_t use_count() const noexcept {
310  if (target_ == NullType::singleton()) {
311  return 0;
312  }
313  return target_->refcount_.load();
314  }
315 
316  size_t weak_use_count() const noexcept {
317  if (target_ == NullType::singleton()) {
318  return 0;
319  }
320  return target_->weakcount_.load();
321  }
322 
323  bool unique() const noexcept {
324  return use_count() == 1;
325  }
326 
334  TTarget* release() noexcept {
335  TTarget* result = target_;
336  target_ = NullType::singleton();
337  return result;
338  }
339 
346  static intrusive_ptr reclaim(TTarget* owning_ptr) {
347  // See Note [Stack allocated intrusive_ptr_target safety]
348  AT_ASSERTM(
349  owning_ptr == NullType::singleton() || owning_ptr->refcount_.load() > 0,
350  "intrusive_ptr: Can only intrusive_ptr::reclaim() owning pointers that were created using intrusive_ptr::release().");
351  return intrusive_ptr(owning_ptr);
352  }
353 
354  template <class... Args>
355  static intrusive_ptr make(Args&&... args) {
356  auto result = intrusive_ptr(new TTarget(std::forward<Args>(args)...));
357  // We can't use retain_(), because we also have to increase weakcount
358  // and because we allow raising these values from 0, which retain_()
359  // has an assertion against.
360  ++result.target_->refcount_;
361  ++result.target_->weakcount_;
362 
363  return result;
364  }
365 
371  static intrusive_ptr unsafe_reclaim_from_nonowning(TTarget* raw_ptr) {
372  // See Note [Stack allocated intrusive_ptr_target safety]
373  AT_ASSERTM(
374  raw_ptr == NullType::singleton() || raw_ptr->refcount_.load() > 0,
375  "intrusive_ptr: Can only reclaim pointers that are owned by someone");
376  auto ptr = reclaim(raw_ptr); // doesn't increase refcount
377  ptr.retain_();
378  return ptr;
379  }
380 };
381 
382 template <
383  class TTarget,
385  class... Args>
386 inline intrusive_ptr<TTarget, NullType> make_intrusive(Args&&... args) {
387  return intrusive_ptr<TTarget, NullType>::make(std::forward<Args>(args)...);
388 }
389 
390 template <class TTarget, class NullType>
391 inline void swap(
393  intrusive_ptr<TTarget, NullType>& rhs) noexcept {
394  lhs.swap(rhs);
395 }
396 
397 // To allow intrusive_ptr inside std::map or std::set, we need operator<
398 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
399 inline bool operator<(
401  const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
402  return lhs.get() < rhs.get();
403 }
404 
405 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
406 inline bool operator==(
408  const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
409  return lhs.get() == rhs.get();
410 }
411 
412 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
413 inline bool operator!=(
415  const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
416  return !operator==(lhs, rhs);
417 }
418 
419 template <
420  typename TTarget,
422 class weak_intrusive_ptr final {
423  private:
424  static_assert(
425  std::is_base_of<intrusive_ptr_target, TTarget>::value,
426  "intrusive_ptr can only be used for classes that inherit from intrusive_ptr_target.");
427 #ifndef _WIN32
428  // This static_assert triggers on MSVC
429  // error C2131: expression did not evaluate to a constant
430  static_assert(
431  NullType::singleton() == NullType::singleton(),
432  "NullType must have a constexpr singleton() method");
433 #endif
434  static_assert(
435  std::is_same<TTarget*, decltype(NullType::singleton())>::value,
436  "NullType::singleton() must return a element_type* pointer");
437 
438  TTarget* target_;
439 
440  template <class TTarget2, class NullType2>
441  friend class weak_intrusive_ptr;
442 
443  void retain_() {
444  if (target_ != NullType::singleton()) {
445  size_t new_weakcount = ++target_->weakcount_;
446  AT_ASSERTM(
447  new_weakcount != 1,
448  "weak_intrusive_ptr: Cannot increase weakcount after it reached zero.");
449  }
450  }
451 
452  void reset_() noexcept {
453  if (target_ != NullType::singleton() && --target_->weakcount_ == 0) {
454  delete target_;
455  }
456  target_ = NullType::singleton();
457  }
458 
459  constexpr explicit weak_intrusive_ptr(TTarget* target) : target_(target) {}
460 
461  public:
462  using element_type = TTarget;
463 
464  explicit weak_intrusive_ptr(const intrusive_ptr<TTarget, NullType>& ptr)
465  : weak_intrusive_ptr(ptr.get()) {
466  retain_();
467  }
468 
469  weak_intrusive_ptr(weak_intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
470  rhs.target_ = NullType::singleton();
471  }
472 
473  template <class From, class FromNullType>
474  /* implicit */ weak_intrusive_ptr(
476  : target_(detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
477  static_assert(
478  std::is_convertible<From*, TTarget*>::value,
479  "Type mismatch. weak_intrusive_ptr move constructor got pointer of wrong type.");
480  rhs.target_ = FromNullType::singleton();
481  }
482 
483  weak_intrusive_ptr(const weak_intrusive_ptr& rhs)
484  : target_(rhs.target_) {
485  retain_();
486  }
487 
488  template <class From, class FromNullType>
489  /* implicit */ weak_intrusive_ptr(
491  : target_(detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
492  static_assert(
493  std::is_convertible<From*, TTarget*>::value,
494  "Type mismatch. weak_intrusive_ptr copy constructor got pointer of wrong type.");
495  retain_();
496  }
497 
498  ~weak_intrusive_ptr() noexcept {
499  reset_();
500  }
501 
502  weak_intrusive_ptr& operator=(weak_intrusive_ptr&& rhs) & noexcept {
503  return operator=<TTarget, NullType>(std::move(rhs));
504  }
505 
506  template <class From, class FromNullType>
507  weak_intrusive_ptr& operator=(
509  noexcept {
510  static_assert(
511  std::is_convertible<From*, TTarget*>::value,
512  "Type mismatch. weak_intrusive_ptr move assignment got pointer of wrong type.");
513  weak_intrusive_ptr tmp = std::move(rhs);
514  swap(tmp);
515  return *this;
516  }
517 
518  weak_intrusive_ptr& operator=(const weak_intrusive_ptr& rhs) & noexcept {
519  return operator=<TTarget, NullType>(rhs);
520  }
521 
522  template <class From, class FromNullType>
523  weak_intrusive_ptr& operator=(
524  const weak_intrusive_ptr<From, NullType>& rhs) & {
525  static_assert(
526  std::is_convertible<From*, TTarget*>::value,
527  "Type mismatch. weak_intrusive_ptr copy assignment got pointer of wrong type.");
528  weak_intrusive_ptr tmp = rhs;
529  swap(tmp);
530  return *this;
531  }
532 
533  void reset() noexcept {
534  reset_();
535  }
536 
537  void swap(weak_intrusive_ptr& rhs) noexcept {
538  TTarget* tmp = target_;
539  target_ = rhs.target_;
540  rhs.target_ = tmp;
541  }
542 
543  // NB: This should ONLY be used by the std::hash implementation
544  // for weak_intrusive_ptr. Another way you could do this is
545  // friend std::hash<weak_intrusive_ptr>, but this triggers two
546  // bugs:
547  //
548  // (1) It triggers an nvcc bug, where std::hash in a friend class
549  // declaration gets preprocessed into hash, which then cannot
550  // actually be found. The error in this case looks like:
551  //
552  // error: no template named 'hash'; did you mean 'std::hash'?
553  //
554  // (2) On OS X, std::hash is declared as a struct, not a class.
555  // This twings:
556  //
557  // error: class 'hash' was previously declared as a struct
558  // [-Werror,-Wmismatched-tags]
559  //
560  // Both of these are work-aroundable, but on the whole, I decided
561  // it would be simpler and easier to make work if we just expose
562  // an unsafe getter for target_
563  //
564  TTarget* _unsafe_get_target() const noexcept {
565  return target_;
566  }
567 
568  size_t use_count() const noexcept {
569  if (target_ == NullType::singleton()) {
570  return 0;
571  }
572  return target_->refcount_.load(); // refcount, not weakcount!
573  }
574 
575  size_t weak_use_count() const noexcept {
576  if (target_ == NullType::singleton()) {
577  return 0;
578  }
579  return target_->weakcount_.load();
580  }
581 
582  bool expired() const noexcept {
583  return use_count() == 0;
584  }
585 
586  intrusive_ptr<TTarget, NullType> lock() const noexcept {
587  auto refcount = target_->refcount_.load();
588  do {
589  if (refcount == 0) {
590  // Object already destructed, no strong references left anymore.
591  // Return nullptr.
592  return intrusive_ptr<TTarget, NullType>(NullType::singleton());
593  }
594  } while (!target_->refcount_.compare_exchange_weak(refcount, refcount + 1));
595  return intrusive_ptr<TTarget, NullType>(target_);
596  }
597 
606  TTarget* release() noexcept {
607  TTarget* result = target_;
608  target_ = NullType::singleton();
609  return result;
610  }
611 
619  static weak_intrusive_ptr reclaim(TTarget* owning_weak_ptr) {
620  // See Note [Stack allocated intrusive_ptr_target safety]
621  // if refcount > 0, weakcount must be >1 for weak references to exist.
622  // see weak counting explanation at top of this file.
623  // if refcount == 0, weakcount only must be >0.
624  AT_ASSERTM(
625  owning_weak_ptr == NullType::singleton() ||
626  owning_weak_ptr->weakcount_.load() > 1 ||
627  (owning_weak_ptr->refcount_.load() == 0 &&
628  owning_weak_ptr->weakcount_.load() > 0),
629  "weak_intrusive_ptr: Can only weak_intrusive_ptr::reclaim() owning pointers that were created using weak_intrusive_ptr::release().");
630  return weak_intrusive_ptr(owning_weak_ptr);
631  }
632 
633  template <class TTarget1, class NullType1, class TTarget2, class NullType2>
634  friend bool operator<(
636  const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept;
637  template <class TTarget1, class NullType1, class TTarget2, class NullType2>
638  friend bool operator==(
640  const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept;
641 };
642 
643 template <class TTarget, class NullType>
644 inline void swap(
647  lhs.swap(rhs);
648 }
649 
650 // To allow weak_intrusive_ptr inside std::map or std::set, we need operator<
651 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
652 inline bool operator<(
654  const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
655  return lhs.target_ < rhs.target_;
656 }
657 
658 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
659 inline bool operator==(
661  const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
662  return lhs.target_ == rhs.target_;
663 }
664 
665 template <class TTarget1, class NullType1, class TTarget2, class NullType2>
666 inline bool operator!=(
668  const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
669  return !operator==(lhs, rhs);
670 }
671 
672 // Alias for documentary purposes, to more easily distinguish
673 // weak raw intrusive pointers from intrusive pointers.
675 
676 // This namespace provides some methods for working with
677 // raw pointers that subclass intrusive_ptr_target. They are not provided
678 // as methods on intrusive_ptr_target, because ideally you would not need these
679 // methods at all (use smart pointers), but if you are dealing with legacy code
680 // that still needs to pass around raw pointers, you may find these quite
681 // useful.
682 //
683 // An important usage note: some functions are only valid if you have a
684 // strong raw pointer to the object, while others are only valid if you
685 // have a weak raw pointer to the object. ONLY call intrusive_ptr namespace
686 // functions on strong pointers, and weak_intrusive_ptr namespace functions
687 // on weak pointers. If you mix it up, you may get an assert failure.
688 namespace raw {
689 
690 namespace intrusive_ptr {
691 
692  // WARNING: Unlike the reclaim() API, it is NOT valid to pass
693  // NullType::singleton to this function
694  inline void incref(intrusive_ptr_target* self) {
696  auto ptr_copy = ptr;
697  ptr_copy.release();
698  ptr.release();
699  }
700 
701  // WARNING: Unlike the reclaim() API, it is NOT valid to pass
702  // NullType::singleton to this function
703  inline void decref(intrusive_ptr_target* self) {
704  // Let it die
706  // NB: Caller still has 'self' pointer, but it's now invalid.
707  // If you want more safety, used the actual c10::intrusive_ptr class
708  }
709 
710  template <typename T>
711  inline T* make_weak(T* self) {
712  // NB: 'this' is a strong pointer, but we return a weak pointer
713  auto ptr = c10::intrusive_ptr<T>::reclaim(self);
714  c10::weak_intrusive_ptr<T> wptr(ptr);
715  ptr.release();
716  return wptr.release();
717  }
718 
719  inline uint32_t use_count(intrusive_ptr_target* self) {
721  auto r = ptr.use_count();
722  ptr.release();
723  return r;
724  }
725 
726 } // namespace intrusive_ptr_target
727 
728 namespace weak_intrusive_ptr {
729 
730  inline void incref(weak_intrusive_ptr_target* self) {
732  auto wptr_copy = wptr;
733  wptr_copy.release();
734  wptr.release();
735  }
736 
737  inline void decref(weak_intrusive_ptr_target* self) {
738  // Let it die
740  // NB: You still "have" the 'self' pointer, but it's now invalid.
741  // If you want more safety, used the actual c10::weak_intrusive_ptr class
742  }
743 
744  template <typename T>
745  inline T* lock(T* self) {
746  auto wptr = c10::weak_intrusive_ptr<T>::reclaim(self);
747  auto ptr = wptr.lock();
748  wptr.release();
749  return ptr.release();
750  }
751 
752  // This gives the STRONG refcount of a WEAK pointer
753  inline uint32_t use_count(weak_intrusive_ptr_target* self) {
755  auto r = wptr.use_count();
756  wptr.release();
757  return r;
758  }
759 
760 } // namespace weak_intrusive_ptr_target
761 
762 } // namespace raw
763 
764 } // namespace c10
765 
766 namespace std {
767 // To allow intrusive_ptr and weak_intrusive_ptr inside std::unordered_map or
768 // std::unordered_set, we need std::hash
769 template <class TTarget, class NullType>
770 struct hash<c10::intrusive_ptr<TTarget, NullType>> {
771  size_t operator()(const c10::intrusive_ptr<TTarget, NullType>& x) const {
772  return std::hash<TTarget*>()(x.get());
773  }
774 };
775 template <class TTarget, class NullType>
776 struct hash<c10::weak_intrusive_ptr<TTarget, NullType>> {
777  size_t operator()(const c10::weak_intrusive_ptr<TTarget, NullType>& x) const {
778  return std::hash<TTarget*>()(x._unsafe_get_target());
779  }
780 };
781 } // namespace std
The low-level representation of a tensor, which contains a pointer to a storage (which contains the a...
Definition: TensorImpl.h:211
static weak_intrusive_ptr reclaim(TTarget *owning_weak_ptr)
Takes an owning (but must be weakly referenced) pointer to TTarget* and creates a weak_intrusive_ptr ...
intrusive_ptr<T> is an alternative to shared_ptr<T> that has better performance because it does the r...
Definition: intrusive_ptr.h:35
To register your own kernel for an operator, do in one (!) cpp file: C10_REGISTER_KERNEL(OperatorHand...
Definition: alias_info.h:7
TTarget * release() noexcept
Returns an owning (!) pointer to the underlying object and makes the intrusive_ptr instance invalid...
TTarget * release() noexcept
Returns an owning (but still only weakly referenced) pointer to the underlying object and makes the w...
static intrusive_ptr reclaim(TTarget *owning_ptr)
Takes an owning pointer to TTarget* and creates an intrusive_ptr that takes over ownership.
static intrusive_ptr unsafe_reclaim_from_nonowning(TTarget *raw_ptr)
Turn a non-owning raw pointer to an intrusive_ptr.