71 static constexpr std::size_t
const NUM = 14;
72 static constexpr std::size_t
const NUM_BUCKETS = std::size_t(1) << (32 - NUM);
73 static constexpr std::size_t
const NUM_BLOCKS_PER_BUCKET = std::size_t(1) << NUM;
81 using Data = std::array<T, NUM_BLOCKS_PER_BUCKET>;
84 struct alignas(32)
S {
86 alignas(8)
bool modified =
false;
91 using size_type = std::size_t;
92 using pos_type = TreeIndex::pos_type;
94 using value_type = std::tuple<Data<pos_type>,
S<Ts>...>;
95 using Bucket = std::atomic<value_type*>;
102 using reverse_iterator = std::reverse_iterator<iterator<T>>;
104 using const_reverse_iterator = std::reverse_iterator<const_iterator<T>>;
111 using reverse_bucket_iterator = std::reverse_iterator<bucket_iterator<T>>;
113 using const_reverse_bucket_iterator = std::reverse_iterator<const_bucket_iterator<T>>;
119 : cap_(other.cap_.load()), num_inactive_(other.num_inactive_.load())
121 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
122 if (
nullptr == other.buckets_[i]) {
126 buckets_[i] =
new value_type(*other.buckets_[i]);
130 template <
class... Ts2>
131 TreeContainer(TreeContainer<Ts2...>
const& other)
132 : cap_(other.cap_.load()), num_inactive_(other.num_inactive_.load())
139 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
140 if (
nullptr == buckets_[i]) {
148 TreeContainer& operator=(TreeContainer
const& rhs)
150 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
151 if (
nullptr == rhs.buckets_[i]) {
155 if (
nullptr == buckets_[i]) {
156 buckets_[i] =
new value_type(*rhs.buckets_[i]);
158 bucket(i) = rhs.bucket(i);
162 cap_ = rhs.cap_.load();
163 num_inactive_ = rhs.num_inactive_.load();
168 template <
class... Ts2>
169 TreeContainer& operator=(TreeContainer<Ts2...>
const& rhs)
173 cap_ = rhs.cap_.load();
174 num_inactive_ = rhs.num_inactive_.load();
180 [[nodiscard]] iterator<T> begin()
182 return iterator<T>(
this, 0);
186 [[nodiscard]] const_iterator<T> begin()
const
188 return const_iterator<T>(
const_cast<TreeContainer*
>(
this), 0);
192 [[nodiscard]] const_iterator<T> cbegin()
const
198 [[nodiscard]] iterator<T> end()
200 return iterator<T>(
this, capacity());
204 [[nodiscard]] const_iterator<T> end()
const
206 return const_iterator<T>(
const_cast<TreeContainer*
>(
this), capacity());
210 [[nodiscard]] const_iterator<T> cend()
const
216 [[nodiscard]] reverse_iterator<T> rbegin()
218 return std::make_reverse_iterator(end<T>());
222 [[nodiscard]] const_reverse_iterator<T> rbegin()
const
224 return std::make_reverse_iterator(end<T>());
228 [[nodiscard]] const_reverse_iterator<T> crbegin()
const
234 [[nodiscard]] reverse_iterator<T> rend()
236 return std::make_reverse_iterator(begin<T>());
240 [[nodiscard]] const_reverse_iterator<T> rend()
const
242 return std::make_reverse_iterator(begin<T>());
246 [[nodiscard]] const_reverse_iterator<T> crend()
const
252 [[nodiscard]]
auto iter()
254 return std::ranges::subrange(begin<T>(), end<T>());
258 [[nodiscard]]
auto iter()
const
260 return std::ranges::subrange(begin<T>(), end<T>());
264 [[nodiscard]]
auto riter()
266 return std::ranges::subrange(rbegin<T>(), rend<T>());
270 [[nodiscard]]
auto riter()
const
272 return std::ranges::subrange(rbegin<T>(), rend<T>());
276 [[nodiscard]] bucket_iterator<T> beginBucket()
278 return bucket_iterator<T>(
this, 0);
282 [[nodiscard]] const_bucket_iterator<T> beginBucket()
const
284 return const_bucket_iterator<T>(
const_cast<TreeContainer*
>(
this), 0);
288 [[nodiscard]] const_bucket_iterator<T> cbeginBucket()
const
290 return beginBucket<T>();
294 [[nodiscard]] bucket_iterator<T> endBucket()
296 return bucket_iterator<T>(
this, numBuckets());
300 [[nodiscard]] const_bucket_iterator<T> endBucket()
const
302 return const_bucket_iterator<T>(
const_cast<TreeContainer*
>(
this), numBuckets());
306 [[nodiscard]] const_bucket_iterator<T> cendBucket()
const
308 return endBucket<T>();
312 [[nodiscard]] reverse_bucket_iterator<T> rbeginBucket()
314 return std::make_reverse_iterator(endBucket<T>());
318 [[nodiscard]] const_reverse_bucket_iterator<T> rbeginBucket()
const
320 return std::make_reverse_iterator(endBucket<T>());
324 [[nodiscard]] const_reverse_bucket_iterator<T> crbeginBucket()
const
326 return rbeginBucket<T>();
330 [[nodiscard]] reverse_bucket_iterator<T> rendBucket()
332 return std::make_reverse_iterator(beginBucket<T>());
336 [[nodiscard]] const_reverse_bucket_iterator<T> rendBucket()
const
338 return std::make_reverse_iterator(beginBucket<T>());
342 [[nodiscard]] const_reverse_bucket_iterator<T> crendBucket()
const
344 return rendBucket<T>();
348 [[nodiscard]]
auto iterBucket()
350 return std::ranges::subrange(beginBucket<T>(), endBucket<T>());
354 [[nodiscard]]
auto iterBucket()
const
356 return std::ranges::subrange(beginBucket<T>(), endBucket<T>());
360 [[nodiscard]]
auto riterBucket()
362 return std::ranges::subrange(rbeginBucket<T>(), rendBucket<T>());
366 [[nodiscard]]
auto riterBucket()
const
368 return std::ranges::subrange(rbeginBucket<T>(), rendBucket<T>());
372 [[nodiscard]] S<T>& bucket(std::size_t idx)
374 return std::get<S<T>>(bucket(idx));
378 [[nodiscard]] S<T>
const& bucket(std::size_t idx)
const
380 return std::get<S<T>>(bucket(idx));
383 template <std::
size_t I>
384 [[nodiscard]]
auto& bucket(std::size_t idx)
386 return std::get<I + 1>(bucket(idx));
389 template <std::
size_t I>
390 [[nodiscard]]
auto const& bucket(std::size_t idx)
const
392 return std::get<I + 1>(bucket(idx));
396 [[nodiscard]]
bool& bucketModified(std::size_t idx)
398 return bucket<T>(idx).modified;
402 [[nodiscard]]
bool bucketModified(std::size_t idx)
const
404 return bucket<T>(idx).modified;
407 template <std::
size_t I>
408 [[nodiscard]]
bool& bucketModified(std::size_t idx)
410 return bucket<I>(idx).modified;
413 template <std::
size_t I>
414 [[nodiscard]]
bool bucketModified(std::size_t idx)
const
416 return bucket<I>(idx).modified;
420 [[nodiscard]] Data<T>& bucketData(std::size_t idx)
422 auto& x = bucket<T>(idx);
428 [[nodiscard]] Data<T>
const& bucketData(std::size_t idx)
const
430 return bucket<T>(idx).data;
433 template <std::
size_t I>
434 [[nodiscard]]
auto& bucketData(std::size_t idx)
436 auto& x = bucket<I>(idx);
441 template <std::
size_t I>
442 [[nodiscard]]
auto const& bucketData(std::size_t idx)
const
444 return bucket<I>(idx).data;
448 [[nodiscard]] T& get(pos_type pos)
450 return bucketData<T>(pos)[blockPos(pos)];
454 [[nodiscard]] T
const& get(pos_type pos)
const
456 return bucketData<T>(pos)[blockPos(pos)];
459 template <std::
size_t I>
460 [[nodiscard]]
auto& get(pos_type pos)
462 return bucketData<I>(pos)[blockPos(pos)];
465 template <std::
size_t I>
466 [[nodiscard]]
auto const& get(pos_type pos)
const
468 return bucketData<I>(pos)[blockPos(pos)];
471 [[nodiscard]]
constexpr pos_type numBuckets() const noexcept
473 return empty() ? 0 : bucketPos(capacity() - 1) + 1;
476 [[nodiscard]]
constexpr pos_type numBlocksPerBucket() const noexcept
478 return NUM_BLOCKS_PER_BUCKET;
481 [[nodiscard]]
constexpr pos_type bucketPos(pos_type pos)
const noexcept
483 return pos / NUM_BLOCKS_PER_BUCKET;
486 [[nodiscard]]
constexpr pos_type blockPos(pos_type pos)
const noexcept
488 return pos % NUM_BLOCKS_PER_BUCKET;
491 [[nodiscard]] pos_type create()
493 if (pos_type idx = num_inactive_.load(std::memory_order_relaxed); 0u < idx) {
495 num_inactive_.store(idx, std::memory_order_relaxed);
496 auto&
b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
497 return std::get<0>(
b)[blockPos(idx)];
500 pos_type idx = cap_.fetch_add(pos_type(1u), std::memory_order_relaxed);
502 pos_type bucket = bucketPos(idx);
504 value_type*
b = buckets_[bucket];
507 b =
new value_type();
508 buckets_[bucket] =
b;
514 [[nodiscard]] pos_type createThreadSafe()
516 if (0u < num_inactive_.load(std::memory_order_relaxed)) {
517 std::scoped_lock lock(mutex_);
518 if (pos_type idx = num_inactive_.load(std::memory_order_acquire); 0u < idx) {
520 num_inactive_.store(idx, std::memory_order_release);
521 auto&
b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
522 return std::get<0>(
b)[blockPos(idx)];
526 pos_type idx = cap_.fetch_add(pos_type(1u), std::memory_order_acq_rel);
528 pos_type bucket = bucketPos(idx);
529 pos_type block = blockPos(idx);
531 value_type* v = buckets_[bucket];
536 v =
new value_type();
537 buckets_[bucket] = v;
541 for (;
nullptr == v; v = buckets_[bucket]) {
549 void eraseBlock(pos_type block)
551 pos_type idx = num_inactive_.fetch_add(pos_type(1), std::memory_order_acq_rel);
552 auto&
b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
553 std::get<0>(
b)[blockPos(idx)] = block;
559 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
560 if (
nullptr == buckets_[i]) {
572 void reserve(pos_type cap)
575 pos_type first = bucketPos(capacity());
576 pos_type last = bucketPos(cap);
577 for (; last >= first; ++first) {
578 if (
nullptr == buckets_[first]) {
585 for (; last >= first; ++first) {
587 buckets_[first] =
new value_type();
593 for (std::size_t i = numBuckets(); NUM_BUCKETS > i; ++i) {
594 if (
nullptr == buckets_[i]) {
599 buckets_[i] =
nullptr;
603 [[nodiscard]]
bool empty()
const {
return 0 == size(); }
605 [[nodiscard]] pos_type size()
const {
return cap_ - num_inactive_; }
607 [[nodiscard]] pos_type capacity()
const {
return cap_; }
610 [[nodiscard]]
static constexpr size_type serializedBucketSize()
612 return sizeof(S<T>::data);
616 [[nodiscard]]
constexpr size_type serializedSize()
const
618 return numBuckets() * serializedBucketSize<T>();
621 void swap(TreeContainer& other)
624 swap(buckets_, other.buckets_);
627 cap_ = other.cap_.load();
631 num_inactive_ = other.num_inactive_.load();
632 other.num_inactive_ = tmp;
636 [[nodiscard]] value_type& bucket(std::size_t idx)
638 return *buckets_[bucketPos(idx)].load(std::memory_order_acquire);
641 [[nodiscard]] value_type
const& bucket(std::size_t idx)
const
643 return *buckets_[bucketPos(idx)].load(std::memory_order_acquire);
647 std::unique_ptr<Bucket[]> buckets_ = std::make_unique<Bucket[]>(NUM_BUCKETS);
649 std::atomic<pos_type> cap_{};
650 std::atomic<pos_type> num_inactive_{};