blob: 884ddb13e69e904ecb37a51e7b2988f69b3a2c04 (
plain)
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
|
/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (C) 2016 ScyllaDB
*/
#pragma once
#include <boost/intrusive/list.hpp>
namespace seastar {
/// A non-owning reference to an object.
///
/// weak_ptr allows one to keep a non-owning reference to an object. When the
/// object is destroyed, it notifies all weak_ptr instances pointing to it.
/// A weak_ptr instance pointing to a destroyed object is equivalent to a
/// `nullptr`.
///
/// The referenced object must inherit from weakly_referencable.
/// weak_ptr instances can only be obtained by calling weak_from_this() on
/// the to-be-referenced object.
///
/// \see weakly_referencable
template<typename T>
class weak_ptr {
template<typename U>
friend class weakly_referencable;
private:
using hook_type = boost::intrusive::list_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
hook_type _hook;
T* _ptr = nullptr;
weak_ptr(T* p) noexcept : _ptr(p) {}
public:
// Note: The default constructor's body is implemented as no-op
// rather than `noexcept = default` due to a bug with gcc 9.3.1
// that deletes the constructor since boost::intrusive::list_member_hook
// is not default_nothrow_constructible.
weak_ptr() noexcept {}
weak_ptr(std::nullptr_t) noexcept : weak_ptr() {}
weak_ptr(weak_ptr&& o) noexcept
: _ptr(o._ptr)
{
_hook.swap_nodes(o._hook);
o._ptr = nullptr;
}
weak_ptr& operator=(weak_ptr&& o) noexcept {
if (this != &o) {
this->~weak_ptr();
new (this) weak_ptr(std::move(o));
}
return *this;
}
explicit operator bool() const noexcept { return _ptr != nullptr; }
T* operator->() const noexcept { return _ptr; }
T& operator*() const noexcept { return *_ptr; }
T* get() const noexcept { return _ptr; }
bool operator==(const weak_ptr& o) const noexcept { return _ptr == o._ptr; }
bool operator!=(const weak_ptr& o) const noexcept { return _ptr != o._ptr; }
};
/// Allows obtaining a non-owning reference (weak_ptr) to the object.
///
/// A live weak_ptr object doesn't prevent the referenced object form being destroyed.
///
/// The underlying pointer held by weak_ptr is valid as long as the referenced object is alive.
/// When the object dies, all weak_ptr objects associated with it are emptied.
///
/// A weak reference is obtained like this:
///
/// class X : public weakly_referencable<X> {};
/// auto x = std::make_unique<X>();
/// weak_ptr<X> ptr = x->weak_from_this();
///
/// The user of weak_ptr can check if it still holds a valid pointer like this:
///
/// if (ptr) ptr->do_something();
///
template<typename T>
class weakly_referencable {
boost::intrusive::list<weak_ptr<T>,
boost::intrusive::member_hook<weak_ptr<T>, typename weak_ptr<T>::hook_type, &weak_ptr<T>::_hook>,
boost::intrusive::constant_time_size<false>> _ptr_list;
public:
// Note: The default constructor's body is implemented as no-op
// rather than `noexcept = default` due to a bug with gcc 9.3.1
// that deletes the constructor since boost::intrusive::member_hook
// is not default_nothrow_constructible.
weakly_referencable() noexcept {}
weakly_referencable(weakly_referencable&&) = delete; // pointer to this is captured and passed to weak_ptr
weakly_referencable(const weakly_referencable&) = delete;
~weakly_referencable() noexcept {
_ptr_list.clear_and_dispose([] (weak_ptr<T>* wp) noexcept {
wp->_ptr = nullptr;
});
}
weak_ptr<T> weak_from_this() noexcept {
weak_ptr<T> ptr(static_cast<T*>(this));
_ptr_list.push_back(ptr);
return ptr;
}
};
}
|