aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cxxsupp/libcxxcuda11/include/__stop_token/intrusive_shared_ptr.h
blob: f00cea5bc2b670687b3bf3f1ec039229faa881e3 (plain) (blame)
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
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___STOP_TOKEN_INTRUSIVE_SHARED_PTR_H
#define _LIBCPP___STOP_TOKEN_INTRUSIVE_SHARED_PTR_H

#include <__atomic/atomic.h>
#include <__atomic/memory_order.h>
#include <__config>
#include <__type_traits/is_reference.h>
#include <__utility/move.h>
#include <__utility/swap.h>
#include <cstddef>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#  pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 20

// For intrusive_shared_ptr to work with a type T, specialize __intrusive_shared_ptr_traits<T> and implement
// the following function:
//
// static std::atomic<U>& __get_atomic_ref_count(T&);
//
// where U must be an integral type representing the number of references to the object.
template <class _Tp>
struct __intrusive_shared_ptr_traits;

// A reference counting shared_ptr for types whose reference counter
// is stored inside the class _Tp itself.
// When the reference count goes to zero, the destructor of _Tp will be called
template <class _Tp>
struct __intrusive_shared_ptr {
  _LIBCPP_HIDE_FROM_ABI __intrusive_shared_ptr() = default;

  _LIBCPP_HIDE_FROM_ABI explicit __intrusive_shared_ptr(_Tp* __raw_ptr) : __raw_ptr_(__raw_ptr) {
    if (__raw_ptr_)
      __increment_ref_count(*__raw_ptr_);
  }

  _LIBCPP_HIDE_FROM_ABI __intrusive_shared_ptr(const __intrusive_shared_ptr& __other) noexcept
      : __raw_ptr_(__other.__raw_ptr_) {
    if (__raw_ptr_)
      __increment_ref_count(*__raw_ptr_);
  }

  _LIBCPP_HIDE_FROM_ABI __intrusive_shared_ptr(__intrusive_shared_ptr&& __other) noexcept
      : __raw_ptr_(__other.__raw_ptr_) {
    __other.__raw_ptr_ = nullptr;
  }

  _LIBCPP_HIDE_FROM_ABI __intrusive_shared_ptr& operator=(const __intrusive_shared_ptr& __other) noexcept {
    if (__other.__raw_ptr_ != __raw_ptr_) {
      if (__other.__raw_ptr_) {
        __increment_ref_count(*__other.__raw_ptr_);
      }
      if (__raw_ptr_) {
        __decrement_ref_count(*__raw_ptr_);
      }
      __raw_ptr_ = __other.__raw_ptr_;
    }
    return *this;
  }

  _LIBCPP_HIDE_FROM_ABI __intrusive_shared_ptr& operator=(__intrusive_shared_ptr&& __other) noexcept {
    __intrusive_shared_ptr(std::move(__other)).swap(*this);
    return *this;
  }

  _LIBCPP_HIDE_FROM_ABI ~__intrusive_shared_ptr() {
    if (__raw_ptr_) {
      __decrement_ref_count(*__raw_ptr_);
    }
  }

  _LIBCPP_HIDE_FROM_ABI _Tp* operator->() const noexcept { return __raw_ptr_; }
  _LIBCPP_HIDE_FROM_ABI _Tp& operator*() const noexcept { return *__raw_ptr_; }
  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __raw_ptr_ != nullptr; }

  _LIBCPP_HIDE_FROM_ABI void swap(__intrusive_shared_ptr& __other) { std::swap(__raw_ptr_, __other.__raw_ptr_); }

  _LIBCPP_HIDE_FROM_ABI friend void swap(__intrusive_shared_ptr& __lhs, __intrusive_shared_ptr& __rhs) {
    __lhs.swap(__rhs);
  }

  _LIBCPP_HIDE_FROM_ABI friend bool constexpr
  operator==(const __intrusive_shared_ptr&, const __intrusive_shared_ptr&) = default;

  _LIBCPP_HIDE_FROM_ABI friend bool constexpr operator==(const __intrusive_shared_ptr& __ptr, std::nullptr_t) {
    return __ptr.__raw_ptr_ == nullptr;
  }

private:
  _Tp* __raw_ptr_ = nullptr;

  // the memory order for increment/decrement the counter is the same for shared_ptr
  // increment is relaxed and decrement is acq_rel
  _LIBCPP_HIDE_FROM_ABI static void __increment_ref_count(_Tp& __obj) {
    __get_atomic_ref_count(__obj).fetch_add(1, std::memory_order_relaxed);
  }

  _LIBCPP_HIDE_FROM_ABI static void __decrement_ref_count(_Tp& __obj) {
    if (__get_atomic_ref_count(__obj).fetch_sub(1, std::memory_order_acq_rel) == 1) {
      delete &__obj;
    }
  }

  _LIBCPP_HIDE_FROM_ABI static decltype(auto) __get_atomic_ref_count(_Tp& __obj) {
    using __ret_type = decltype(__intrusive_shared_ptr_traits<_Tp>::__get_atomic_ref_count(__obj));
    static_assert(
        std::is_reference_v<__ret_type>, "__get_atomic_ref_count should return a reference to the atomic counter");
    return __intrusive_shared_ptr_traits<_Tp>::__get_atomic_ref_count(__obj);
  }
};

#endif // _LIBCPP_STD_VER >= 20

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___STOP_TOKEN_INTRUSIVE_SHARED_PTR_H