7#include "wfree_idle_count.hpp"
8#include "unfair_mutex.hpp"
13namespace hi::inline v1 {
20template<
typename T,
typename Allocator = std::allocator<T>>
24 using allocator_type = Allocator;
31 constexpr rcu(allocator_type allocator = allocator_type{})
noexcept : _allocator(allocator) {}
34 rcu(rcu
const&) =
delete;
36 rcu& operator=(rcu
const&) =
delete;
37 rcu& operator=(rcu&&) =
delete;
69 value_type
const *
get() noexcept
71 return _ptr.load(std::memory_order::acquire);
81#if defined(__alpha__) or defined(__alpha) or defined(_M_ALPHA)
82 return _ptr.load(std::memory_order::acquire);
84 return _ptr.load(std::memory_order::relaxed);
92 [[nodiscard]] uint64_t
version() const noexcept
101 hilet lock = std::scoped_lock(_old_ptrs_mutex);
102 return _old_ptrs.size() + not empty();
111 [[nodiscard]] value_type *
exchange(value_type *ptr)
noexcept
113 return _ptr.exchange(ptr, std::memory_order::release);
118 [[nodiscard]] value_type *
copy() const noexcept
122 hilet *new_ptr = std::construct_at(allocation, *get());
137 template<
typename... Args>
141 auto *
const new_ptr = std::construct_at(allocation, std::forward<Args>(args)...);
144 auto *
const old_ptr = exchange(new_ptr);
145 hilet old_version = version();
148 add_old_copy(old_version, old_ptr);
151 [[nodiscard]]
bool empty() const noexcept
153 return not to_bool(_ptr.load(std::memory_order::relaxed));
156 explicit operator bool() const noexcept
161 void reset() noexcept
164 auto *
const old_ptr = _ptr.exchange(
nullptr, std::memory_order::release);
165 hilet old_version = *_idle_count;
168 add_old_copy(old_version, old_ptr);
171 rcu& operator=(nullptr_t)
noexcept
192 hilet new_version = version();
194 hilet lock = std::scoped_lock(_old_ptrs_mutex);
195 _old_ptrs.emplace_back(old_version, old_ptr);
198 auto it = _old_ptrs.begin();
199 while (it != _old_ptrs.end() and it->first < new_version) {
200 std::destroy_at(it->second);
204 _old_ptrs.erase(_old_ptrs.begin(), it);
211 allocator_type _allocator;
216template<
typename RCU>
219 using rcu_type = RCU;
220 using value_type = rcu_type::value_type;
235 constexpr rcu_read()
noexcept =
default;
237 rcu_read(
rcu_read const& other) noexcept : _rcu(other._rcu), _ptr(other._ptr)
242 rcu_read(
rcu_read&& other) noexcept : _rcu(std::exchange(other._rcu,
nullptr)), _ptr(std::exchange(other._ptr,
nullptr)) {}
246 if (_rcu != other._rcu) {
248 other._rcu->read_lock();
263 if (_rcu and _rcu != other._rcu) {
267 _rcu = std::exchange(other._rcu,
nullptr);
268 _ptr = std::exchange(other._ptr,
nullptr);
272 [[nodiscard]]
constexpr value_type
const *operator->()
const noexcept
277 [[nodiscard]]
constexpr value_type
const& operator*()
const noexcept
283 [[nodiscard]]
constexpr bool empty()
const noexcept
285 return _ptr ==
nullptr;
288 constexpr operator bool()
const noexcept
293 [[nodiscard]]
constexpr bool operator==(nullptr_t)
const noexcept
295 return _rcu ==
nullptr;
298 void reset()
noexcept
306 rcu_read& operator=(nullptr_t)
noexcept
313 rcu_type *_rcu =
nullptr;
314 value_type
const *_ptr =
nullptr;
317template<
typename RCU>
320 using rcu_type = RCU;
321 using value_type = rcu_type::value_type;
330 constexpr rcu_write()
noexcept =
default;
334 rcu_write(
rcu_write&& other) noexcept : _rcu(std::exchange(other._rcu,
nullptr)), _ptr(std::exchange(other._ptr,
nullptr)) {}
339 _rcu = std::exchange(other._rcu,
nullptr);
340 _ptr = std::exchange(other._ptr,
nullptr);
344 [[nodiscard]]
constexpr bool empty()
const noexcept
346 return _ptr ==
nullptr;
349 constexpr operator bool()
const noexcept
354 [[nodiscard]]
constexpr bool operator==(nullptr_t)
const noexcept
356 return _ptr ==
nullptr;
359 void reset()
noexcept
363 hilet *old_ptr = _rcu.exchange(_ptr);
367 _rcu.add_old_copy(old_version, old_ptr);
380 rcu_type *_rcu =
nullptr;
381 value_type *_ptr =
nullptr;
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Read-copy-update.
Definition rcu.hpp:21
constexpr rcu(allocator_type allocator=allocator_type{}) noexcept
Construct a new rcu object.
Definition rcu.hpp:31
value_type const * get() noexcept
get the rcu-pointer.
Definition rcu.hpp:69
void add_old_copy(uint64_t old_version, value_type *old_ptr) noexcept
Add an old copy.
Definition rcu.hpp:186
void emplace(Args &&...args) noexcept
Emplace a new value.
Definition rcu.hpp:138
void read_lock() noexcept
Lock the rcu pointer for reading.
Definition rcu.hpp:41
void write_unlock() noexcept
Unlock the rcu pointer for writing.
Definition rcu.hpp:62
value_type * copy() const noexcept
Create a copy of the value.
Definition rcu.hpp:118
value_type * exchange(value_type *ptr) noexcept
Exchange the rcu-pointers.
Definition rcu.hpp:111
value_type const * unsafe_get() noexcept
Derefence the rcu-pointer.
Definition rcu.hpp:79
size_t capacity() const noexcept
Number of object that are currently allocated.
Definition rcu.hpp:99
void write_lock() noexcept
Lock the rcu pointer for writing.
Definition rcu.hpp:55
uint64_t version() const noexcept
The version of the lock.
Definition rcu.hpp:92
void read_unlock() noexcept
Unlock the rcu pointer for reading.
Definition rcu.hpp:48
Counts how many times a critical section was idle.
Definition wfree_idle_count.hpp:39