17#if __cplusplus > 199711L || _MSC_VER >= 1700
35#ifndef MOODYCAMEL_CACHE_LINE_SIZE
36#define MOODYCAMEL_CACHE_LINE_SIZE 64
39#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED
40#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__))
41#define MOODYCAMEL_EXCEPTIONS_ENABLED
45#ifndef MOODYCAMEL_HAS_EMPLACE
46#if !defined(_MSC_VER) || _MSC_VER >= 1800
47#define MOODYCAMEL_HAS_EMPLACE 1
51#ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
52#if defined (__APPLE__) && defined (__MACH__) && __cplusplus >= 201703L
54#include <CoreFoundation/CoreFoundation.h>
55#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14
57#define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
62#ifndef MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
63#define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE AE_ALIGN(MOODYCAMEL_CACHE_LINE_SIZE)
68#pragma warning(disable: 4324)
69#pragma warning(disable: 4820)
70#pragma warning(disable: 4127)
75template<
typename T,
size_t MAX_BLOCK_SIZE = 512>
111 assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) &&
"MAX_BLOCK_SIZE must be a power of 2");
112 assert(MAX_BLOCK_SIZE >= 2 &&
"MAX_BLOCK_SIZE must be at least 2");
114 Block* firstBlock =
nullptr;
116 largestBlockSize = ceilToPow2(size + 1);
117 if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
123 size_t initialBlockCount = (size + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
124 largestBlockSize = MAX_BLOCK_SIZE;
125 Block* lastBlock =
nullptr;
126 for (
size_t i = 0; i != initialBlockCount; ++i) {
127 auto block = make_block(largestBlockSize);
128 if (block ==
nullptr) {
129#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
130 throw std::bad_alloc();
135 if (firstBlock ==
nullptr) {
139 lastBlock->next = block;
142 block->next = firstBlock;
146 firstBlock = make_block(largestBlockSize);
147 if (firstBlock ==
nullptr) {
148#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
149 throw std::bad_alloc();
154 firstBlock->next = firstBlock;
156 frontBlock = firstBlock;
157 tailBlock = firstBlock;
166 : frontBlock(other.frontBlock.load()),
167 tailBlock(other.tailBlock.load()),
168 largestBlockSize(other.largestBlockSize)
174 other.largestBlockSize = 32;
175 Block* b = other.make_block(other.largestBlockSize);
177#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
178 throw std::bad_alloc();
184 other.frontBlock = b;
192 Block* b = frontBlock.load();
193 frontBlock = other.frontBlock.load();
194 other.frontBlock = b;
195 b = tailBlock.load();
196 tailBlock = other.tailBlock.load();
198 std::swap(largestBlockSize, other.largestBlockSize);
210 Block* frontBlock_ = frontBlock;
211 Block* block = frontBlock_;
213 Block* nextBlock = block->next;
214 size_t blockFront = block->front;
215 size_t blockTail = block->tail;
217 for (
size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
218 auto element =
reinterpret_cast<T*
>(block->data + i *
sizeof(T));
223 auto rawBlock = block->rawThis;
227 }
while (block != frontBlock_);
236 return inner_enqueue<CannotAlloc>(element);
244 return inner_enqueue<CannotAlloc>(std::forward<T>(element));
247#if MOODYCAMEL_HAS_EMPLACE
249 template<
typename... Args>
252 return inner_enqueue<CannotAlloc>(std::forward<Args>(
args)...);
261 return inner_enqueue<CanAlloc>(element);
269 return inner_enqueue<CanAlloc>(std::forward<T>(element));
272#if MOODYCAMEL_HAS_EMPLACE
274 template<
typename... Args>
277 return inner_enqueue<CanAlloc>(std::forward<Args>(
args)...);
288 ReentrantGuard guard(this->dequeuing);
308 Block* frontBlock_ = frontBlock.load();
309 size_t blockTail = frontBlock_->localTail;
310 size_t blockFront = frontBlock_->front.load();
312 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
315 non_empty_front_block:
317 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
318 result = std::move(*element);
321 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
324 frontBlock_->front = blockFront;
326 else if (frontBlock_ != tailBlock.load()) {
329 frontBlock_ = frontBlock.load();
330 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
331 blockFront = frontBlock_->front.load();
334 if (blockFront != blockTail) {
336 goto non_empty_front_block;
340 Block* nextBlock = frontBlock_->next;
345 size_t nextBlockFront = nextBlock->front.load();
346 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
351 assert(nextBlockFront != nextBlockTail);
356 frontBlock = frontBlock_ = nextBlock;
360 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
362 result = std::move(*element);
365 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
368 frontBlock_->front = nextBlockFront;
387 ReentrantGuard guard(this->dequeuing);
391 Block* frontBlock_ = frontBlock.load();
392 size_t blockTail = frontBlock_->localTail;
393 size_t blockFront = frontBlock_->front.load();
395 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
397 non_empty_front_block:
398 return reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
400 else if (frontBlock_ != tailBlock.load()) {
402 frontBlock_ = frontBlock.load();
403 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
404 blockFront = frontBlock_->front.load();
407 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));
429 ReentrantGuard guard(this->dequeuing);
433 Block* frontBlock_ = frontBlock.load();
434 size_t blockTail = frontBlock_->localTail;
435 size_t blockFront = frontBlock_->front.load();
437 if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
440 non_empty_front_block:
441 auto element =
reinterpret_cast<T*
>(frontBlock_->data + blockFront *
sizeof(T));
444 blockFront = (blockFront + 1) & frontBlock_->sizeMask;
447 frontBlock_->front = blockFront;
449 else if (frontBlock_ != tailBlock.load()) {
451 frontBlock_ = frontBlock.load();
452 blockTail = frontBlock_->localTail = frontBlock_->tail.load();
453 blockFront = frontBlock_->front.load();
456 if (blockFront != blockTail) {
457 goto non_empty_front_block;
461 Block* nextBlock = frontBlock_->next;
463 size_t nextBlockFront = nextBlock->front.load();
464 size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
467 assert(nextBlockFront != nextBlockTail);
471 frontBlock = frontBlock_ = nextBlock;
475 auto element =
reinterpret_cast<T*
>(frontBlock_->data + nextBlockFront *
sizeof(T));
478 nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
481 frontBlock_->front = nextBlockFront;
496 Block* frontBlock_ = frontBlock.load();
497 Block* block = frontBlock_;
500 size_t blockFront = block->front.load();
501 size_t blockTail = block->tail.load();
502 result += (blockTail - blockFront) & block->sizeMask;
503 block = block->next.load();
504 }
while (block != frontBlock_);
519 Block* frontBlock_ = frontBlock.load();
520 Block* block = frontBlock_;
523 result += block->sizeMask;
524 block = block->next.load();
525 }
while (block != frontBlock_);
531 enum AllocationMode { CanAlloc, CannotAlloc };
533#if MOODYCAMEL_HAS_EMPLACE
534 template<AllocationMode canAlloc,
typename... Args>
537 template<AllocationMode canAlloc,
typename U>
542 ReentrantGuard guard(this->enqueuing);
552 Block* tailBlock_ = tailBlock.load();
553 size_t blockFront = tailBlock_->localFront;
554 size_t blockTail = tailBlock_->tail.load();
556 size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
557 if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) {
560 char* location = tailBlock_->data + blockTail *
sizeof(T);
561#if MOODYCAMEL_HAS_EMPLACE
562 new (location) T(std::forward<Args>(
args)...);
564 new (location) T(std::forward<U>(element));
568 tailBlock_->tail = nextBlockTail;
572 if (tailBlock_->next.load() != frontBlock) {
581 Block* tailBlockNext = tailBlock_->next.load();
582 size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load();
583 nextBlockTail = tailBlockNext->tail.load();
588 assert(nextBlockFront == nextBlockTail);
589 tailBlockNext->localFront = nextBlockFront;
591 char* location = tailBlockNext->data + nextBlockTail *
sizeof(T);
592#if MOODYCAMEL_HAS_EMPLACE
593 new (location) T(std::forward<Args>(
args)...);
595 new (location) T(std::forward<U>(element));
598 tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
601 tailBlock = tailBlockNext;
603 else if (canAlloc == CanAlloc) {
605 auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
606 auto newBlock = make_block(newBlockSize);
607 if (newBlock ==
nullptr) {
611 largestBlockSize = newBlockSize;
613#if MOODYCAMEL_HAS_EMPLACE
614 new (newBlock->data) T(std::forward<Args>(
args)...);
616 new (newBlock->data) T(std::forward<U>(element));
618 assert(newBlock->front == 0);
619 newBlock->tail = newBlock->localTail = 1;
621 newBlock->next = tailBlock_->next.load();
622 tailBlock_->next = newBlock;
631 tailBlock = newBlock;
633 else if (canAlloc == CannotAlloc) {
638 assert(
false &&
"Should be unreachable code");
648 ReaderWriterQueue(ReaderWriterQueue
const&) { }
651 ReaderWriterQueue& operator=(ReaderWriterQueue
const&) { }
661 for (
size_t i = 1; i <
sizeof(size_t); i <<= 1) {
671 const std::size_t alignment = std::alignment_of<U>::value;
672 return ptr + (alignment - (
reinterpret_cast<std::uintptr_t
>(ptr) % alignment)) % alignment;
676 struct ReentrantGuard
678 AE_NO_TSAN ReentrantGuard(weak_atomic<bool>& _inSection)
679 : inSection(_inSection)
681 assert(!inSection &&
"Concurrent (or re-entrant) enqueue or dequeue operation detected (only one thread at a time may hold the producer or consumer role)");
685 AE_NO_TSAN ~ReentrantGuard() { inSection =
false; }
688 ReentrantGuard& operator=(ReentrantGuard
const&);
691 weak_atomic<bool>& inSection;
698 weak_atomic<size_t> front;
702 weak_atomic<size_t> tail;
706 weak_atomic<Block*> next;
710 const size_t sizeMask;
714 AE_NO_TSAN Block(
size_t const& _size,
char* _rawThis,
char* _data)
715 : front(0UL), localTail(0), tail(0UL), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1), rawThis(_rawThis)
721 Block& operator=(Block
const&);
728 static Block* make_block(
size_t capacity)
AE_NO_TSAN
731 auto size =
sizeof(Block) + std::alignment_of<Block>::value - 1;
732 size +=
sizeof(T) * capacity + std::alignment_of<T>::value - 1;
733 auto newBlockRaw =
static_cast<char*
>(std::malloc(size));
734 if (newBlockRaw ==
nullptr) {
738 auto newBlockAligned = align_for<Block>(newBlockRaw);
739 auto newBlockData = align_for<T>(newBlockAligned +
sizeof(Block));
740 return new (newBlockAligned) Block(capacity, newBlockRaw, newBlockData);
744 weak_atomic<Block*> frontBlock;
747 weak_atomic<Block*> tailBlock;
749 size_t largestBlockSize;
752 weak_atomic<bool> enqueuing;
753 mutable weak_atomic<bool> dequeuing;
758template<
typename T,
size_t MAX_BLOCK_SIZE = 512>
766 : inner(size), sema(new spsc_sema::LightweightSemaphore())
770 : inner(std::move(other.inner)), sema(std::move(other.sema))
775 std::swap(sema, other.sema);
776 std::swap(inner, other.inner);
805#if MOODYCAMEL_HAS_EMPLACE
807 template<
typename... Args>
836 if (inner.
enqueue(std::forward<T>(element))) {
843#if MOODYCAMEL_HAS_EMPLACE
845 template<
typename... Args>
863 if (sema->tryWait()) {
878 while (!sema->wait());
895 if (!sema->wait(timeout_usecs)) {
906#if __cplusplus > 199711L || _MSC_VER >= 1700
913 template<
typename U,
typename Rep,
typename Period>
916 return wait_dequeue_timed(result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
936 if (sema->tryWait()) {
937 bool result = inner.
pop();
949 return sema->availableApprox();
971 ReaderWriterQueue inner;
972 std::unique_ptr<spsc_sema::LightweightSemaphore> sema;
#define AE_UNUSED(x)
Definition: atomicops.h:44
#define AE_FORCEINLINE
Definition: atomicops.h:76
#define AE_NO_TSAN
Definition: atomicops.h:61
Definition: readerwriterqueue.h:760
AE_FORCEINLINE bool try_enqueue(T &&element) AE_NO_TSAN
Definition: readerwriterqueue.h:796
AE_FORCEINLINE bool try_emplace(Args &&... args) AE_NO_TSAN
Definition: readerwriterqueue.h:808
AE_FORCEINLINE bool emplace(Args &&... args) AE_NO_TSAN
Definition: readerwriterqueue.h:846
AE_FORCEINLINE bool enqueue(T const &element) AE_NO_TSAN
Definition: readerwriterqueue.h:822
bool wait_dequeue_timed(U &result, std::int64_t timeout_usecs) AE_NO_TSAN
Definition: readerwriterqueue.h:893
AE_FORCEINLINE size_t max_capacity() const
Definition: readerwriterqueue.h:961
AE_FORCEINLINE bool enqueue(T &&element) AE_NO_TSAN
Definition: readerwriterqueue.h:834
void wait_dequeue(U &result) AE_NO_TSAN
Definition: readerwriterqueue.h:876
AE_FORCEINLINE bool pop() AE_NO_TSAN
Definition: readerwriterqueue.h:934
BlockingReaderWriterQueue(BlockingReaderWriterQueue &&other) AE_NO_TSAN
Definition: readerwriterqueue.h:769
bool try_dequeue(U &result) AE_NO_TSAN
Definition: readerwriterqueue.h:861
AE_FORCEINLINE T * peek() const AE_NO_TSAN
Definition: readerwriterqueue.h:926
BlockingReaderWriterQueue(size_t size=15) AE_NO_TSAN
Definition: readerwriterqueue.h:765
BlockingReaderWriterQueue & operator=(BlockingReaderWriterQueue &&other) AE_NO_TSAN
Definition: readerwriterqueue.h:773
AE_FORCEINLINE bool try_enqueue(T const &element) AE_NO_TSAN
Definition: readerwriterqueue.h:784
AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN
Definition: readerwriterqueue.h:947
Definition: readerwriterqueue.h:77
AE_FORCEINLINE bool enqueue(T &&element) AE_NO_TSAN
Definition: readerwriterqueue.h:267
T * peek() const AE_NO_TSAN
Definition: readerwriterqueue.h:384
AE_FORCEINLINE bool emplace(Args &&... args) AE_NO_TSAN
Definition: readerwriterqueue.h:275
size_t size_approx() const AE_NO_TSAN
Definition: readerwriterqueue.h:493
bool try_dequeue(U &result) AE_NO_TSAN
Definition: readerwriterqueue.h:285
ReaderWriterQueue & operator=(ReaderWriterQueue &&other) AE_NO_TSAN
Definition: readerwriterqueue.h:190
AE_FORCEINLINE bool enqueue(T const &element) AE_NO_TSAN
Definition: readerwriterqueue.h:259
T value_type
Definition: readerwriterqueue.h:99
AE_NO_TSAN ~ReaderWriterQueue()
Definition: readerwriterqueue.h:204
AE_FORCEINLINE bool try_enqueue(T &&element) AE_NO_TSAN
Definition: readerwriterqueue.h:242
bool pop() AE_NO_TSAN
Definition: readerwriterqueue.h:426
AE_NO_TSAN ReaderWriterQueue(size_t size=15)
Definition: readerwriterqueue.h:105
size_t max_capacity() const
Definition: readerwriterqueue.h:517
AE_NO_TSAN ReaderWriterQueue(ReaderWriterQueue &&other)
Definition: readerwriterqueue.h:165
AE_FORCEINLINE bool try_enqueue(T const &element) AE_NO_TSAN
Definition: readerwriterqueue.h:234
AE_FORCEINLINE bool try_emplace(Args &&... args) AE_NO_TSAN
Definition: readerwriterqueue.h:250
args
Definition: build.py:22
Definition: atomicops.h:93
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
Definition: atomicops.h:206
@ memory_order_acquire
Definition: atomicops.h:97
@ memory_order_sync
Definition: atomicops.h:104
@ memory_order_release
Definition: atomicops.h:98
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
Definition: atomicops.h:218
#define MOODYCAMEL_CACHE_LINE_SIZE
Definition: readerwriterqueue.h:36
#define MOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE
Definition: readerwriterqueue.h:63