Wildmeshing Toolkit
Loading...
Searching...
No Matches
SlotPool.hpp
1#pragma once
2
3#include <atomic>
4#include <cstddef>
5#include <vector>
6
7namespace wmtk {
8
11inline constexpr size_t INVALID_SLOT = static_cast<size_t>(-1);
12
36template <class T>
38{
39public:
40 using value_type = T;
41
42 SlotPool() = default;
43 SlotPool(const SlotPool&) = delete;
44 SlotPool& operator=(const SlotPool&) = delete;
45
47 size_t capacity() const { return m_data.size(); }
48
52 size_t live() const { return m_live.load(std::memory_order_relaxed); }
53
55 void set_live(size_t n) { m_live.store(n, std::memory_order_relaxed); }
56
58 void resize(size_t n) { m_data.resize(n); }
59
60 void shrink_to_fit() { m_data.shrink_to_fit(); }
61
63 void clear()
64 {
65 m_data.clear();
66 set_live(0);
67 }
68
77 bool refused() const { return m_refused.load(std::memory_order_relaxed); }
78 void clear_refused() { m_refused.store(false, std::memory_order_relaxed); }
81 T& operator[](size_t i) { return m_data[i]; }
82 const T& operator[](size_t i) const { return m_data[i]; }
83
91 auto begin() { return m_data.begin(); }
92 auto end() { return m_data.end(); }
93 auto begin() const { return m_data.begin(); }
94 auto end() const { return m_data.end(); }
107 size_t request(size_t n)
108 {
109 size_t first = m_live.load(std::memory_order_relaxed);
110 if (n == 0) {
111 return first;
112 }
113 const size_t cap = m_data.size();
114 do {
115 // Phrased as a subtraction rather than `first + n > cap` so that it cannot
116 // overflow; `first <= cap` always holds, so `cap - first` is well defined.
117 if (first > cap || n > cap - first) {
118 m_refused.store(true, std::memory_order_relaxed);
119 return INVALID_SLOT;
120 }
121 } while (!m_live.compare_exchange_weak(
122 first,
123 first + n,
124 std::memory_order_acq_rel,
125 std::memory_order_relaxed));
126
127 // Reset the handed-out slots. The storage keeps whatever a previous generation left in
128 // the spare region, so a fresh slot has to be cleared here rather than being fresh by
129 // construction -- which is what the tbb::concurrent_vector this replaced used to give.
130 for (size_t i = first; i < first + n; ++i) {
131 m_data[i] = T{};
132 }
133 return first;
134 }
135
136private:
137 std::vector<T> m_data;
138 std::atomic<size_t> m_live{0};
139 std::atomic<bool> m_refused{false};
140};
141
142} // namespace wmtk
Preallocated storage plus the atomic counter that hands slots out of it.
Definition SlotPool.hpp:38
void set_live(size_t n)
Set the live count directly. For init and consolidate, which fill [0, n) themselves.
Definition SlotPool.hpp:55
size_t capacity() const
Slots the storage can hold: the end of the spare region.
Definition SlotPool.hpp:47
void clear()
Drop the storage and the live count together, leaving an empty pool.
Definition SlotPool.hpp:63
void resize(size_t n)
Resize the storage. Does not touch the live count – the caller decides that.
Definition SlotPool.hpp:58
size_t request(size_t n)
Atomically reserve n contiguous fresh slots.
Definition SlotPool.hpp:107
size_t live() const
Definition SlotPool.hpp:52