2#ifndef CEL_RUNTIME_DETAIL_RETIREMENT_HPP
3#define CEL_RUNTIME_DETAIL_RETIREMENT_HPP
10namespace cel::detail {
11static_assert(std::atomic<std::size_t>::is_always_lock_free,
12 "runtime ownership requires lock-free reference counts");
13class retirement_queue;
17struct retirement_node {
18 std::atomic<std::size_t> owners{1};
19 retirement_node* next =
nullptr;
20 void (*dispose)(retirement_node&, retirement_queue&)
noexcept;
23 explicit retirement_node(
void (*operation)(retirement_node&, retirement_queue&)
noexcept) :
30class retirement_queue {
31 retirement_node* _pending =
nullptr;
35 retirement_queue() noexcept = default;
37 retirement_queue(const retirement_queue&) = delete;
39 retirement_queue& operator=(const retirement_queue&) = delete;
44 auto* current = _pending;
45 _pending = current->next;
46 current->next =
nullptr;
47 current->dispose(*current, *
this);
52 void release(retirement_node* node)
noexcept {
55 if (node && node->owners.fetch_sub(1, std::memory_order_acq_rel) == 1) {
56 node->next = _pending;
67 retirement_node* _node =
nullptr;
71 retirement_ptr() noexcept = default;
74 explicit retirement_ptr(std::remove_const_t<T>* node) noexcept : _node(node) {}
76 retirement_ptr(
const retirement_ptr& other) noexcept : _node(other._node) {
77 if (_node) _node->owners.fetch_add(1, std::memory_order_relaxed);
80 retirement_ptr(retirement_ptr&& other) noexcept : _node(std::exchange(other._node,
nullptr)) {}
84 retirement_queue queue;
89 retirement_ptr& operator=(
const retirement_ptr& other)
noexcept {
90 retirement_ptr next(other);
96 retirement_ptr& operator=(retirement_ptr&& other)
noexcept {
98 retirement_ptr next(std::move(other));
104 void swap(retirement_ptr& other)
noexcept { std::swap(_node, other._node); }
106 void retire(retirement_queue& queue)
noexcept { queue.release(std::exchange(_node,
nullptr)); }
108 explicit operator bool() const noexcept {
return _node !=
nullptr; }
111 T* operator->() const noexcept {
113 return static_cast<T*
>(_node);