90 static_assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) &&
"MAX_BLOCK_SIZE must be a power of 2");
91 static_assert(MAX_BLOCK_SIZE >= 2 &&
"MAX_BLOCK_SIZE must be at least 2");
93 Block* firstBlock =
nullptr;
95 largestBlockSize = ceilToPow2(
size + 1);
96 if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
102 size_t initialBlockCount = (
size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
103 largestBlockSize = MAX_BLOCK_SIZE;
104 Block* lastBlock =
nullptr;
105 for (
size_t i = 0; i != initialBlockCount; ++i) {
106 auto block = make_block(largestBlockSize);
107 if (block ==
nullptr) {
108 throw std::bad_alloc();
110 if (firstBlock ==
nullptr) {
114 lastBlock->next = block;
117 block->next = firstBlock;
121 firstBlock = make_block(largestBlockSize);
122 if (firstBlock ==
nullptr) {
123 throw std::bad_alloc();
125 firstBlock->next = firstBlock;
127 frontBlock = firstBlock;
128 tailBlock = firstBlock;
132 : frontBlock(other.frontBlock),
133 tailBlock(other.tailBlock),
134 largestBlockSize(other.largestBlockSize)
136 other.largestBlockSize = 32;
137 Block* b = other.make_block(other.largestBlockSize);
139 throw std::bad_alloc();
142 other.frontBlock = b;
148 Block* b = frontBlock;
149 frontBlock = other.frontBlock;
150 other.frontBlock = b;
152 tailBlock = other.tailBlock;
154 std::swap(largestBlockSize, other.largestBlockSize);
161 Block* frontBlock_ = frontBlock;
162 Block* block = frontBlock_;
164 Block* nextBlock = block->next;
165 size_t blockFront = block->front;
166 size_t blockTail = block->tail;
168 for (
size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
169 auto element =
reinterpret_cast<T*
>(block->data + i *
sizeof(T));
177 }
while (block != frontBlock_);
186 return inner_enqueue<CannotAlloc>(element);
194 return inner_enqueue<CannotAlloc>(std::forward<T>(element));
198 template<
typename... Args>
201 return inner_enqueue<CannotAlloc>(std::forward<Args>(args)...);
209 return inner_enqueue<CanAlloc>(element);
217 return inner_enqueue<CanAlloc>(std::forward<T>(element));
221 template<
typename... Args>
224 return inner_enqueue<CanAlloc>(std::forward<Args>(args)...);
240 Block* frontBlock_ = frontBlock;
241 size_t blockTail = frontBlock_->localTail;
242 size_t blockFront = frontBlock_->front;
244 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
246 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
247 result = std::move(*element);
250 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
252 frontBlock_->front = blockFront;
254 else if (frontBlock_ != tailBlock) {
255 frontBlock_ = frontBlock;
256 blockTail = frontBlock_->localTail = frontBlock_->tail;
257 blockFront = frontBlock_->front;
260 Block* nextBlock = frontBlock_->next;
261 size_t nextBlockFront = nextBlock->front;
262 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail;
266 assert(nextBlockFront != nextBlockTail);
267 (void) nextBlockTail;
270 frontBlock = frontBlock_ = nextBlock;
272 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
274 result = std::move(*element);
277 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
279 frontBlock_->front = nextBlockFront;
298 Block* frontBlock_ = frontBlock;
299 size_t blockTail = frontBlock_->localTail;
300 size_t blockFront = frontBlock_->front;
302 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
303 return reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
305 else if (frontBlock_ != tailBlock) {
306 frontBlock_ = frontBlock;
307 blockTail = frontBlock_->localTail = frontBlock_->tail;
308 blockFront = frontBlock_->front;
310 Block* nextBlock = frontBlock_->next;
312 size_t nextBlockFront = nextBlock->front;
314 assert(nextBlockFront != nextBlock->tail);
315 return reinterpret_cast<T*
>(nextBlock->data + nextBlockFront *
sizeof(T));
328 Block* frontBlock_ = frontBlock;
329 size_t blockTail = frontBlock_->localTail;
330 size_t blockFront = frontBlock_->front;
332 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail)) {
333 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
336 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
338 frontBlock_->front = blockFront;
340 else if (frontBlock_ != tailBlock) {
341 frontBlock_ = frontBlock;
342 blockTail = frontBlock_->localTail = frontBlock_->tail;
343 blockFront = frontBlock_->front;
346 Block* nextBlock = frontBlock_->next;
348 size_t nextBlockFront = nextBlock->front;
349 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail;
351 assert(nextBlockFront != nextBlockTail);
352 (void) nextBlockTail;
354 frontBlock = frontBlock_ = nextBlock;
356 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
359 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
361 frontBlock_->front = nextBlockFront;
380 Block* frontBlock_ = frontBlock;
381 Block* block = frontBlock_;
383 size_t blockFront = block->front;
384 size_t blockTail = block->tail;
385 result += (blockTail - blockFront) & block->sizeMask;
387 }
while (block != frontBlock_);
395 Block* frontBlock_ = frontBlock;
396 Block* block = frontBlock_;
398 result += block->sizeMask;
400 }
while (block != frontBlock_);
406 enum AllocationMode { CanAlloc, CannotAlloc };
408 template<AllocationMode canAlloc,
typename... Args>
409 bool inner_enqueue(Args&&... args)
418 Block* tailBlock_ = tailBlock;
419 size_t blockFront = tailBlock_->localFront;
420 size_t blockTail = tailBlock_->tail;
422 size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
423 if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front)) {
425 char* location = tailBlock_->data + blockTail *
sizeof(T);
426 new (location) T(std::forward<Args>(args)...);
428 tailBlock_->tail = nextBlockTail;
431 if (tailBlock_->next != frontBlock) {
438 Block* tailBlockNext = tailBlock_->next;
439 size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front;
440 nextBlockTail = tailBlockNext->tail;
444 assert(nextBlockFront == nextBlockTail);
445 tailBlockNext->localFront = nextBlockFront;
447 char* location = tailBlockNext->data + nextBlockTail *
sizeof(T);
448 new (location) T(std::forward<Args>(args)...);
450 tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
452 tailBlock = tailBlockNext;
454 else if constexpr (canAlloc == CanAlloc) {
456 auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
457 auto newBlock = make_block(newBlockSize);
458 if (newBlock ==
nullptr) {
462 largestBlockSize = newBlockSize;
464 new (newBlock->data) T(std::forward<Args>(args)...);
465 assert(newBlock->front == 0);
466 newBlock->tail = newBlock->localTail = 1;
468 newBlock->next = tailBlock_->next;
469 tailBlock_->next = newBlock;
471 tailBlock = newBlock;
473 else if constexpr (canAlloc == CannotAlloc) {
478 assert(
false &&
"Should be unreachable code");
492 static constexpr size_t ceilToPow2(
size_t x)
499 for (
size_t i = 1; i <
sizeof(size_t); i <<= 1) {
509 const std::size_t alignment = std::alignment_of<U>::value;
510 return ptr + (alignment - (
reinterpret_cast<std::uintptr_t
>(
ptr) % alignment)) % alignment;
527 const size_t sizeMask;
530 Block(
size_t _size,
char* _data)
531 : front(0UL), localTail(0), tail(0UL), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1)
537 static Block* make_block(
size_t capacity)
540 auto size =
sizeof(Block);
541 size +=
sizeof(T) * capacity + std::alignment_of<T>::value - 1;
542 auto newBlock =
static_cast<char*
>(std::malloc(
size));
543 if (newBlock ==
nullptr) {
547 auto newBlockData = align_for<T>(newBlock +
sizeof(Block));
548 return new (newBlock) Block(capacity, newBlockData);
554 size_t largestBlockSize;
you may not use this file except in compliance with the License You may obtain a copy of the License at software distributed under the License is distributed on an AS IS WITHOUT WARRANTIES OR CONDITIONS OF ANY either express or implied See the License for the specific language governing permissions and limitations under the License LLVM Exceptions to the Apache License As an if
Definition ThirdPartyNotices.txt:301