-
Notifications
You must be signed in to change notification settings - Fork 4
/
qsbr_ptr.hpp
195 lines (153 loc) · 4.74 KB
/
qsbr_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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright (C) 2021-2024 Laurynas Biveinis
#ifndef UNODB_DETAIL_QSBR_PTR_HPP
#define UNODB_DETAIL_QSBR_PTR_HPP
#include "global.hpp"
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
#include <gsl/span>
namespace unodb {
namespace detail {
class qsbr_ptr_base {
protected:
qsbr_ptr_base() = default;
#ifndef NDEBUG
static void register_active_ptr(const void *ptr);
static void unregister_active_ptr(const void *ptr);
#endif
};
} // namespace detail
// An active pointer to QSBR-managed shared data. A thread cannot go through a
// quiescent state while at least one is alive, which is asserted in the debug
// build. A smart pointer class that provides a raw pointer-like interface.
// Implemented bare minimum to get things to work, expand as necessary.
template <class T>
class [[nodiscard]] qsbr_ptr : public detail::qsbr_ptr_base {
public:
using pointer_type = T *;
UNODB_DETAIL_DISABLE_MSVC_WARNING(26447)
UNODB_DETAIL_RELEASE_CONSTEXPR explicit qsbr_ptr(
pointer_type ptr_ UNODB_DETAIL_LIFETIMEBOUND) noexcept
: ptr{ptr_} {
#ifndef NDEBUG
register_active_ptr(ptr);
#endif
}
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr(const qsbr_ptr<T> &other) noexcept
: ptr{other.ptr} {
#ifndef NDEBUG
register_active_ptr(ptr);
#endif
}
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
constexpr qsbr_ptr(qsbr_ptr<T> &&other) noexcept
: ptr{std::exchange(other.ptr, nullptr)} {}
UNODB_DETAIL_DISABLE_MSVC_WARNING(26447)
~qsbr_ptr() noexcept {
#ifndef NDEBUG
unregister_active_ptr(ptr);
#endif
}
UNODB_DETAIL_DISABLE_MSVC_WARNING(26456)
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr<T> &operator=(
const qsbr_ptr<T> &other) noexcept {
#ifndef NDEBUG
if (this == &other) return *this;
unregister_active_ptr(ptr);
#endif
ptr = other.ptr;
#ifndef NDEBUG
register_active_ptr(ptr);
#endif
return *this;
}
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr<T> &operator=(
qsbr_ptr<T> &&other) noexcept {
#ifndef NDEBUG
unregister_active_ptr(ptr);
#endif
ptr = std::exchange(other.ptr, nullptr);
return *this;
}
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
[[nodiscard]] constexpr std::add_lvalue_reference_t<T> operator*() const {
return *ptr;
}
UNODB_DETAIL_DISABLE_MSVC_WARNING(26481)
constexpr qsbr_ptr<T> &operator++() noexcept {
#ifndef NDEBUG
unregister_active_ptr(ptr);
#endif
++ptr;
#ifndef NDEBUG
register_active_ptr(ptr);
#endif
return *this;
}
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
[[nodiscard, gnu::pure]] constexpr std::ptrdiff_t operator-(
qsbr_ptr<T> other) const noexcept {
return get() - other.get();
}
[[nodiscard, gnu::pure]] constexpr bool operator==(
qsbr_ptr<T> other) const noexcept {
return get() == other.get();
}
[[nodiscard, gnu::pure]] constexpr bool operator!=(
qsbr_ptr<T> other) const noexcept {
return get() != other.get();
}
[[nodiscard, gnu::pure]] constexpr bool operator<=(
qsbr_ptr<T> other) const noexcept {
return get() <= other.get();
}
[[nodiscard, gnu::pure]] constexpr T *get() const noexcept { return ptr; }
private:
pointer_type ptr;
};
} // namespace unodb
namespace std {
template <typename T>
struct iterator_traits<unodb::qsbr_ptr<T>> {
using difference_type = ptrdiff_t;
using value_type = T;
using pointer = T *;
using reference = T &;
using iterator_category = random_access_iterator_tag;
};
} // namespace std
namespace unodb {
// A gsl::span (or std::span), but with qsbr_ptr instead of raw pointer.
// Implemented bare minimum to get things to work, expand as necessary.
template <class T>
class qsbr_ptr_span {
public:
UNODB_DETAIL_RELEASE_CONSTEXPR explicit qsbr_ptr_span(
const gsl::span<T> &other) noexcept
: start{other.data()}, length{static_cast<std::size_t>(other.size())} {}
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr_span(
const qsbr_ptr_span<T> &) noexcept = default;
constexpr qsbr_ptr_span(qsbr_ptr_span<T> &&) noexcept = default;
~qsbr_ptr_span() noexcept = default;
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr_span<T> &operator=(
const qsbr_ptr_span<T> &) noexcept = default;
UNODB_DETAIL_RELEASE_CONSTEXPR qsbr_ptr_span<T> &operator=(
qsbr_ptr_span<T> &&) noexcept = default;
[[nodiscard, gnu::pure]] constexpr qsbr_ptr<T> begin() const noexcept {
return start;
}
UNODB_DETAIL_DISABLE_MSVC_WARNING(26481)
[[nodiscard, gnu::pure]] constexpr qsbr_ptr<T> end() const noexcept {
return qsbr_ptr<T>{start.get() + length};
}
UNODB_DETAIL_RESTORE_MSVC_WARNINGS()
private:
qsbr_ptr<T> start;
std::size_t length;
};
template <class T>
qsbr_ptr_span(const gsl::span<T> &) -> qsbr_ptr_span<T>;
} // namespace unodb
#endif // UNODB_DETAIL_QSBR_PTR_HPP