-
Notifications
You must be signed in to change notification settings - Fork 0
/
weak_intrusive_ptr.hpp
145 lines (110 loc) · 3.44 KB
/
weak_intrusive_ptr.hpp
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
144
#pragma once
#include <cstddef>
#include <algorithm>
#include <stdexcept>
#include <type_traits>
#include "intrusive_ptr.hpp"
namespace std {
template <class T>
class weak_intrusive_ptr {
public:
using pointer = T*;
using const_pointer = const T*;
using element_type = T;
using reference = T&;
using const_reference = const T&;
static constexpr bool has_weak_ptr_semantics = true;
constexpr weak_intrusive_ptr() noexcept : ptr_(nullptr) {
}
weak_intrusive_ptr(pointer raw_ptr, bool add_ref = true) noexcept {
set_ptr(raw_ptr, add_ref);
}
weak_intrusive_ptr(weak_intrusive_ptr&& other) noexcept
: ptr_(other.detach()) {
}
weak_intrusive_ptr(const weak_intrusive_ptr& other) noexcept {
set_ptr(other.get(), true);
}
template <class Y>
weak_intrusive_ptr(weak_intrusive_ptr<Y> other) noexcept
: ptr_(other.detach()) {
static_assert(std::is_convertible<Y*, T*>::value, "Y* is not assignable to T*");
}
~weak_intrusive_ptr() {
if (ptr_) {
intrusive_ptr_release_weak(ptr_);
}
}
void swap(weak_intrusive_ptr& other) noexcept {
std::swap(ptr_, other.ptr_);
}
pointer detach() noexcept {
auto result = ptr_;
if (result) {
ptr_ = nullptr;
}
return result;
}
pointer release() noexcept {
return detach();
}
void reset(pointer new_value = nullptr, bool add_ref = true) {
auto old = ptr_;
set_ptr(new_value, add_ref);
if (old) {
intrusive_ptr_release_weak(old);
}
}
weak_intrusive_ptr& operator=(pointer ptr) noexcept {
reset(ptr);
return *this;
}
weak_intrusive_ptr& operator=(weak_intrusive_ptr other) noexcept {
swap(other);
return *this;
}
pointer get() const noexcept {
return ptr_;
}
pointer operator->() const noexcept {
return ptr_;
}
reference operator*() const noexcept {
return *ptr_;
}
bool operator!() const noexcept {
return !ptr_;
}
explicit operator bool() const noexcept {
return static_cast<bool>(ptr_);
}
intrusive_ptr<T> lock() const noexcept {
if (!ptr_ || !intrusive_ptr_upgrade_weak(ptr_)) {
return nullptr;
}
return {ptr_, false};
}
pointer get_locked() const noexcept {
if (!ptr_ || !intrusive_ptr_upgrade_weak(ptr_)) {
return nullptr;
}
return ptr_;
}
private:
void set_ptr(pointer raw_ptr, bool add_ref) noexcept {
ptr_ = raw_ptr;
if (raw_ptr && add_ref) {
intrusive_ptr_add_weak_ref(raw_ptr);
}
}
pointer ptr_;
};
template <class X, typename Y>
bool operator==(const weak_intrusive_ptr<X>& lhs, const weak_intrusive_ptr<Y>& rhs) {
return lhs.get() == rhs.get();
}
template <class X, typename Y>
bool operator!=(const weak_intrusive_ptr<X>& lhs, const weak_intrusive_ptr<Y>& rhs) {
return !(lhs == rhs);
}
}