| 2376 | |
| 2377 | |
| 2378 | bool new_block_index(size_t numberOfFilledSlotsToExpose) |
| 2379 | { |
| 2380 | auto prevBlockSizeMask = pr_blockIndexSize - 1; |
| 2381 | |
| 2382 | // Create the new block |
| 2383 | pr_blockIndexSize <<= 1; |
| 2384 | auto newRawPtr = static_cast<char*>((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); |
| 2385 | if (newRawPtr == nullptr) { |
| 2386 | pr_blockIndexSize >>= 1; // Reset to allow graceful retry |
| 2387 | return false; |
| 2388 | } |
| 2389 | |
| 2390 | auto newBlockIndexEntries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(newRawPtr + sizeof(BlockIndexHeader))); |
| 2391 | |
| 2392 | // Copy in all the old indices, if any |
| 2393 | size_t j = 0; |
| 2394 | if (pr_blockIndexSlotsUsed != 0) { |
| 2395 | auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; |
| 2396 | do { |
| 2397 | newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; |
| 2398 | i = (i + 1) & prevBlockSizeMask; |
| 2399 | } while (i != pr_blockIndexFront); |
| 2400 | } |
| 2401 | |
| 2402 | // Update everything |
| 2403 | auto header = new (newRawPtr) BlockIndexHeader; |
| 2404 | header->size = pr_blockIndexSize; |
| 2405 | header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); |
| 2406 | header->entries = newBlockIndexEntries; |
| 2407 | header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later |
| 2408 | |
| 2409 | pr_blockIndexFront = j; |
| 2410 | pr_blockIndexEntries = newBlockIndexEntries; |
| 2411 | pr_blockIndexRaw = newRawPtr; |
| 2412 | blockIndex.store(header, std::memory_order_release); |
| 2413 | |
| 2414 | return true; |
| 2415 | } |
| 2416 | |
| 2417 | private: |
| 2418 | std::atomic<BlockIndexHeader*> blockIndex; |
no test coverage detected