RADLib
RADical C++ application framework
RADDataStructures.h
Go to the documentation of this file.
1 
6 #pragma once
7 
8 #include <RADCore/RADLicenseGate.h>
9 
10 #include <algorithm>
11 #include <atomic>
12 #include <cstddef>
13 #include <cstdint>
14 #include <cstdlib>
15 #include <cstring>
16 #include <functional>
17 #include <initializer_list>
18 #include <iterator>
19 #include <limits>
20 #include <memory>
21 #include <new>
22 #include <optional>
23 #include <stdexcept>
24 #include <type_traits>
25 #include <utility>
26 #include <vector>
27 
28 namespace RADData {
29 
31  namespace Detail {
33  constexpr size_t nextPowerOfTwo(size_t value) {
34  if (value <= 2) return 2;
35  --value;
36  for (size_t shift = 1; shift < sizeof(size_t) * 8; shift <<= 1) {
37  value |= value >> shift;
38  }
39  return value + 1;
40  }
41  }
42 
44  template<typename T>
45  class RADArrayView {
46  public:
48  RADArrayView() = default;
50  RADArrayView(T* data, size_t size) : data_(data), size_(size) {}
52  template<typename Container>
53  explicit RADArrayView(Container& container) : data_(container.data()), size_(container.size()) {}
54 
56  T* data() const { return data_; }
58  size_t size() const { return size_; }
60  bool empty() const { return size_ == 0; }
62  T& operator[](size_t index) const { return data_[index]; }
64  T* begin() const { return data_; }
66  T* end() const { return data_ + size_; }
67 
68  private:
69  T* data_ = nullptr;
70  size_t size_ = 0;
71  };
72 
77 
79  class RADByteArray {
80  public:
82  RADByteArray() = default;
84  explicit RADByteArray(size_t count) : bytes_(count) {}
86  RADByteArray(const void* data, size_t size) { append(data, size); }
87 
89  size_t size() const { return bytes_.size(); }
91  bool empty() const { return bytes_.empty(); }
93  uint8_t* data() { return bytes_.data(); }
95  const uint8_t* data() const { return bytes_.data(); }
97  uint8_t& operator[](size_t index) { return bytes_[index]; }
99  const uint8_t& operator[](size_t index) const { return bytes_[index]; }
101  void clear() { bytes_.clear(); }
103  void reserve(size_t capacity) { bytes_.reserve(capacity); }
105  void append(uint8_t byte) { bytes_.push_back(byte); }
107  void append(const void* data, size_t size) {
108  if (!data || size == 0) return;
109  const auto* first = static_cast<const uint8_t*>(data);
110  bytes_.insert(bytes_.end(), first, first + size);
111  }
113  RADByteArrayView view() { return RADByteArrayView(bytes_.data(), bytes_.size()); }
115  RADConstByteArrayView view() const { return RADConstByteArrayView(bytes_.data(), bytes_.size()); }
117  const std::vector<uint8_t>& vector() const { return bytes_; }
118 
119  private:
120  std::vector<uint8_t> bytes_;
121  };
122 
125  public:
127  explicit RADMonotonicArena(size_t capacity = 65536) : storage_(capacity) {}
129  void* allocate(size_t size, size_t alignment = alignof(std::max_align_t)) {
130  size_t current = offset_;
131  const size_t aligned = (current + alignment - 1) & ~(alignment - 1);
132  if (aligned + size > storage_.size()) {
133  storage_.resize(std::max(storage_.size() * 2, aligned + size));
134  }
135  offset_ = aligned + size;
136  return storage_.data() + aligned;
137  }
139  void reset() { offset_ = 0; }
141  size_t used() const { return offset_; }
143  size_t capacity() const { return storage_.size(); }
144 
145  private:
146  std::vector<uint8_t> storage_;
147  size_t offset_ = 0;
148  };
149 
151  class RADFixedPool {
152  public:
154  RADFixedPool(size_t blockSize, size_t blockCount)
155  : blockSize_(Detail::nextPowerOfTwo(std::max(blockSize, sizeof(std::max_align_t)))),
156  storage_((blockSize_ * blockCount + sizeof(std::max_align_t) - 1) / sizeof(std::max_align_t)),
157  freeList_(nullptr) {
158  auto* base = reinterpret_cast<uint8_t*>(storage_.data());
159  for (size_t i = 0; i < blockCount; ++i) {
160  auto* block = base + i * blockSize_;
161  *reinterpret_cast<uint8_t**>(block) = freeList_;
162  freeList_ = block;
163  }
164  }
165 
167  void* allocate() {
168  if (!freeList_) return nullptr;
169  uint8_t* block = freeList_;
170  freeList_ = *reinterpret_cast<uint8_t**>(freeList_);
171  return block;
172  }
173 
175  void deallocate(void* ptr) {
176  if (!ptr) return;
177  auto* block = static_cast<uint8_t*>(ptr);
178  *reinterpret_cast<uint8_t**>(block) = freeList_;
179  freeList_ = block;
180  }
181 
183  size_t blockSize() const { return blockSize_; }
184 
185  private:
186  size_t blockSize_ = 0;
187  std::vector<std::max_align_t> storage_;
188  uint8_t* freeList_ = nullptr;
189  };
190 
192  template<typename T>
194  public:
195  using value_type = T;
196 
198  template<typename U>
199  struct rebind {
201  };
202 
208  template<typename U>
209  RADMonotonicAllocator(const RADMonotonicAllocator<U>& other) : arena_(other.arena()) {}
210 
212  T* allocate(size_t n) {
213  if (!arena_) return std::allocator<T>{}.allocate(n);
214  return static_cast<T*>(arena_->allocate(sizeof(T) * n, alignof(T)));
215  }
217  void deallocate(T* ptr, size_t n) {
218  if (!arena_) std::allocator<T>{}.deallocate(ptr, n);
219  }
221  RADMonotonicArena* arena() const { return arena_; }
222 
223  template<typename U> friend class RADMonotonicAllocator;
224 
225  private:
226  RADMonotonicArena* arena_ = nullptr;
227  };
228 
230  template<typename T, typename U>
232  return lhs.arena() == rhs.arena();
233  }
234 
236  template<typename T, typename U>
238  return !(lhs == rhs);
239  }
240 
242  template<typename T, size_t Alignment = alignof(T)>
244  public:
245  using value_type = T;
246 
248  template<typename U>
249  struct rebind {
251  };
252 
254  T* allocate(size_t n) {
255  void* ptr = nullptr;
256  if (posix_memalign(&ptr, Alignment, sizeof(T) * n) != 0) {
257  throw std::bad_alloc();
258  }
259  return static_cast<T*>(ptr);
260  }
262  void deallocate(T* ptr, size_t) { std::free(ptr); }
263  };
264 
266  template<typename T, size_t A, typename U, size_t B>
268  return A == B;
269  }
270 
272  template<typename T, size_t A, typename U, size_t B>
274  return !(lhs == rhs);
275  }
276 
278  template <typename T, typename Alloc = std::allocator<T>>
279  class RADVector {
280  public:
282  using value_type = T;
284  using allocator_type = Alloc;
286  using size_type = size_t;
288  using reference = T&;
290  using const_reference = const T&;
292  using pointer = T*;
294  using const_pointer = const T*;
296  using iterator = T*;
298  using const_iterator = const T*;
299 
301  RADVector() = default;
302 
304  explicit RADVector(size_t count, const T& value = T()) {
305  resize(count, value);
306  }
307 
309  RADVector(std::initializer_list<T> values) {
310  reserve(values.size());
311  for (const auto& value : values) push_back(value);
312  }
313 
315  RADVector(const RADVector& other) {
316  reserve(other.size_);
317  for (const auto& value : other) push_back(value);
318  }
319 
321  RADVector(RADVector&& other) noexcept
322  : data_(other.data_),
323  size_(other.size_),
324  capacity_(other.capacity_),
325  allocator_(std::move(other.allocator_)) {
326  other.data_ = nullptr;
327  other.size_ = 0;
328  other.capacity_ = 0;
329  }
330 
332  RADVector& operator=(const RADVector& other) {
333  if (this == &other) return *this;
334  clear();
335  reserve(other.size_);
336  for (const auto& value : other) push_back(value);
337  return *this;
338  }
339 
341  RADVector& operator=(RADVector&& other) noexcept {
342  if (this == &other) return *this;
343  destroyStorage();
344  data_ = other.data_;
345  size_ = other.size_;
346  capacity_ = other.capacity_;
347  allocator_ = std::move(other.allocator_);
348  other.data_ = nullptr;
349  other.size_ = 0;
350  other.capacity_ = 0;
351  return *this;
352  }
353 
356  destroyStorage();
357  }
358 
360  iterator begin() noexcept { return data_; }
362  const_iterator begin() const noexcept { return data_; }
364  const_iterator cbegin() const noexcept { return data_; }
366  iterator end() noexcept { return data_ + size_; }
368  const_iterator end() const noexcept { return data_ + size_; }
370  const_iterator cend() const noexcept { return data_ + size_; }
371 
373  bool empty() const noexcept { return size_ == 0; }
375  size_t size() const noexcept { return size_; }
377  size_t capacity() const noexcept { return capacity_; }
379  T* data() noexcept { return data_; }
381  const T* data() const noexcept { return data_; }
382 
384  T& operator[](size_t index) noexcept { return data_[index]; }
386  const T& operator[](size_t index) const noexcept { return data_[index]; }
387 
389  T& at(size_t index) {
390  if (index >= size_) throw std::out_of_range("RADVector::at");
391  return data_[index];
392  }
393 
395  const T& at(size_t index) const {
396  if (index >= size_) throw std::out_of_range("RADVector::at");
397  return data_[index];
398  }
399 
401  T& front() noexcept { return data_[0]; }
403  const T& front() const noexcept { return data_[0]; }
405  T& back() noexcept { return data_[size_ - 1]; }
407  const T& back() const noexcept { return data_[size_ - 1]; }
408 
410  void reserve(size_t newCapacity) {
411  if (newCapacity <= capacity_) return;
412  reallocate(newCapacity);
413  }
414 
416  void shrink_to_fit() {
417  if (size_ == capacity_) return;
418  if (size_ == 0) {
419  destroyStorage();
420  return;
421  }
422  reallocate(size_);
423  }
424 
426  void resize(size_t newSize) {
427  if (newSize < size_) {
428  destroyRange(newSize, size_);
429  size_ = newSize;
430  return;
431  }
432  reserveForSize(newSize);
433  for (; size_ < newSize; ++size_) {
434  std::allocator_traits<Alloc>::construct(allocator_, data_ + size_);
435  }
436  }
437 
439  void resize(size_t newSize, const T& value) {
440  if (newSize < size_) {
441  destroyRange(newSize, size_);
442  size_ = newSize;
443  return;
444  }
445  reserveForSize(newSize);
446  for (; size_ < newSize; ++size_) {
447  std::allocator_traits<Alloc>::construct(allocator_, data_ + size_, value);
448  }
449  }
450 
452  template <typename... Args>
453  T& emplace_back(Args&&... args) {
454  reserveForSize(size_ + 1);
455  std::allocator_traits<Alloc>::construct(
456  allocator_, data_ + size_, std::forward<Args>(args)...);
457  return data_[size_++];
458  }
459 
461  void push_back(const T& value) { emplace_back(value); }
463  void push_back(T&& value) { emplace_back(std::move(value)); }
464 
466  void pop_back() {
467  if (size_ == 0) return;
468  --size_;
469  std::allocator_traits<Alloc>::destroy(allocator_, data_ + size_);
470  }
471 
474  const size_t index = static_cast<size_t>(position - data_);
475  if (index >= size_) return end();
476  for (size_t i = index; i + 1 < size_; ++i) {
477  data_[i] = std::move(data_[i + 1]);
478  }
479  pop_back();
480  return data_ + index;
481  }
482 
484  void clear() noexcept {
485  destroyRange(0, size_);
486  size_ = 0;
487  }
488 
489  private:
490  void reserveForSize(size_t desired) {
491  if (desired <= capacity_) return;
492  const size_t grown = capacity_ == 0 ? 8 : capacity_ + capacity_ / 2;
493  reallocate(std::max(desired, grown));
494  }
495 
496  void reallocate(size_t newCapacity) {
497  T* newData = std::allocator_traits<Alloc>::allocate(allocator_, newCapacity);
498  size_t constructed = 0;
499  try {
500  for (; constructed < size_; ++constructed) {
501  std::allocator_traits<Alloc>::construct(
502  allocator_, newData + constructed,
503  std::move_if_noexcept(data_[constructed]));
504  }
505  } catch (...) {
506  for (size_t i = 0; i < constructed; ++i) {
507  std::allocator_traits<Alloc>::destroy(allocator_, newData + i);
508  }
509  std::allocator_traits<Alloc>::deallocate(allocator_, newData, newCapacity);
510  throw;
511  }
512  destroyRange(0, size_);
513  if (data_) std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
514  data_ = newData;
515  capacity_ = newCapacity;
516  }
517 
518  void destroyRange(size_t first, size_t last) noexcept {
519  for (size_t i = first; i < last; ++i) {
520  std::allocator_traits<Alloc>::destroy(allocator_, data_ + i);
521  }
522  }
523 
524  void destroyStorage() noexcept {
525  clear();
526  if (data_) {
527  std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
528  data_ = nullptr;
529  capacity_ = 0;
530  }
531  }
532 
533  T* data_ = nullptr;
534  size_t size_ = 0;
535  size_t capacity_ = 0;
536  Alloc allocator_;
537  };
538 
540  template <typename T, size_t InlineN = 8, typename Alloc = std::allocator<T>>
542  public:
544  using iterator = T*;
546  using const_iterator = const T*;
547 
550  : data_(inlineData()), capacity_(InlineN) {}
551 
553  RADSmallVector(std::initializer_list<T> values)
554  : RADSmallVector() {
555  reserve(values.size());
556  for (const auto& value : values) push_back(value);
557  }
558 
561  : RADSmallVector() {
562  reserve(other.size_);
563  for (const auto& value : other) push_back(value);
564  }
565 
567  RADSmallVector(RADSmallVector&& other) noexcept
568  : RADSmallVector() {
569  if (other.usingInline()) {
570  for (auto& value : other) push_back(std::move(value));
571  other.clear();
572  } else {
573  data_ = other.data_;
574  size_ = other.size_;
575  capacity_ = other.capacity_;
576  other.data_ = other.inlineData();
577  other.size_ = 0;
578  other.capacity_ = InlineN;
579  }
580  }
581 
584  if (this == &other) return *this;
585  clear();
586  reserve(other.size_);
587  for (const auto& value : other) push_back(value);
588  return *this;
589  }
590 
593  if (this == &other) return *this;
594  destroyHeapStorage();
595  data_ = inlineData();
596  size_ = 0;
597  capacity_ = InlineN;
598  if (other.usingInline()) {
599  for (auto& value : other) push_back(std::move(value));
600  other.clear();
601  } else {
602  data_ = other.data_;
603  size_ = other.size_;
604  capacity_ = other.capacity_;
605  other.data_ = other.inlineData();
606  other.size_ = 0;
607  other.capacity_ = InlineN;
608  }
609  return *this;
610  }
611 
614  destroyHeapStorage();
615  }
616 
618  iterator begin() noexcept { return data_; }
620  const_iterator begin() const noexcept { return data_; }
622  iterator end() noexcept { return data_ + size_; }
624  const_iterator end() const noexcept { return data_ + size_; }
626  bool empty() const noexcept { return size_ == 0; }
628  size_t size() const noexcept { return size_; }
630  size_t capacity() const noexcept { return capacity_; }
632  bool usingInlineStorage() const noexcept { return usingInline(); }
634  T* data() noexcept { return data_; }
636  const T* data() const noexcept { return data_; }
638  T& operator[](size_t index) noexcept { return data_[index]; }
640  const T& operator[](size_t index) const noexcept { return data_[index]; }
642  T& back() noexcept { return data_[size_ - 1]; }
644  const T& back() const noexcept { return data_[size_ - 1]; }
645 
647  void reserve(size_t newCapacity) {
648  if (newCapacity <= capacity_) return;
649  reallocate(newCapacity);
650  }
651 
653  template <typename... Args>
654  T& emplace_back(Args&&... args) {
655  if (size_ == capacity_) {
656  reallocate(capacity_ + capacity_ / 2 + 1);
657  }
658  new (data_ + size_) T(std::forward<Args>(args)...);
659  return data_[size_++];
660  }
661 
663  void push_back(const T& value) { emplace_back(value); }
665  void push_back(T&& value) { emplace_back(std::move(value)); }
666 
668  void pop_back() {
669  if (size_ == 0) return;
670  data_[--size_].~T();
671  }
672 
674  void clear() noexcept {
675  for (size_t i = 0; i < size_; ++i) data_[i].~T();
676  size_ = 0;
677  }
678 
679  private:
680  using Storage = std::aligned_storage_t<sizeof(T), alignof(T)>;
681 
682  T* inlineData() noexcept {
683  return reinterpret_cast<T*>(inlineStorage_);
684  }
685 
686  const T* inlineData() const noexcept {
687  return reinterpret_cast<const T*>(inlineStorage_);
688  }
689 
690  bool usingInline() const noexcept {
691  return data_ == inlineData();
692  }
693 
694  void reallocate(size_t newCapacity) {
695  T* newData = std::allocator_traits<Alloc>::allocate(allocator_, newCapacity);
696  size_t constructed = 0;
697  try {
698  for (; constructed < size_; ++constructed) {
699  new (newData + constructed) T(std::move_if_noexcept(data_[constructed]));
700  }
701  } catch (...) {
702  for (size_t i = 0; i < constructed; ++i) newData[i].~T();
703  std::allocator_traits<Alloc>::deallocate(allocator_, newData, newCapacity);
704  throw;
705  }
706  clear();
707  if (!usingInline()) {
708  std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
709  }
710  data_ = newData;
711  size_ = constructed;
712  capacity_ = newCapacity;
713  }
714 
715  void destroyHeapStorage() noexcept {
716  clear();
717  if (!usingInline()) {
718  std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
719  data_ = inlineData();
720  capacity_ = InlineN;
721  }
722  }
723 
724  Storage inlineStorage_[InlineN == 0 ? 1 : InlineN];
725  T* data_;
726  size_t size_ = 0;
727  size_t capacity_;
728  Alloc allocator_;
729  };
730 
732  template <typename T, typename Alloc = std::allocator<T>>
734  public:
736  explicit RADRingBuffer(size_t capacity = 16) {
737  reserve(capacity);
738  }
739 
742  clear();
743  if (data_) std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
744  }
745 
747  RADRingBuffer(const RADRingBuffer& other) {
748  reserve(other.capacity_);
749  for (const auto& value : other) push_back(value);
750  }
751 
754  if (this == &other) return *this;
755  clear();
756  reserve(other.capacity_);
757  for (const auto& value : other) push_back(value);
758  return *this;
759  }
760 
762  RADRingBuffer(RADRingBuffer&& other) noexcept
763  : data_(other.data_),
764  capacity_(other.capacity_),
765  mask_(other.mask_),
766  head_(other.head_),
767  size_(other.size_),
768  allocator_(std::move(other.allocator_)) {
769  other.data_ = nullptr;
770  other.capacity_ = 0;
771  other.mask_ = 0;
772  other.head_ = 0;
773  other.size_ = 0;
774  }
775 
777  RADRingBuffer& operator=(RADRingBuffer&& other) noexcept {
778  if (this == &other) return *this;
779  clear();
780  if (data_) std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
781  data_ = other.data_;
782  capacity_ = other.capacity_;
783  mask_ = other.mask_;
784  head_ = other.head_;
785  size_ = other.size_;
786  allocator_ = std::move(other.allocator_);
787  other.data_ = nullptr;
788  other.capacity_ = 0;
789  other.mask_ = 0;
790  other.head_ = 0;
791  other.size_ = 0;
792  return *this;
793  }
794 
796  class iterator {
797  public:
798  using iterator_category = std::forward_iterator_tag;
799  using value_type = T;
800  using difference_type = std::ptrdiff_t;
801  using pointer = T*;
802  using reference = T&;
803 
804  iterator(RADRingBuffer* owner, size_t offset) : owner_(owner), offset_(offset) {}
805  T& operator*() const { return (*owner_)[offset_]; }
806  iterator& operator++() { ++offset_; return *this; }
807  bool operator!=(const iterator& other) const { return offset_ != other.offset_; }
808 
809  private:
810  RADRingBuffer* owner_;
811  size_t offset_;
812  };
813 
816  public:
817  using iterator_category = std::forward_iterator_tag;
818  using value_type = T;
819  using difference_type = std::ptrdiff_t;
820  using pointer = const T*;
821  using reference = const T&;
822 
823  const_iterator(const RADRingBuffer* owner, size_t offset) : owner_(owner), offset_(offset) {}
824  const T& operator*() const { return (*owner_)[offset_]; }
825  const_iterator& operator++() { ++offset_; return *this; }
826  bool operator!=(const const_iterator& other) const { return offset_ != other.offset_; }
827 
828  private:
829  const RADRingBuffer* owner_;
830  size_t offset_;
831  };
832 
834  iterator begin() noexcept { return iterator(this, 0); }
836  iterator end() noexcept { return iterator(this, size_); }
838  const_iterator begin() const noexcept { return const_iterator(this, 0); }
840  const_iterator end() const noexcept { return const_iterator(this, size_); }
841 
843  bool empty() const noexcept { return size_ == 0; }
845  size_t size() const noexcept { return size_; }
847  size_t capacity() const noexcept { return capacity_; }
848 
850  T& operator[](size_t index) noexcept { return data_[physical(index)]; }
852  const T& operator[](size_t index) const noexcept { return data_[physical(index)]; }
854  T& front() noexcept { return (*this)[0]; }
856  const T& front() const noexcept { return (*this)[0]; }
858  T& back() noexcept { return (*this)[size_ - 1]; }
860  const T& back() const noexcept { return (*this)[size_ - 1]; }
861 
863  void reserve(size_t requestedCapacity) {
864  const size_t newCapacity = Detail::nextPowerOfTwo(requestedCapacity);
865  if (newCapacity <= capacity_) return;
866  T* newData = std::allocator_traits<Alloc>::allocate(allocator_, newCapacity);
867  size_t constructed = 0;
868  try {
869  for (; constructed < size_; ++constructed) {
870  std::allocator_traits<Alloc>::construct(
871  allocator_, newData + constructed,
872  std::move_if_noexcept((*this)[constructed]));
873  }
874  } catch (...) {
875  for (size_t i = 0; i < constructed; ++i) {
876  std::allocator_traits<Alloc>::destroy(allocator_, newData + i);
877  }
878  std::allocator_traits<Alloc>::deallocate(allocator_, newData, newCapacity);
879  throw;
880  }
881  clear();
882  if (data_) std::allocator_traits<Alloc>::deallocate(allocator_, data_, capacity_);
883  data_ = newData;
884  capacity_ = newCapacity;
885  mask_ = capacity_ - 1;
886  head_ = 0;
887  size_ = constructed;
888  }
889 
891  template <typename... Args>
892  T& emplace_back(Args&&... args) {
893  if (size_ == capacity_) reserve(capacity_ * 2);
894  const size_t index = physical(size_);
895  std::allocator_traits<Alloc>::construct(
896  allocator_, data_ + index, std::forward<Args>(args)...);
897  ++size_;
898  return data_[index];
899  }
900 
902  template <typename... Args>
903  T& emplace_front(Args&&... args) {
904  if (size_ == capacity_) reserve(capacity_ * 2);
905  head_ = (head_ - 1) & mask_;
906  std::allocator_traits<Alloc>::construct(
907  allocator_, data_ + head_, std::forward<Args>(args)...);
908  ++size_;
909  return data_[head_];
910  }
911 
913  void push_back(const T& value) { emplace_back(value); }
915  void push_back(T&& value) { emplace_back(std::move(value)); }
917  void push_front(const T& value) { emplace_front(value); }
919  void push_front(T&& value) { emplace_front(std::move(value)); }
920 
922  void pop_front() {
923  if (empty()) return;
924  std::allocator_traits<Alloc>::destroy(allocator_, data_ + head_);
925  head_ = (head_ + 1) & mask_;
926  --size_;
927  }
928 
930  void pop_back() {
931  if (empty()) return;
932  const size_t index = physical(size_ - 1);
933  std::allocator_traits<Alloc>::destroy(allocator_, data_ + index);
934  --size_;
935  }
936 
938  void clear() noexcept {
939  for (size_t i = 0; i < size_; ++i) {
940  std::allocator_traits<Alloc>::destroy(allocator_, data_ + physical(i));
941  }
942  head_ = 0;
943  size_ = 0;
944  }
945 
946  private:
947  size_t physical(size_t logical) const noexcept {
948  return (head_ + logical) & mask_;
949  }
950 
951  T* data_ = nullptr;
952  size_t capacity_ = 0;
953  size_t mask_ = 0;
954  size_t head_ = 0;
955  size_t size_ = 0;
956  Alloc allocator_;
957  };
958 
960  template <typename T, typename Alloc = std::allocator<T>>
961  class RADQueue {
962  public:
964  explicit RADQueue(size_t capacity = 16) : buffer_(capacity) {}
966  bool empty() const noexcept { return buffer_.empty(); }
968  size_t size() const noexcept { return buffer_.size(); }
970  T& front() noexcept { return buffer_.front(); }
972  const T& front() const noexcept { return buffer_.front(); }
974  void push(const T& value) { buffer_.push_back(value); }
976  void push(T&& value) { buffer_.push_back(std::move(value)); }
978  template <typename... Args> T& emplace(Args&&... args) {
979  return buffer_.emplace_back(std::forward<Args>(args)...);
980  }
982  void pop() { buffer_.pop_front(); }
984  void clear() { buffer_.clear(); }
985 
986  private:
987  RADRingBuffer<T, Alloc> buffer_;
988  };
989 
991  template <typename T, typename Alloc = std::allocator<T>>
992  class RADStack {
993  public:
995  bool empty() const noexcept { return values_.empty(); }
997  size_t size() const noexcept { return values_.size(); }
999  T& top() noexcept { return values_.back(); }
1001  const T& top() const noexcept { return values_.back(); }
1003  void push(const T& value) { values_.push_back(value); }
1005  void push(T&& value) { values_.push_back(std::move(value)); }
1007  template <typename... Args> T& emplace(Args&&... args) {
1008  return values_.emplace_back(std::forward<Args>(args)...);
1009  }
1011  void pop() { values_.pop_back(); }
1013  void clear() { values_.clear(); }
1014 
1015  private:
1016  RADVector<T, Alloc> values_;
1017  };
1018 
1020  template <typename T>
1022  public:
1024  explicit RADSpscQueue(size_t capacity)
1025  : capacity_(Detail::nextPowerOfTwo(capacity + 1)),
1026  mask_(capacity_ - 1),
1027  storage_(std::make_unique<Slot[]>(capacity_)) {}
1028 
1031  while (!empty()) {
1032  const size_t head = head_.load(std::memory_order_relaxed);
1033  storage_[head].ptr()->~T();
1034  head_.store((head + 1) & mask_, std::memory_order_relaxed);
1035  }
1036  }
1037 
1039  RADSpscQueue(const RADSpscQueue&) = delete;
1042 
1044  bool empty() const noexcept {
1045  return head_.load(std::memory_order_acquire) == tail_.load(std::memory_order_acquire);
1046  }
1047 
1049  size_t capacity() const noexcept { return capacity_ - 1; }
1050 
1052  bool try_push(const T& value) {
1053  return emplace(value);
1054  }
1055 
1057  bool try_push(T&& value) {
1058  return emplace(std::move(value));
1059  }
1060 
1062  template <typename... Args>
1063  bool emplace(Args&&... args) {
1064  const size_t tail = tail_.load(std::memory_order_relaxed);
1065  const size_t next = (tail + 1) & mask_;
1066  if (next == head_.load(std::memory_order_acquire)) return false;
1067  new (storage_[tail].ptr()) T(std::forward<Args>(args)...);
1068  tail_.store(next, std::memory_order_release);
1069  return true;
1070  }
1071 
1073  bool try_pop(T& out) {
1074  const size_t head = head_.load(std::memory_order_relaxed);
1075  if (head == tail_.load(std::memory_order_acquire)) return false;
1076  T* value = storage_[head].ptr();
1077  out = std::move(*value);
1078  value->~T();
1079  head_.store((head + 1) & mask_, std::memory_order_release);
1080  return true;
1081  }
1082 
1083  private:
1084  struct Slot {
1085  alignas(T) unsigned char bytes[sizeof(T)];
1086  T* ptr() noexcept { return reinterpret_cast<T*>(bytes); }
1087  };
1088 
1089  const size_t capacity_;
1090  const size_t mask_;
1091  std::unique_ptr<Slot[]> storage_;
1092  std::atomic<size_t> head_{0};
1093  std::atomic<size_t> tail_{0};
1094  };
1095 
1097  template <typename K, typename V, typename Hash = std::hash<K>, typename Eq = std::equal_to<K>>
1099  public:
1101  using value_type = std::pair<K, V>;
1102 
1103  private:
1104  enum class State : uint8_t { Empty, Occupied, Deleted };
1105  struct Entry {
1106  State state = State::Empty;
1107  std::optional<value_type> value;
1108  };
1109  struct InsertSlot {
1110  size_t index;
1111  bool found;
1112  };
1113 
1114  static constexpr size_t npos = std::numeric_limits<size_t>::max();
1115 
1116  public:
1119  rehash(16);
1120  }
1121 
1123  explicit RADFlatHashMap(size_t capacity) {
1124  rehash(capacity);
1125  }
1126 
1129  rehash(other.capacity_);
1130  for (const auto& value : other) insert(value.first, value.second);
1131  }
1132 
1135  if (this == &other) return *this;
1136  clear();
1137  delete[] entries_;
1138  entries_ = nullptr;
1139  capacity_ = 0;
1140  mask_ = 0;
1141  tombstones_ = 0;
1142  rehash(other.capacity_);
1143  for (const auto& value : other) insert(value.first, value.second);
1144  return *this;
1145  }
1146 
1148  RADFlatHashMap(RADFlatHashMap&& other) noexcept
1149  : entries_(other.entries_),
1150  capacity_(other.capacity_),
1151  mask_(other.mask_),
1152  size_(other.size_),
1153  tombstones_(other.tombstones_),
1154  hasher_(std::move(other.hasher_)),
1155  eq_(std::move(other.eq_)) {
1156  other.entries_ = nullptr;
1157  other.capacity_ = 0;
1158  other.mask_ = 0;
1159  other.size_ = 0;
1160  other.tombstones_ = 0;
1161  }
1162 
1165  if (this == &other) return *this;
1166  clear();
1167  delete[] entries_;
1168  entries_ = other.entries_;
1169  capacity_ = other.capacity_;
1170  mask_ = other.mask_;
1171  size_ = other.size_;
1172  tombstones_ = other.tombstones_;
1173  hasher_ = std::move(other.hasher_);
1174  eq_ = std::move(other.eq_);
1175  other.entries_ = nullptr;
1176  other.capacity_ = 0;
1177  other.mask_ = 0;
1178  other.size_ = 0;
1179  other.tombstones_ = 0;
1180  return *this;
1181  }
1182 
1185  clear();
1186  delete[] entries_;
1187  }
1188 
1190  class iterator {
1191  public:
1193  iterator(Entry* entry, Entry* end) : entry_(entry), end_(end) { skip(); }
1195  value_type& operator*() const { return *entry_->value; }
1197  value_type* operator->() const { return &*entry_->value; }
1199  iterator& operator++() { ++entry_; skip(); return *this; }
1201  bool operator!=(const iterator& other) const { return entry_ != other.entry_; }
1202 
1203  private:
1204  void skip() {
1205  while (entry_ != end_ && entry_->state != State::Occupied) ++entry_;
1206  }
1207  Entry* entry_;
1208  Entry* end_;
1209  };
1210 
1213  public:
1215  const_iterator(const Entry* entry, const Entry* end) : entry_(entry), end_(end) { skip(); }
1217  const value_type& operator*() const { return *entry_->value; }
1219  const value_type* operator->() const { return &*entry_->value; }
1221  const_iterator& operator++() { ++entry_; skip(); return *this; }
1223  bool operator!=(const const_iterator& other) const { return entry_ != other.entry_; }
1224 
1225  private:
1226  void skip() {
1227  while (entry_ != end_ && entry_->state != State::Occupied) ++entry_;
1228  }
1229  const Entry* entry_;
1230  const Entry* end_;
1231  };
1232 
1234  iterator begin() noexcept { return iterator(entries_, entries_ + capacity_); }
1236  iterator end() noexcept { return iterator(entries_ + capacity_, entries_ + capacity_); }
1238  const_iterator begin() const noexcept { return const_iterator(entries_, entries_ + capacity_); }
1240  const_iterator end() const noexcept { return const_iterator(entries_ + capacity_, entries_ + capacity_); }
1241 
1243  bool empty() const noexcept { return size_ == 0; }
1245  size_t size() const noexcept { return size_; }
1247  size_t capacity() const noexcept { return capacity_; }
1248 
1250  void clear() noexcept {
1251  if (!entries_) return;
1252  for (size_t i = 0; i < capacity_; ++i) {
1253  if (entries_[i].state == State::Occupied) entries_[i].value.reset();
1254  entries_[i].state = State::Empty;
1255  }
1256  size_ = 0;
1257  tombstones_ = 0;
1258  }
1259 
1261  bool contains(const K& key) const {
1262  return findIndex(key) != npos;
1263  }
1264 
1266  V* find(const K& key) {
1267  const size_t index = findIndex(key);
1268  return index == npos ? nullptr : &entries_[index].value->second;
1269  }
1270 
1272  const V* find(const K& key) const {
1273  const size_t index = findIndex(key);
1274  return index == npos ? nullptr : &entries_[index].value->second;
1275  }
1276 
1278  std::pair<iterator, bool> insert(const K& key, const V& value) {
1279  return emplace(key, value);
1280  }
1281 
1283  template <typename KeyArg, typename ValueArg>
1284  std::pair<iterator, bool> emplace(KeyArg&& key, ValueArg&& value) {
1285  ensureCapacity();
1286  InsertSlot slot = findInsertSlot(key);
1287  if (slot.found) {
1288  entries_[slot.index].value->second = std::forward<ValueArg>(value);
1289  return {iterator(entries_ + slot.index, entries_ + capacity_), false};
1290  }
1291  if (entries_[slot.index].state == State::Deleted) --tombstones_;
1292  entries_[slot.index].state = State::Occupied;
1293  entries_[slot.index].value.emplace(
1294  std::forward<KeyArg>(key), std::forward<ValueArg>(value));
1295  ++size_;
1296  return {iterator(entries_ + slot.index, entries_ + capacity_), true};
1297  }
1298 
1300  V& operator[](const K& key) {
1301  return emplace(key, V{}).first->second;
1302  }
1303 
1305  bool erase(const K& key) {
1306  const size_t index = findIndex(key);
1307  if (index == npos) return false;
1308  entries_[index].value.reset();
1309  entries_[index].state = State::Deleted;
1310  --size_;
1311  ++tombstones_;
1312  return true;
1313  }
1314 
1316  void reserve(size_t desired) {
1317  if (desired * 10 < capacity_ * 7) return;
1318  rehash(desired * 2);
1319  }
1320 
1321  private:
1322  void ensureCapacity() {
1323  if ((size_ + tombstones_ + 1) * 10 >= capacity_ * 7) {
1324  rehash(capacity_ * 2);
1325  }
1326  }
1327 
1328  void rehash(size_t requestedCapacity) {
1329  const size_t newCapacity = Detail::nextPowerOfTwo(std::max<size_t>(16, requestedCapacity));
1330  Entry* oldEntries = entries_;
1331  const size_t oldCapacity = capacity_;
1332  entries_ = new Entry[newCapacity];
1333  capacity_ = newCapacity;
1334  mask_ = newCapacity - 1;
1335  size_ = 0;
1336  tombstones_ = 0;
1337  if (!oldEntries) return;
1338  for (size_t i = 0; i < oldCapacity; ++i) {
1339  if (oldEntries[i].state == State::Occupied) {
1340  emplace(std::move(oldEntries[i].value->first), std::move(oldEntries[i].value->second));
1341  oldEntries[i].value.reset();
1342  }
1343  }
1344  delete[] oldEntries;
1345  }
1346 
1347  size_t findIndex(const K& key) const {
1348  if (!entries_) return npos;
1349  size_t index = hasher_(key) & mask_;
1350  for (;;) {
1351  const Entry& entry = entries_[index];
1352  if (entry.state == State::Empty) return npos;
1353  if (entry.state == State::Occupied && eq_(entry.value->first, key)) return index;
1354  index = (index + 1) & mask_;
1355  }
1356  }
1357 
1358  template <typename KeyArg>
1359  InsertSlot findInsertSlot(const KeyArg& key) const {
1360  size_t index = hasher_(key) & mask_;
1361  size_t firstDeleted = npos;
1362  for (;;) {
1363  const Entry& entry = entries_[index];
1364  if (entry.state == State::Empty) {
1365  return {firstDeleted == npos ? index : firstDeleted, false};
1366  }
1367  if (entry.state == State::Deleted) {
1368  if (firstDeleted == npos) firstDeleted = index;
1369  } else if (eq_(entry.value->first, key)) {
1370  return {index, true};
1371  }
1372  index = (index + 1) & mask_;
1373  }
1374  }
1375 
1376  Entry* entries_ = nullptr;
1377  size_t capacity_ = 0;
1378  size_t mask_ = 0;
1379  size_t size_ = 0;
1380  size_t tombstones_ = 0;
1381  Hash hasher_;
1382  Eq eq_;
1383  };
1384 
1386  template <typename K, typename Hash = std::hash<K>, typename Eq = std::equal_to<K>>
1388  public:
1390  bool empty() const noexcept { return map_.empty(); }
1392  size_t size() const noexcept { return map_.size(); }
1394  void clear() noexcept { map_.clear(); }
1396  void reserve(size_t desired) { map_.reserve(desired); }
1398  bool contains(const K& key) const { return map_.contains(key); }
1400  bool insert(const K& key) { return map_.insert(key, Empty{}).second; }
1402  bool erase(const K& key) { return map_.erase(key); }
1403 
1404  private:
1405  struct Empty {};
1406  RADFlatHashMap<K, Empty, Hash, Eq> map_;
1407  };
1408 
1410  template <typename T, typename Alloc = std::allocator<T>>
1411  class RADList {
1412  struct Node;
1413 
1414  public:
1416  RADList() = default;
1417 
1419  RADList(std::initializer_list<T> values) {
1420  for (const auto& value : values) push_back(value);
1421  }
1422 
1424  RADList(const RADList& other) {
1425  for (const auto& value : other) push_back(value);
1426  }
1427 
1429  RADList& operator=(const RADList& other) {
1430  if (this == &other) return *this;
1431  clear();
1432  for (const auto& value : other) push_back(value);
1433  return *this;
1434  }
1435 
1437  RADList(RADList&& other) noexcept
1438  : head_(other.head_), tail_(other.tail_), size_(other.size_) {
1439  other.head_ = nullptr;
1440  other.tail_ = nullptr;
1441  other.size_ = 0;
1442  }
1443 
1445  RADList& operator=(RADList&& other) noexcept {
1446  if (this == &other) return *this;
1447  clear();
1448  head_ = other.head_;
1449  tail_ = other.tail_;
1450  size_ = other.size_;
1451  other.head_ = nullptr;
1452  other.tail_ = nullptr;
1453  other.size_ = 0;
1454  return *this;
1455  }
1456 
1459  clear();
1460  }
1461 
1463  class iterator {
1464  public:
1466  iterator(Node* node) : node_(node) {}
1468  T& operator*() const { return node_->value; }
1470  T* operator->() const { return &node_->value; }
1472  iterator& operator++() { node_ = node_->next; return *this; }
1474  iterator& operator--() { node_ = node_->prev; return *this; }
1476  bool operator!=(const iterator& other) const { return node_ != other.node_; }
1478  bool operator==(const iterator& other) const { return node_ == other.node_; }
1479 
1480  private:
1481  friend class RADList;
1482  Node* node_;
1483  };
1484 
1487  public:
1489  const_iterator(const Node* node) : node_(node) {}
1491  const T& operator*() const { return node_->value; }
1493  const T* operator->() const { return &node_->value; }
1495  const_iterator& operator++() { node_ = node_->next; return *this; }
1497  bool operator!=(const const_iterator& other) const { return node_ != other.node_; }
1498 
1499  private:
1500  const Node* node_;
1501  };
1502 
1504  iterator begin() noexcept { return iterator(head_); }
1506  iterator end() noexcept { return iterator(nullptr); }
1508  const_iterator begin() const noexcept { return const_iterator(head_); }
1510  const_iterator end() const noexcept { return const_iterator(nullptr); }
1512  bool empty() const noexcept { return size_ == 0; }
1514  size_t size() const noexcept { return size_; }
1516  T& front() noexcept { return head_->value; }
1518  const T& front() const noexcept { return head_->value; }
1520  T& back() noexcept { return tail_->value; }
1522  const T& back() const noexcept { return tail_->value; }
1523 
1525  template <typename... Args>
1526  T& emplace_back(Args&&... args) {
1527  Node* node = new Node(std::forward<Args>(args)...);
1528  node->prev = tail_;
1529  if (tail_) tail_->next = node;
1530  else head_ = node;
1531  tail_ = node;
1532  ++size_;
1533  return node->value;
1534  }
1535 
1537  template <typename... Args>
1538  T& emplace_front(Args&&... args) {
1539  Node* node = new Node(std::forward<Args>(args)...);
1540  node->next = head_;
1541  if (head_) head_->prev = node;
1542  else tail_ = node;
1543  head_ = node;
1544  ++size_;
1545  return node->value;
1546  }
1547 
1549  void push_back(const T& value) { emplace_back(value); }
1551  void push_back(T&& value) { emplace_back(std::move(value)); }
1553  void push_front(const T& value) { emplace_front(value); }
1555  void push_front(T&& value) { emplace_front(std::move(value)); }
1556 
1558  void pop_front() {
1559  if (!head_) return;
1560  Node* node = head_;
1561  head_ = head_->next;
1562  if (head_) head_->prev = nullptr;
1563  else tail_ = nullptr;
1564  delete node;
1565  --size_;
1566  }
1567 
1569  void pop_back() {
1570  if (!tail_) return;
1571  Node* node = tail_;
1572  tail_ = tail_->prev;
1573  if (tail_) tail_->next = nullptr;
1574  else head_ = nullptr;
1575  delete node;
1576  --size_;
1577  }
1578 
1581  Node* node = it.node_;
1582  if (!node) return end();
1583  Node* next = node->next;
1584  if (node->prev) node->prev->next = node->next;
1585  else head_ = node->next;
1586  if (node->next) node->next->prev = node->prev;
1587  else tail_ = node->prev;
1588  delete node;
1589  --size_;
1590  return iterator(next);
1591  }
1592 
1594  void clear() noexcept {
1595  Node* node = head_;
1596  while (node) {
1597  Node* next = node->next;
1598  delete node;
1599  node = next;
1600  }
1601  head_ = nullptr;
1602  tail_ = nullptr;
1603  size_ = 0;
1604  }
1605 
1606  private:
1607  struct Node {
1608  template <typename... Args>
1609  explicit Node(Args&&... args) : value(std::forward<Args>(args)...) {}
1610  T value;
1611  Node* prev = nullptr;
1612  Node* next = nullptr;
1613  };
1614 
1615  Node* head_ = nullptr;
1616  Node* tail_ = nullptr;
1617  size_t size_ = 0;
1618  };
1619 
1620 } // namespace RADData
Standard-compatible aligned allocator.
Definition: RADDataStructures.h:243
void deallocate(T *ptr, size_t)
Frees aligned storage.
Definition: RADDataStructures.h:262
T value_type
Definition: RADDataStructures.h:245
T * allocate(size_t n)
Allocates n aligned objects.
Definition: RADDataStructures.h:254
Non-owning contiguous view over T values.
Definition: RADDataStructures.h:45
bool empty() const
Returns true when empty.
Definition: RADDataStructures.h:60
T * begin() const
Returns iterator to first element.
Definition: RADDataStructures.h:64
T * end() const
Returns iterator one past last element.
Definition: RADDataStructures.h:66
size_t size() const
Returns number of elements.
Definition: RADDataStructures.h:58
RADArrayView()=default
Creates an empty view.
T * data() const
Returns pointer to first element.
Definition: RADDataStructures.h:56
RADArrayView(T *data, size_t size)
Creates a view over data and size.
Definition: RADDataStructures.h:50
RADArrayView(Container &container)
Creates a view over a vector-like container.
Definition: RADDataStructures.h:53
T & operator[](size_t index) const
Returns element at index.
Definition: RADDataStructures.h:62
Owning byte array with lightweight append/view helpers.
Definition: RADDataStructures.h:79
const std::vector< uint8_t > & vector() const
Returns std::vector-compatible storage.
Definition: RADDataStructures.h:117
RADByteArray(size_t count)
Creates count zero-initialized bytes.
Definition: RADDataStructures.h:84
RADConstByteArrayView view() const
Returns const view.
Definition: RADDataStructures.h:115
void reserve(size_t capacity)
Reserves byte capacity.
Definition: RADDataStructures.h:103
uint8_t & operator[](size_t index)
Returns mutable byte at index.
Definition: RADDataStructures.h:97
void append(uint8_t byte)
Appends one byte.
Definition: RADDataStructures.h:105
bool empty() const
Returns true when no bytes are stored.
Definition: RADDataStructures.h:91
RADByteArrayView view()
Returns mutable view.
Definition: RADDataStructures.h:113
RADByteArray(const void *data, size_t size)
Creates bytes from raw memory.
Definition: RADDataStructures.h:86
const uint8_t * data() const
Returns const byte pointer.
Definition: RADDataStructures.h:95
size_t size() const
Returns number of bytes.
Definition: RADDataStructures.h:89
void clear()
Clears all bytes.
Definition: RADDataStructures.h:101
void append(const void *data, size_t size)
Appends raw memory bytes.
Definition: RADDataStructures.h:107
const uint8_t & operator[](size_t index) const
Returns const byte at index.
Definition: RADDataStructures.h:99
uint8_t * data()
Returns mutable byte pointer.
Definition: RADDataStructures.h:93
RADByteArray()=default
Creates an empty byte array.
Fixed-size block pool for high-frequency same-size allocations.
Definition: RADDataStructures.h:151
size_t blockSize() const
Returns the block size.
Definition: RADDataStructures.h:183
void deallocate(void *ptr)
Returns one block to the pool.
Definition: RADDataStructures.h:175
RADFixedPool(size_t blockSize, size_t blockCount)
Creates a pool with blockSize bytes per block and blockCount blocks.
Definition: RADDataStructures.h:154
void * allocate()
Allocates one fixed-size block or returns nullptr when exhausted.
Definition: RADDataStructures.h:167
Const forward iterator over occupied map entries.
Definition: RADDataStructures.h:1212
const_iterator & operator++()
Advances to the next occupied entry.
Definition: RADDataStructures.h:1221
const value_type & operator*() const
Returns current key/value pair.
Definition: RADDataStructures.h:1217
const_iterator(const Entry *entry, const Entry *end)
Creates a const iterator over an entry range.
Definition: RADDataStructures.h:1215
bool operator!=(const const_iterator &other) const
Compares iterator position.
Definition: RADDataStructures.h:1223
const value_type * operator->() const
Returns current key/value pair pointer.
Definition: RADDataStructures.h:1219
Forward iterator over occupied map entries.
Definition: RADDataStructures.h:1190
iterator(Entry *entry, Entry *end)
Creates an iterator over an entry range.
Definition: RADDataStructures.h:1193
iterator & operator++()
Advances to the next occupied entry.
Definition: RADDataStructures.h:1199
value_type & operator*() const
Returns current key/value pair.
Definition: RADDataStructures.h:1195
bool operator!=(const iterator &other) const
Compares iterator position.
Definition: RADDataStructures.h:1201
value_type * operator->() const
Returns current key/value pair pointer.
Definition: RADDataStructures.h:1197
Open-addressed flat hash map optimized for cache-local lookups.
Definition: RADDataStructures.h:1098
const_iterator begin() const noexcept
Returns const iterator to first occupied entry.
Definition: RADDataStructures.h:1238
RADFlatHashMap()
Creates an empty map with default capacity.
Definition: RADDataStructures.h:1118
std::pair< iterator, bool > emplace(KeyArg &&key, ValueArg &&value)
Inserts or replaces key/value with forwarding support.
Definition: RADDataStructures.h:1284
iterator end() noexcept
Returns iterator one past the entry table.
Definition: RADDataStructures.h:1236
RADFlatHashMap(const RADFlatHashMap &other)
Copies another map.
Definition: RADDataStructures.h:1128
~RADFlatHashMap()
Destroys entries and releases storage.
Definition: RADDataStructures.h:1184
std::pair< iterator, bool > insert(const K &key, const V &value)
Inserts or replaces key with value.
Definition: RADDataStructures.h:1278
RADFlatHashMap(size_t capacity)
Creates an empty map with at least capacity slots.
Definition: RADDataStructures.h:1123
size_t size() const noexcept
Returns number of occupied entries.
Definition: RADDataStructures.h:1245
const V * find(const K &key) const
Returns const pointer to mapped value for key, or nullptr when absent.
Definition: RADDataStructures.h:1272
V & operator[](const K &key)
Returns mapped value for key, inserting a default value if absent.
Definition: RADDataStructures.h:1300
iterator begin() noexcept
Returns iterator to first occupied entry.
Definition: RADDataStructures.h:1234
const_iterator end() const noexcept
Returns const iterator one past the entry table.
Definition: RADDataStructures.h:1240
bool empty() const noexcept
Returns true when the map contains no entries.
Definition: RADDataStructures.h:1243
std::pair< K, V > value_type
Stored key/value pair type.
Definition: RADDataStructures.h:1101
bool erase(const K &key)
Erases key and returns true when an entry was removed.
Definition: RADDataStructures.h:1305
void reserve(size_t desired)
Reserves enough capacity for desired entries.
Definition: RADDataStructures.h:1316
V * find(const K &key)
Returns pointer to mapped value for key, or nullptr when absent.
Definition: RADDataStructures.h:1266
bool contains(const K &key) const
Returns true when key exists.
Definition: RADDataStructures.h:1261
size_t capacity() const noexcept
Returns current hash table capacity.
Definition: RADDataStructures.h:1247
RADFlatHashMap(RADFlatHashMap &&other) noexcept
Moves another map without rehashing.
Definition: RADDataStructures.h:1148
RADFlatHashMap & operator=(RADFlatHashMap &&other) noexcept
Replaces this map by taking other's storage.
Definition: RADDataStructures.h:1164
void clear() noexcept
Removes all entries while keeping table storage.
Definition: RADDataStructures.h:1250
RADFlatHashMap & operator=(const RADFlatHashMap &other)
Replaces this map with a copy of other.
Definition: RADDataStructures.h:1134
Flat hash set implemented on top of RADFlatHashMap.
Definition: RADDataStructures.h:1387
bool erase(const K &key)
Removes key and returns true when it existed.
Definition: RADDataStructures.h:1402
size_t size() const noexcept
Returns number of stored keys.
Definition: RADDataStructures.h:1392
bool insert(const K &key)
Inserts key and returns true when newly inserted.
Definition: RADDataStructures.h:1400
bool contains(const K &key) const
Returns true when key exists.
Definition: RADDataStructures.h:1398
void reserve(size_t desired)
Reserves capacity for desired keys.
Definition: RADDataStructures.h:1396
void clear() noexcept
Removes all keys.
Definition: RADDataStructures.h:1394
bool empty() const noexcept
Returns true when the set contains no keys.
Definition: RADDataStructures.h:1390
Const forward iterator.
Definition: RADDataStructures.h:1486
const T * operator->() const
Returns current element pointer.
Definition: RADDataStructures.h:1493
const T & operator*() const
Returns current element.
Definition: RADDataStructures.h:1491
const_iterator(const Node *node)
Creates a const iterator from an internal node.
Definition: RADDataStructures.h:1489
const_iterator & operator++()
Advances to next node.
Definition: RADDataStructures.h:1495
bool operator!=(const const_iterator &other) const
Compares iterator inequality.
Definition: RADDataStructures.h:1497
Mutable bidirectional iterator.
Definition: RADDataStructures.h:1463
bool operator!=(const iterator &other) const
Compares iterator inequality.
Definition: RADDataStructures.h:1476
iterator & operator--()
Moves to previous node.
Definition: RADDataStructures.h:1474
iterator(Node *node)
Creates an iterator from an internal node.
Definition: RADDataStructures.h:1466
bool operator==(const iterator &other) const
Compares iterator equality.
Definition: RADDataStructures.h:1478
T & operator*() const
Returns current element.
Definition: RADDataStructures.h:1468
iterator & operator++()
Advances to next node.
Definition: RADDataStructures.h:1472
T * operator->() const
Returns current element pointer.
Definition: RADDataStructures.h:1470
Stable-node doubly linked list for cases where node stability matters.
Definition: RADDataStructures.h:1411
T & back() noexcept
Returns last element.
Definition: RADDataStructures.h:1520
void push_back(const T &value)
Appends a copy at the back.
Definition: RADDataStructures.h:1549
RADList()=default
Creates an empty list.
const T & back() const noexcept
Returns last element.
Definition: RADDataStructures.h:1522
const_iterator end() const noexcept
Returns const end iterator.
Definition: RADDataStructures.h:1510
RADList & operator=(const RADList &other)
Replaces this list with a copy of other.
Definition: RADDataStructures.h:1429
iterator end() noexcept
Returns end iterator.
Definition: RADDataStructures.h:1506
void pop_back()
Removes the last node.
Definition: RADDataStructures.h:1569
void clear() noexcept
Removes all nodes.
Definition: RADDataStructures.h:1594
T & emplace_front(Args &&... args)
Constructs an element at the front and returns it.
Definition: RADDataStructures.h:1538
const T & front() const noexcept
Returns first element.
Definition: RADDataStructures.h:1518
RADList & operator=(RADList &&other) noexcept
Replaces this list by taking other's node chain.
Definition: RADDataStructures.h:1445
RADList(const RADList &other)
Copies another list.
Definition: RADDataStructures.h:1424
const_iterator begin() const noexcept
Returns const iterator to first node.
Definition: RADDataStructures.h:1508
T & emplace_back(Args &&... args)
Constructs an element at the back and returns it.
Definition: RADDataStructures.h:1526
iterator begin() noexcept
Returns iterator to first node.
Definition: RADDataStructures.h:1504
void push_front(const T &value)
Prepends a copy at the front.
Definition: RADDataStructures.h:1553
size_t size() const noexcept
Returns number of nodes.
Definition: RADDataStructures.h:1514
void push_back(T &&value)
Appends a moved value at the back.
Definition: RADDataStructures.h:1551
void push_front(T &&value)
Prepends a moved value at the front.
Definition: RADDataStructures.h:1555
RADList(RADList &&other) noexcept
Moves another list by taking its node chain.
Definition: RADDataStructures.h:1437
RADList(std::initializer_list< T > values)
Creates a list from initializer-list values.
Definition: RADDataStructures.h:1419
T & front() noexcept
Returns first element.
Definition: RADDataStructures.h:1516
bool empty() const noexcept
Returns true when no nodes are present.
Definition: RADDataStructures.h:1512
void pop_front()
Removes the first node.
Definition: RADDataStructures.h:1558
iterator erase(iterator it)
Erases the node at it and returns the following iterator.
Definition: RADDataStructures.h:1580
~RADList()
Destroys all nodes.
Definition: RADDataStructures.h:1458
Standard-compatible allocator backed by RADMonotonicArena.
Definition: RADDataStructures.h:193
RADMonotonicArena * arena() const
Returns backing arena.
Definition: RADDataStructures.h:221
RADMonotonicAllocator(const RADMonotonicAllocator< U > &other)
Converts from another monotonic allocator type.
Definition: RADDataStructures.h:209
RADMonotonicAllocator()=default
Creates an allocator without an arena; allocations use std::allocator.
RADMonotonicAllocator(RADMonotonicArena *arena)
Creates an allocator using arena.
Definition: RADDataStructures.h:206
void deallocate(T *ptr, size_t n)
No-op for arena allocations; std fallback deallocates normally.
Definition: RADDataStructures.h:217
T value_type
Definition: RADDataStructures.h:195
T * allocate(size_t n)
Allocates n objects.
Definition: RADDataStructures.h:212
Simple monotonic arena for short-lived allocations.
Definition: RADDataStructures.h:124
size_t capacity() const
Returns backing capacity.
Definition: RADDataStructures.h:143
size_t used() const
Returns allocated bytes in the current generation.
Definition: RADDataStructures.h:141
RADMonotonicArena(size_t capacity=65536)
Creates an arena with initial capacity bytes.
Definition: RADDataStructures.h:127
void * allocate(size_t size, size_t alignment=alignof(std::max_align_t))
Allocates size bytes with alignment.
Definition: RADDataStructures.h:129
void reset()
Resets all allocations without releasing storage.
Definition: RADDataStructures.h:139
FIFO queue adapter backed by RADRingBuffer.
Definition: RADDataStructures.h:961
void push(const T &value)
Pushes a copy at the back.
Definition: RADDataStructures.h:974
void push(T &&value)
Pushes a moved value at the back.
Definition: RADDataStructures.h:976
T & emplace(Args &&... args)
Constructs an element at the back.
Definition: RADDataStructures.h:978
void clear()
Removes all queued elements.
Definition: RADDataStructures.h:984
const T & front() const noexcept
Returns the front element.
Definition: RADDataStructures.h:972
T & front() noexcept
Returns the front element.
Definition: RADDataStructures.h:970
void pop()
Removes the front element.
Definition: RADDataStructures.h:982
size_t size() const noexcept
Returns number of queued elements.
Definition: RADDataStructures.h:968
RADQueue(size_t capacity=16)
Creates a queue with initial ring capacity.
Definition: RADDataStructures.h:964
bool empty() const noexcept
Returns true when the queue is empty.
Definition: RADDataStructures.h:966
Const forward iterator over logical ring order.
Definition: RADDataStructures.h:815
T value_type
Definition: RADDataStructures.h:818
const T * pointer
Definition: RADDataStructures.h:820
bool operator!=(const const_iterator &other) const
Definition: RADDataStructures.h:826
const T & operator*() const
Definition: RADDataStructures.h:824
const_iterator(const RADRingBuffer *owner, size_t offset)
Definition: RADDataStructures.h:823
std::forward_iterator_tag iterator_category
Definition: RADDataStructures.h:817
const T & reference
Definition: RADDataStructures.h:821
std::ptrdiff_t difference_type
Definition: RADDataStructures.h:819
const_iterator & operator++()
Definition: RADDataStructures.h:825
Forward iterator over logical ring order.
Definition: RADDataStructures.h:796
iterator(RADRingBuffer *owner, size_t offset)
Definition: RADDataStructures.h:804
std::ptrdiff_t difference_type
Definition: RADDataStructures.h:800
T & reference
Definition: RADDataStructures.h:802
T * pointer
Definition: RADDataStructures.h:801
iterator & operator++()
Definition: RADDataStructures.h:806
std::forward_iterator_tag iterator_category
Definition: RADDataStructures.h:798
T value_type
Definition: RADDataStructures.h:799
bool operator!=(const iterator &other) const
Definition: RADDataStructures.h:807
T & operator*() const
Definition: RADDataStructures.h:805
Power-of-two circular buffer with push/pop at both ends.
Definition: RADDataStructures.h:733
void push_back(const T &value)
Appends a copy at the back.
Definition: RADDataStructures.h:913
iterator begin() noexcept
Returns iterator to the logical first element.
Definition: RADDataStructures.h:834
void pop_front()
Removes the logical first element.
Definition: RADDataStructures.h:922
const T & operator[](size_t index) const noexcept
Returns const logical element index without bounds checking.
Definition: RADDataStructures.h:852
size_t capacity() const noexcept
Returns allocated ring capacity.
Definition: RADDataStructures.h:847
T & back() noexcept
Returns last logical element.
Definition: RADDataStructures.h:858
RADRingBuffer(size_t capacity=16)
Creates a ring buffer with at least capacity slots.
Definition: RADDataStructures.h:736
T & operator[](size_t index) noexcept
Returns logical element index without bounds checking.
Definition: RADDataStructures.h:850
RADRingBuffer(RADRingBuffer &&other) noexcept
Moves another ring buffer without moving individual elements.
Definition: RADDataStructures.h:762
void push_back(T &&value)
Appends a moved value at the back.
Definition: RADDataStructures.h:915
~RADRingBuffer()
Destroys elements and releases storage.
Definition: RADDataStructures.h:741
void push_front(const T &value)
Prepends a copy at the front.
Definition: RADDataStructures.h:917
bool empty() const noexcept
Returns true when no elements are stored.
Definition: RADDataStructures.h:843
T & front() noexcept
Returns first logical element.
Definition: RADDataStructures.h:854
void push_front(T &&value)
Prepends a moved value at the front.
Definition: RADDataStructures.h:919
const_iterator begin() const noexcept
Returns const iterator to the logical first element.
Definition: RADDataStructures.h:838
const T & back() const noexcept
Returns last logical element.
Definition: RADDataStructures.h:860
void pop_back()
Removes the logical last element.
Definition: RADDataStructures.h:930
RADRingBuffer & operator=(RADRingBuffer &&other) noexcept
Replaces this buffer by taking other's storage.
Definition: RADDataStructures.h:777
T & emplace_front(Args &&... args)
Constructs an element at the logical front.
Definition: RADDataStructures.h:903
void clear() noexcept
Destroys all elements while keeping storage.
Definition: RADDataStructures.h:938
RADRingBuffer(const RADRingBuffer &other)
Copies another ring buffer in logical order.
Definition: RADDataStructures.h:747
const T & front() const noexcept
Returns first logical element.
Definition: RADDataStructures.h:856
RADRingBuffer & operator=(const RADRingBuffer &other)
Replaces this buffer with a copy of other.
Definition: RADDataStructures.h:753
const_iterator end() const noexcept
Returns const iterator one past the logical last element.
Definition: RADDataStructures.h:840
void reserve(size_t requestedCapacity)
Ensures capacity is at least requestedCapacity.
Definition: RADDataStructures.h:863
size_t size() const noexcept
Returns number of stored elements.
Definition: RADDataStructures.h:845
T & emplace_back(Args &&... args)
Constructs an element at the logical back.
Definition: RADDataStructures.h:892
iterator end() noexcept
Returns iterator one past the logical last element.
Definition: RADDataStructures.h:836
Vector with InlineN elements of inline storage before heap allocation.
Definition: RADDataStructures.h:541
void push_back(T &&value)
Appends value by move.
Definition: RADDataStructures.h:665
const T * data() const noexcept
Returns const contiguous storage pointer.
Definition: RADDataStructures.h:636
RADSmallVector()
Creates an empty small vector using inline storage.
Definition: RADDataStructures.h:549
RADSmallVector(const RADSmallVector &other)
Copies another small vector.
Definition: RADDataStructures.h:560
size_t size() const noexcept
Returns number of elements.
Definition: RADDataStructures.h:628
iterator end() noexcept
Returns iterator one past the last element.
Definition: RADDataStructures.h:622
void pop_back()
Removes the last element when present.
Definition: RADDataStructures.h:668
size_t capacity() const noexcept
Returns current capacity, including inline capacity.
Definition: RADDataStructures.h:630
const T & operator[](size_t index) const noexcept
Returns const element at index without bounds checking.
Definition: RADDataStructures.h:640
void push_back(const T &value)
Appends a copy of value.
Definition: RADDataStructures.h:663
bool usingInlineStorage() const noexcept
Returns true while storage is still inline.
Definition: RADDataStructures.h:632
RADSmallVector(std::initializer_list< T > values)
Creates a small vector from initializer-list values.
Definition: RADDataStructures.h:553
RADSmallVector & operator=(RADSmallVector &&other) noexcept
Replaces this vector by moving from other.
Definition: RADDataStructures.h:592
RADSmallVector & operator=(const RADSmallVector &other)
Replaces this vector with a copy of other.
Definition: RADDataStructures.h:583
T & emplace_back(Args &&... args)
Constructs an element at the end and returns it.
Definition: RADDataStructures.h:654
T & operator[](size_t index) noexcept
Returns element at index without bounds checking.
Definition: RADDataStructures.h:638
void clear() noexcept
Destroys all elements while keeping current storage.
Definition: RADDataStructures.h:674
const_iterator end() const noexcept
Returns const iterator one past the last element.
Definition: RADDataStructures.h:624
T * iterator
Mutable contiguous iterator.
Definition: RADDataStructures.h:544
const T * const_iterator
Const contiguous iterator.
Definition: RADDataStructures.h:546
~RADSmallVector()
Destroys elements and heap storage, if allocated.
Definition: RADDataStructures.h:613
T * data() noexcept
Returns mutable contiguous storage pointer.
Definition: RADDataStructures.h:634
bool empty() const noexcept
Returns true when no elements are stored.
Definition: RADDataStructures.h:626
T & back() noexcept
Returns last element; vector must not be empty.
Definition: RADDataStructures.h:642
const T & back() const noexcept
Returns last element; vector must not be empty.
Definition: RADDataStructures.h:644
const_iterator begin() const noexcept
Returns const iterator to first element.
Definition: RADDataStructures.h:620
void reserve(size_t newCapacity)
Ensures capacity is at least newCapacity.
Definition: RADDataStructures.h:647
RADSmallVector(RADSmallVector &&other) noexcept
Moves another small vector.
Definition: RADDataStructures.h:567
iterator begin() noexcept
Returns iterator to first element.
Definition: RADDataStructures.h:618
Lock-free single-producer/single-consumer bounded queue.
Definition: RADDataStructures.h:1021
size_t capacity() const noexcept
Returns usable queue capacity.
Definition: RADDataStructures.h:1049
bool try_pop(T &out)
Attempts to pop into out; returns false when empty.
Definition: RADDataStructures.h:1073
RADSpscQueue(size_t capacity)
Creates a queue with usable capacity rounded to a power of two.
Definition: RADDataStructures.h:1024
RADSpscQueue(const RADSpscQueue &)=delete
SPSC queues own atomic storage and cannot be copied.
bool emplace(Args &&... args)
Attempts to construct an item in-place; returns false when full.
Definition: RADDataStructures.h:1063
bool empty() const noexcept
Returns true when no item is available.
Definition: RADDataStructures.h:1044
RADSpscQueue & operator=(const RADSpscQueue &)=delete
SPSC queues own atomic storage and cannot be copied.
~RADSpscQueue()
Destroys any elements still queued.
Definition: RADDataStructures.h:1030
bool try_push(const T &value)
Attempts to push a copy; returns false when full.
Definition: RADDataStructures.h:1052
bool try_push(T &&value)
Attempts to push a moved value; returns false when full.
Definition: RADDataStructures.h:1057
LIFO stack adapter backed by RADVector.
Definition: RADDataStructures.h:992
const T & top() const noexcept
Returns the top element.
Definition: RADDataStructures.h:1001
size_t size() const noexcept
Returns number of stacked elements.
Definition: RADDataStructures.h:997
T & top() noexcept
Returns the top element.
Definition: RADDataStructures.h:999
void push(const T &value)
Pushes a copy onto the stack.
Definition: RADDataStructures.h:1003
bool empty() const noexcept
Returns true when the stack is empty.
Definition: RADDataStructures.h:995
void push(T &&value)
Pushes a moved value onto the stack.
Definition: RADDataStructures.h:1005
void clear()
Removes all elements.
Definition: RADDataStructures.h:1013
T & emplace(Args &&... args)
Constructs an element on top of the stack.
Definition: RADDataStructures.h:1007
void pop()
Removes the top element.
Definition: RADDataStructures.h:1011
Contiguous dynamic array optimized for RADLib hot paths.
Definition: RADDataStructures.h:279
T & emplace_back(Args &&... args)
Constructs an element at the end and returns it.
Definition: RADDataStructures.h:453
const_iterator cbegin() const noexcept
Returns const iterator to first element.
Definition: RADDataStructures.h:364
const T & at(size_t index) const
Returns const element at index or throws std::out_of_range.
Definition: RADDataStructures.h:395
size_t size_type
Unsigned size type.
Definition: RADDataStructures.h:286
const_iterator cend() const noexcept
Returns const iterator one past the last element.
Definition: RADDataStructures.h:370
const T & const_reference
Const reference type.
Definition: RADDataStructures.h:290
iterator end() noexcept
Returns iterator one past the last element.
Definition: RADDataStructures.h:366
RADVector & operator=(const RADVector &other)
Replaces this vector with a copy of other.
Definition: RADDataStructures.h:332
size_t size() const noexcept
Returns the number of constructed elements.
Definition: RADDataStructures.h:375
const T & front() const noexcept
Returns first element; vector must not be empty.
Definition: RADDataStructures.h:403
RADVector()=default
Creates an empty vector.
void clear() noexcept
Destroys all elements while keeping capacity.
Definition: RADDataStructures.h:484
const T & operator[](size_t index) const noexcept
Returns const element at index without bounds checking.
Definition: RADDataStructures.h:386
void resize(size_t newSize, const T &value)
Resizes with copies of value for new elements.
Definition: RADDataStructures.h:439
RADVector(RADVector &&other) noexcept
Moves another vector without moving individual elements when possible.
Definition: RADDataStructures.h:321
const T & back() const noexcept
Returns last element; vector must not be empty.
Definition: RADDataStructures.h:407
void push_back(T &&value)
Appends value by move.
Definition: RADDataStructures.h:463
const_iterator begin() const noexcept
Returns const iterator to first element.
Definition: RADDataStructures.h:362
void reserve(size_t newCapacity)
Ensures capacity is at least newCapacity.
Definition: RADDataStructures.h:410
RADVector(size_t count, const T &value=T())
Creates count copies of value.
Definition: RADDataStructures.h:304
iterator erase(const_iterator position)
Removes the element at position and returns the next iterator.
Definition: RADDataStructures.h:473
T & reference
Mutable reference type.
Definition: RADDataStructures.h:288
RADVector(std::initializer_list< T > values)
Creates a vector from initializer-list values.
Definition: RADDataStructures.h:309
T * data() noexcept
Returns mutable contiguous storage pointer.
Definition: RADDataStructures.h:379
void push_back(const T &value)
Appends a copy of value.
Definition: RADDataStructures.h:461
size_t capacity() const noexcept
Returns allocated element capacity.
Definition: RADDataStructures.h:377
T * pointer
Mutable pointer type.
Definition: RADDataStructures.h:292
void shrink_to_fit()
Releases unused capacity when possible.
Definition: RADDataStructures.h:416
const T * data() const noexcept
Returns const contiguous storage pointer.
Definition: RADDataStructures.h:381
void resize(size_t newSize)
Resizes with value-initialized new elements.
Definition: RADDataStructures.h:426
Alloc allocator_type
Allocator type.
Definition: RADDataStructures.h:284
bool empty() const noexcept
Returns true when the vector contains no elements.
Definition: RADDataStructures.h:373
T & at(size_t index)
Returns element at index or throws std::out_of_range.
Definition: RADDataStructures.h:389
void pop_back()
Removes the last element when present.
Definition: RADDataStructures.h:466
RADVector & operator=(RADVector &&other) noexcept
Replaces this vector by taking other's storage.
Definition: RADDataStructures.h:341
const T * const_iterator
Const contiguous iterator.
Definition: RADDataStructures.h:298
T & front() noexcept
Returns first element; vector must not be empty.
Definition: RADDataStructures.h:401
T & operator[](size_t index) noexcept
Returns element at index without bounds checking.
Definition: RADDataStructures.h:384
T * iterator
Mutable contiguous iterator.
Definition: RADDataStructures.h:296
T value_type
Stored value type.
Definition: RADDataStructures.h:282
RADVector(const RADVector &other)
Copies another vector.
Definition: RADDataStructures.h:315
~RADVector()
Destroys all elements and releases owned storage.
Definition: RADDataStructures.h:355
iterator begin() noexcept
Returns iterator to first element.
Definition: RADDataStructures.h:360
T & back() noexcept
Returns last element; vector must not be empty.
Definition: RADDataStructures.h:405
const_iterator end() const noexcept
Returns const iterator one past the last element.
Definition: RADDataStructures.h:368
const T * const_pointer
Const pointer type.
Definition: RADDataStructures.h:294
constexpr size_t nextPowerOfTwo(size_t value)
Returns the next power-of-two capacity at least as large as value.
Definition: RADDataStructures.h:33
Definition: RADDataStructures.h:28
bool operator!=(const RADMonotonicAllocator< T > &lhs, const RADMonotonicAllocator< U > &rhs)
Compares monotonic allocators by backing arena.
Definition: RADDataStructures.h:237
RADArrayView< uint8_t > RADByteArrayView
Mutable byte view.
Definition: RADDataStructures.h:74
RADArrayView< const uint8_t > RADConstByteArrayView
Const byte view.
Definition: RADDataStructures.h:76
bool operator==(const RADMonotonicAllocator< T > &lhs, const RADMonotonicAllocator< U > &rhs)
Compares monotonic allocators by backing arena.
Definition: RADDataStructures.h:231
Rebinds the allocator to another value type.
Definition: RADDataStructures.h:249
Rebinds the allocator to another value type.
Definition: RADDataStructures.h:199