| 2354 | |
| 2355 | |
| 2356 | bool new_block_index(size_t numberOfFilledSlotsToExpose) |
| 2357 | { |
| 2358 | auto prevBlockSizeMask = pr_blockIndexSize - 1; |
| 2359 | |
| 2360 | // Create the new block |
| 2361 | pr_blockIndexSize <<= 1; |
| 2362 | auto newRawPtr = static_cast<char*>((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); |
| 2363 | if (newRawPtr == nullptr) { |
| 2364 | pr_blockIndexSize >>= 1; // Reset to allow graceful retry |
| 2365 | return false; |
| 2366 | } |
| 2367 | |
| 2368 | auto newBlockIndexEntries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(newRawPtr + sizeof(BlockIndexHeader))); |
| 2369 | |
| 2370 | // Copy in all the old indices, if any |
| 2371 | size_t j = 0; |
| 2372 | if (pr_blockIndexSlotsUsed != 0) { |
| 2373 | auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; |
| 2374 | do { |
| 2375 | newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; |
| 2376 | i = (i + 1) & prevBlockSizeMask; |
| 2377 | } while (i != pr_blockIndexFront); |
| 2378 | } |
| 2379 | |
| 2380 | // Update everything |
| 2381 | auto header = new (newRawPtr) BlockIndexHeader; |
| 2382 | header->size = pr_blockIndexSize; |
| 2383 | header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); |
| 2384 | header->entries = newBlockIndexEntries; |
| 2385 | header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later |
| 2386 | |
| 2387 | pr_blockIndexFront = j; |
| 2388 | pr_blockIndexEntries = newBlockIndexEntries; |
| 2389 | pr_blockIndexRaw = newRawPtr; |
| 2390 | blockIndex.store(header, std::memory_order_release); |
| 2391 | |
| 2392 | return true; |
| 2393 | } |
| 2394 | |
| 2395 | private: |
| 2396 | std::atomic<BlockIndexHeader*> blockIndex; |
no test coverage detected