17 #if __cplusplus > 199711L || _MSC_VER >= 1700 // C++11 or VS2012
34 #ifndef MOODYCAMEL_CACHE_LINE_SIZE
35 #define MOODYCAMEL_CACHE_LINE_SIZE 64
38 #ifndef MOODYCAMEL_EXCEPTIONS_ENABLED
39 #if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || \
40 (!defined(_MSC_VER) && !defined(__GNUC__))
41 #define MOODYCAMEL_EXCEPTIONS_ENABLED
45 #ifndef MOODYCAMEL_HAS_EMPLACE
46 #if !defined(_MSC_VER) || _MSC_VER >= 1800 // variadic templates: either a non-MS compiler or VS >= 2013
47 #define MOODYCAMEL_HAS_EMPLACE 1
53 #pragma warning(disable : 4324) // structure was padded due to __declspec(align())
54 #pragma warning(disable : 4820) // padding was added
55 #pragma warning(disable : 4127) // conditional expression is constant
60 template <
typename T,
size_t MAX_BLOCK_SIZE = 512>
96 assert(MAX_BLOCK_SIZE ==
ceilToPow2(MAX_BLOCK_SIZE) &&
"MAX_BLOCK_SIZE must be a power of 2");
97 assert(MAX_BLOCK_SIZE >= 2 &&
"MAX_BLOCK_SIZE must be at least 2");
99 Block* firstBlock =
nullptr;
109 size_t initialBlockCount = (size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
111 Block* lastBlock =
nullptr;
112 for (
size_t i = 0; i != initialBlockCount; ++i)
115 if (block ==
nullptr)
117 #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
118 throw std::bad_alloc();
123 if (firstBlock ==
nullptr)
129 lastBlock->next = block;
132 block->next = firstBlock;
138 if (firstBlock ==
nullptr)
140 #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
141 throw std::bad_alloc();
146 firstBlock->next = firstBlock;
166 other.largestBlockSize = 32;
167 Block* b = other.make_block(other.largestBlockSize);
170 #ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
171 throw std::bad_alloc();
177 other.frontBlock = b;
187 other.frontBlock = b;
204 Block* block = frontBlock_;
207 Block* nextBlock = block->next;
208 size_t blockFront = block->front;
209 size_t blockTail = block->tail;
211 for (
size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask)
213 auto element =
reinterpret_cast<T*
>(block->data + i *
sizeof(T));
218 auto rawBlock = block->rawThis;
222 }
while (block != frontBlock_);
230 return inner_enqueue<CannotAlloc>(element);
238 return inner_enqueue<CannotAlloc>(std::forward<T>(element));
241 #if MOODYCAMEL_HAS_EMPLACE
243 template <
typename... Args>
246 return inner_enqueue<CannotAlloc>(std::forward<Args>(
args)...);
255 return inner_enqueue<CanAlloc>(element);
263 return inner_enqueue<CanAlloc>(std::forward<T>(element));
266 #if MOODYCAMEL_HAS_EMPLACE
268 template <
typename... Args>
271 return inner_enqueue<CanAlloc>(std::forward<Args>(
args)...);
278 template <
typename U>
303 size_t blockTail = frontBlock_->localTail;
304 size_t blockFront = frontBlock_->front.load();
306 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
310 non_empty_front_block:
312 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
313 result = std::move(*element);
316 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
319 frontBlock_->front = blockFront;
321 else if (frontBlock_ !=
tailBlock.load())
326 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
327 blockFront = frontBlock_->front.load();
330 if (blockFront != blockTail)
333 goto non_empty_front_block;
337 Block* nextBlock = frontBlock_->next;
342 size_t nextBlockFront = nextBlock->front.load();
343 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
348 assert(nextBlockFront != nextBlockTail);
357 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
359 result = std::move(*element);
362 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
365 frontBlock_->front = nextBlockFront;
389 size_t blockTail = frontBlock_->localTail;
390 size_t blockFront = frontBlock_->front.load();
392 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
395 non_empty_front_block:
396 return reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
398 else if (frontBlock_ !=
tailBlock.load())
402 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
403 blockFront = frontBlock_->front.load();
406 if (blockFront != blockTail)
408 goto non_empty_front_block;
411 Block* nextBlock = frontBlock_->next;
413 size_t nextBlockFront = nextBlock->front.load();
416 assert(nextBlockFront != nextBlock->tail.load());
417 return reinterpret_cast<T*
>(nextBlock->data + nextBlockFront *
sizeof(T));
434 size_t blockTail = frontBlock_->localTail;
435 size_t blockFront = frontBlock_->front.load();
437 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
441 non_empty_front_block:
442 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
445 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
448 frontBlock_->front = blockFront;
450 else if (frontBlock_ !=
tailBlock.load())
454 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
455 blockFront = frontBlock_->front.load();
458 if (blockFront != blockTail)
460 goto non_empty_front_block;
464 Block* nextBlock = frontBlock_->next;
466 size_t nextBlockFront = nextBlock->front.load();
467 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
470 assert(nextBlockFront != nextBlockTail);
478 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
481 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
484 frontBlock_->front = nextBlockFront;
501 Block* block = frontBlock_;
505 size_t blockFront = block->front.load();
506 size_t blockTail = block->tail.load();
507 result += (blockTail - blockFront) & block->sizeMask;
508 block = block->next.load();
509 }
while (block != frontBlock_);
526 Block* block = frontBlock_;
530 result += block->sizeMask;
531 block = block->next.load();
532 }
while (block != frontBlock_);
543 #if MOODYCAMEL_HAS_EMPLACE
547 template <AllocationMode canAlloc,
typename U>
563 size_t blockFront = tailBlock_->localFront;
564 size_t blockTail = tailBlock_->tail.load();
566 size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
567 if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load()))
571 char* location = tailBlock_->data + blockTail *
sizeof(T);
572 #if MOODYCAMEL_HAS_EMPLACE
573 new (location) T(std::forward<Args>(
args)...);
575 new (location) T(std::forward<U>(element));
579 tailBlock_->tail = nextBlockTail;
594 Block* tailBlockNext = tailBlock_->next.load();
595 size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load();
596 nextBlockTail = tailBlockNext->tail.load();
601 assert(nextBlockFront == nextBlockTail);
602 tailBlockNext->localFront = nextBlockFront;
604 char* location = tailBlockNext->data + nextBlockTail *
sizeof(T);
605 #if MOODYCAMEL_HAS_EMPLACE
606 new (location) T(std::forward<Args>(
args)...);
608 new (location) T(std::forward<U>(element));
611 tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
621 if (newBlock ==
nullptr)
628 #if MOODYCAMEL_HAS_EMPLACE
629 new (newBlock->data) T(std::forward<Args>(
args)...);
631 new (newBlock->data) T(std::forward<U>(element));
633 assert(newBlock->front == 0);
634 newBlock->tail = newBlock->localTail = 1;
636 newBlock->next = tailBlock_->next.load();
637 tailBlock_->next = newBlock;
655 assert(
false &&
"Should be unreachable code");
680 for (
size_t i = 1; i <
sizeof(size_t); i <<= 1)
688 template <
typename U>
691 const std::size_t alignment = std::alignment_of<U>::value;
692 return ptr + (alignment - (
reinterpret_cast<std::uintptr_t
>(ptr) % alignment)) % alignment;
701 assert(!
inSection &&
"Concurrent (or re-entrant) enqueue or dequeue operation detected (only one thread at a "
702 "time may hold the producer or consumer role)");
762 auto size =
sizeof(Block) + std::alignment_of<Block>::value - 1;
763 size +=
sizeof(T) * capacity + std::alignment_of<T>::value - 1;
764 auto newBlockRaw =
static_cast<char*
>(std::malloc(size));
765 if (newBlockRaw ==
nullptr)
770 auto newBlockAligned = align_for<Block>(newBlockRaw);
771 auto newBlockData = align_for<T>(newBlockAligned +
sizeof(Block));
772 return new (newBlockAligned) Block(capacity, newBlockRaw, newBlockData);
790 template <
typename T,
size_t MAX_BLOCK_SIZE = 512>
798 sema(new spsc_sema::LightweightSemaphore())
803 sema(std::move(other.sema))
809 std::swap(
sema, other.sema);
810 std::swap(
inner, other.inner);
869 template <
typename U>
884 template <
typename U>
887 while (!
sema->wait())
901 template <
typename U>
904 if (!
sema->wait(timeout_usecs))
915 #if __cplusplus > 199711L || _MSC_VER >= 1700
922 template <
typename U,
typename Rep,
typename Period>
925 return wait_dequeue_timed(result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
958 return sema->availableApprox();
986 std::unique_ptr<spsc_sema::LightweightSemaphore>
sema;