in folly/container/detail/F14Table.h [1784:1915]
void rehashImpl(
std::size_t origSize,
std::size_t origChunkCount,
std::size_t origCapacityScale,
std::size_t newChunkCount,
std::size_t newCapacityScale) {
auto origChunks = chunks_;
auto origCapacity = computeCapacity(origChunkCount, origCapacityScale);
auto origAllocSize = chunkAllocSize(origChunkCount, origCapacityScale);
auto newCapacity = computeCapacity(newChunkCount, newCapacityScale);
auto newAllocSize = chunkAllocSize(newChunkCount, newCapacityScale);
BytePtr rawAllocation;
auto undoState = this->beforeRehash(
origSize, origCapacity, newCapacity, newAllocSize, rawAllocation);
chunks_ = initializeChunks(rawAllocation, newChunkCount, newCapacityScale);
FOLLY_SAFE_DCHECK(
newChunkCount < std::numeric_limits<InternalSizeType>::max(), "");
chunkMask_ = static_cast<InternalSizeType>(newChunkCount - 1);
bool success = false;
SCOPE_EXIT {
// this SCOPE_EXIT reverts chunks_ and chunkMask_ if necessary
BytePtr finishedRawAllocation = nullptr;
std::size_t finishedAllocSize = 0;
if (LIKELY(success)) {
if (origCapacity > 0) {
finishedRawAllocation = std::pointer_traits<BytePtr>::pointer_to(
*static_cast<uint8_t*>(static_cast<void*>(&*origChunks)));
finishedAllocSize = origAllocSize;
}
} else {
finishedRawAllocation = rawAllocation;
finishedAllocSize = newAllocSize;
chunks_ = origChunks;
FOLLY_SAFE_DCHECK(
origChunkCount < std::numeric_limits<InternalSizeType>::max(), "");
chunkMask_ = static_cast<InternalSizeType>(origChunkCount - 1);
F14LinkCheck<getF14IntrinsicsMode()>::check();
}
this->afterRehash(
std::move(undoState),
success,
origSize,
origCapacity,
newCapacity,
finishedRawAllocation,
finishedAllocSize);
};
if (origSize == 0) {
// nothing to do
} else if (origChunkCount == 1 && newChunkCount == 1) {
// no mask, no chunk scan, no hash computation, no probing
auto srcChunk = origChunks;
auto dstChunk = chunks_;
std::size_t srcI = 0;
std::size_t dstI = 0;
while (dstI < origSize) {
if (LIKELY(srcChunk->occupied(srcI))) {
dstChunk->setTag(dstI, srcChunk->tag(srcI));
this->moveItemDuringRehash(
dstChunk->itemAddr(dstI), srcChunk->item(srcI));
++dstI;
}
++srcI;
}
if (kEnableItemIteration) {
sizeAndPackedBegin_.packedBegin() = ItemIter{dstChunk, dstI - 1}.pack();
}
} else {
// 1 byte per chunk means < 1 bit per value temporary overhead
std::array<uint8_t, 256> stackBuf;
uint8_t* fullness;
if (newChunkCount <= stackBuf.size()) {
fullness = stackBuf.data();
} else {
ByteAlloc a{this->alloc()};
// may throw
fullness =
&*std::allocator_traits<ByteAlloc>::allocate(a, newChunkCount);
}
std::memset(fullness, '\0', newChunkCount);
SCOPE_EXIT {
if (newChunkCount > stackBuf.size()) {
ByteAlloc a{this->alloc()};
std::allocator_traits<ByteAlloc>::deallocate(
a,
std::pointer_traits<typename std::allocator_traits<
ByteAlloc>::pointer>::pointer_to(*fullness),
newChunkCount);
}
};
auto srcChunk = origChunks + origChunkCount - 1;
std::size_t remaining = origSize;
while (remaining > 0) {
auto iter = srcChunk->occupiedIter();
if (prefetchBeforeRehash()) {
for (auto piter = iter; piter.hasNext();) {
this->prefetchValue(srcChunk->item(piter.next()));
}
}
while (iter.hasNext()) {
--remaining;
auto srcI = iter.next();
Item& srcItem = srcChunk->item(srcI);
auto hp = splitHash(
this->computeItemHash(const_cast<Item const&>(srcItem)));
FOLLY_SAFE_CHECK(hp.second == srcChunk->tag(srcI), "");
auto dstIter = allocateTag(fullness, hp);
this->moveItemDuringRehash(dstIter.itemAddr(), srcItem);
}
--srcChunk;
}
if (kEnableItemIteration) {
// this code replaces size invocations of adjustSizeAndBeginAfterInsert
std::size_t i = chunkMask_;
while (fullness[i] == 0) {
--i;
}
sizeAndPackedBegin_.packedBegin() =
ItemIter{chunks_ + i, std::size_t{fullness[i]} - 1}.pack();
}
}
success = true;
}