@@ -167,7 +167,7 @@ class CNodePool : public core::IReferenceCounted
167
167
const uint32_t size = T::calc_size (args...);
168
168
const Handle retval = alloc (size,alignof (T));
169
169
if (retval)
170
- new (deref<T>(retval)) T ( std::forward<Args>(args)...);
170
+ std::construct_at<T> (deref<T>(retval), std::forward<Args>(args)...);
171
171
return retval;
172
172
}
173
173
// delete
@@ -176,25 +176,12 @@ class CNodePool : public core::IReferenceCounted
176
176
{
177
177
T* ptr = deref<T>(h);
178
178
const uint32_t size = ptr->getSize ();
179
- ptr->~T ();
179
+ std::destroy_at<T>(ptr);
180
+ // wipe v-table to mark as dead (so `~CNodePool` doesn't run destructor twice)
181
+ memset (static_cast <INode*>(ptr),0 ,sizeof (INode));
180
182
free (h,size);
181
183
}
182
184
183
- // for now using KISS, we can use geeneralpupose allocator later
184
- struct Chunk
185
- {
186
- inline Handle::value_t alloc (const uint32_t size, const uint16_t alignment)
187
- {
188
- return m_alloc.alloc_addr (size,alignment);
189
- }
190
- inline void free (const Handle::value_t addr, const uint32_t size)
191
- {
192
- m_alloc.free_addr (addr,size);
193
- }
194
-
195
- core::LinearAddressAllocatorST<Handle::value_t > m_alloc;
196
- uint8_t * m_data;
197
- };
198
185
inline CNodePool (const uint8_t _chunkSizeLog2, const uint8_t _maxNodeAlignLog2, refctd_pmr_t && _pmr) :
199
186
m_chunkSizeLog2(_chunkSizeLog2), m_maxNodeAlignLog2(_maxNodeAlignLog2), m_pmr(_pmr ? std::move(_pmr):core::getDefaultMemoryResource())
200
187
{
@@ -206,19 +193,65 @@ class CNodePool : public core::IReferenceCounted
206
193
const auto chunkAlign = 0x1u <<m_maxNodeAlignLog2;
207
194
for (auto & chunk : m_chunks)
208
195
{
209
- // TODO: destroy nodes allocated from chunk
196
+ for (auto handleOff=chunk.m_alloc .get_total_size (); handleOff<chunkSize; handleOff+=sizeof (Handle))
197
+ {
198
+ const auto pHandle = reinterpret_cast <const Handle*>(chunk.m_data +handleOff);
199
+ if (auto * node=deref<INode>({.value =*pHandle}); node)
200
+ std::destroy_at (node);
201
+ }
210
202
m_pmr->deallocate (chunk.m_data ,chunkSize,chunkAlign);
211
203
}
212
204
}
213
205
214
206
private:
207
+ struct Chunk
208
+ {
209
+ inline Handle::value_t alloc (const uint32_t size, const uint16_t alignment)
210
+ {
211
+ const auto retval = m_alloc.alloc_addr (size,alignment);
212
+ // successful allocation, time for some book keeping
213
+ constexpr auto invalid_address = decltype (m_alloc)::invalid_address;
214
+ if (retval!=invalid_address)
215
+ {
216
+ // we keep a list of all the allocated nodes at the back of a chunk
217
+ const auto newSize = m_alloc.get_total_size ()-sizeof (retval);
218
+ // handle no space left for bookkeeping case
219
+ if (retval+size>newSize)
220
+ {
221
+ free (retval,size);
222
+ return invalid_address;
223
+ }
224
+ // clear vtable to mark as not initialized yet
225
+ memset (m_data+retval,0 ,sizeof (INode));
226
+ *reinterpret_cast <Handle::value_t *>(m_data+newSize) = retval;
227
+ // shrink allocator
228
+ m_alloc = decltype (m_alloc)(newSize,std::move (m_alloc));
229
+ }
230
+ return retval;
231
+ }
232
+ inline void free (const Handle::value_t addr, const uint32_t size)
233
+ {
234
+ m_alloc.free_addr (addr,size);
235
+ }
236
+
237
+ // for now using KISS, we can use geeneralpupose allocator later
238
+ core::LinearAddressAllocatorST<Handle::value_t > m_alloc;
239
+ uint8_t * m_data;
240
+ };
215
241
inline uint32_t getChunkIx (const Handle& h) {h.value >>m_chunkSizeLog2;}
216
242
217
243
template <typename T> requires (std::is_base_of_v<INode,T> && !std::is_const_v<T>)
218
244
inline T* deref(const Handle& h)
219
245
{
220
- const auto loAddr = h.value &(0x1u <<m_chunkSizeLog2);
221
- return reinterpret_cast <T*>(chunks[getChunkIx (h)].data ()+loAddr);
246
+ const auto hiAddr = getChunkIx (h);
247
+ assert (hiAddr<chunks.size ());
248
+ {
249
+ const auto loAddr = h.value &(0x1u <<m_chunkSizeLog2);
250
+ void * ptr = chunks[hiAddr].data ()+loAddr;
251
+ if (ptr) // vtable not wiped
252
+ return reinterpret_cast <T*>(ptr);
253
+ }
254
+ return nullptr ;
222
255
}
223
256
template <typename T> requires (std::is_base_of_v<INode,T> && std::is_const_v<T>)
224
257
inline T* deref(const Handle& h) const
@@ -228,7 +261,7 @@ class CNodePool : public core::IReferenceCounted
228
261
229
262
core::vector<Chunk> m_chunks;
230
263
refctd_pmr_t m_pmr;
231
- const uint8_t m_chunkSizeLog2;
264
+ const uint8_t m_chunkSizeLog2; // maybe hardcode chunk sizes to 64kb ?
232
265
const uint8_t m_maxNodeAlignLog2;
233
266
};
234
267
0 commit comments