Foundation
Loading...
Searching...
No Matches
AtomicPool.hpp
Go to the documentation of this file.
1#pragma once
2#include <cstring>
3#include "Allocator.hpp"
4#include "Atomic.hpp"
5namespace Foundation::Core
6{
16 template <typename T>
18 {
19 struct Node;
20 struct alignas(2 * sizeof(Node*)) PTag
21 {
22 Node* p{nullptr};
24 };
25 struct alignas(2 * sizeof(Node*)) Node
26 {
30
31 };
32 Node* mNodes{nullptr};
33 size_t mSize{0};
36
38 {
39 PTag old_head = mHead.load(std::memory_order_relaxed);
40 while (true)
41 {
42 if (!old_head.p)
43 return nullptr;
44 // ABA mitigation as seen in AtomicStack
45 PTag new_head = {old_head.p->next, old_head.tag + 1};
46 if (mHead.compare_exchange_weak(old_head, new_head, std::memory_order_acquire,
47 std::memory_order_relaxed))
48 {
49 return old_head.p;
50 }
51 }
52 }
53
55 {
56 PTag old_head = mHead.load(std::memory_order_relaxed);
57 while (true)
58 {
59 node->next = old_head.p;
61 if (mHead.compare_exchange_weak(old_head, new_head, std::memory_order_acquire,
62 std::memory_order_relaxed))
63 {
64 return;
65 }
66 }
67 }
68
69 public:
70 AtomicPool() = default;
71 AtomicPool(size_t size, Allocator* alloc) : mSize(size), mArena(alloc, size * sizeof(Node))
72 {
73 std::memset(mArena.arena.memory, 0, mArena.arena.size);
74 mNodes = static_cast<Node*>(mArena.arena.memory);
75 for (size_t i = 0; i + 1 < mSize; i++)
76 mNodes[i].next = &mNodes[i + 1];
77 mNodes[mSize - 1].next = nullptr;
78 mHead.store({&mNodes[0], 0});
79 }
86 template <typename... Args>
88 {
90 if (!node)
91 return nullptr;
92 node->used = true;
93 std::construct_at(&node->data, std::forward<Args>(args)...);
94 return &node->data;
95 }
99 void Destruct(T* ptr)
100 {
101 if (!ptr)
102 return;
103 // We know the memory layout is Node.data, so we can get the Node* from T*
104 // Hacky - though guaranteed to work by standard layout.
105 Node* node = reinterpret_cast<Node*>(reinterpret_cast<uintptr_t>(ptr) - offsetof(Node, data));
106 node->used = false;
107 node->data.~T();
109 }
114 size_t Index(T* ptr) const
115 {
116 Node* node = reinterpret_cast<Node*>(reinterpret_cast<uintptr_t>(ptr) - offsetof(Node, data));
117 return static_cast<size_t>(node - mNodes);
118 }
123 T* At(size_t index)
124 {
125 if (index >= mSize)
126 return nullptr;
127 return &mNodes[index].data;
128 }
132 void Collect()
133 {
134 for (size_t i = 0; i < mSize; i++)
135 if (mNodes[i].used)
136 mNodes[i].used = false, mNodes[i].data.~T();
137 }
139 };
140} // namespace Foundation::Core
General Purpose Allocator (GPA) interface.
Definition Allocator.hpp:24
Atomic, bounded object pool of fixed allocation sizes. Being a sibling to AtomicStack - key differenc...
Definition AtomicPool.hpp:18
Atomic< PTag > mHead
Definition AtomicPool.hpp:34
Node * mNodes
Definition AtomicPool.hpp:32
ScopedArena mArena
Definition AtomicPool.hpp:35
void Destruct(T *ptr)
Destructs the object pointed to by ptr and returns it to the pool.
Definition AtomicPool.hpp:99
~AtomicPool()
Definition AtomicPool.hpp:138
size_t mSize
Definition AtomicPool.hpp:33
T * At(size_t index)
Returns the pointer at the given index in the pool.
Definition AtomicPool.hpp:123
size_t Index(T *ptr) const
Returns the index of the given pointer in the pool.
Definition AtomicPool.hpp:114
T * Construct(Args &&... args)
Constructs an object of type T in the pool with the given arguments.
Definition AtomicPool.hpp:87
void Collect()
Destruct all allocated objects in the pool, collecting garbage.
Definition AtomicPool.hpp:132
AtomicPool(size_t size, Allocator *alloc)
Definition AtomicPool.hpp:71
void DeallocateNode(Node *node)
Definition AtomicPool.hpp:54
Node * AllocateNode()
Definition AtomicPool.hpp:37
Lock-free atomic primitives and implementations of data structures.
Definition Allocator.hpp:5
std::atomic< T > Atomic
Alias of std::atomic<T>.
Definition Atomic.hpp:26
size_type size
Definition Allocator.hpp:19
pointer memory
Definition Allocator.hpp:18
Definition AtomicPool.hpp:26
uintptr_t used
Definition AtomicPool.hpp:28
Node * next
Definition AtomicPool.hpp:27
T data
Definition AtomicPool.hpp:29
Definition AtomicPool.hpp:21
Node * p
Definition AtomicPool.hpp:22
uintptr_t tag
Definition AtomicPool.hpp:23
RAII wrapper for an arena allocated from an Allocator.
Definition Allocator.hpp:44
Arena arena
Definition Allocator.hpp:46