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)");
746 , sizeMask(_size - 1)
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);
819 if (inner.try_enqueue(element))
832 if (inner.try_enqueue(std::forward<T>(element)))
845 if (inner.enqueue(element))
858 if (inner.enqueue(std::forward<T>(element)))
869 template <
typename U>
874 bool success = inner.try_dequeue(result);
884 template <
typename U>
887 while (!sema->wait())
889 bool success = inner.try_dequeue(result);
901 template <
typename U>
904 if (!sema->wait(timeout_usecs))
908 bool success = inner.try_dequeue(result);
915 #if __cplusplus > 199711L || _MSC_VER >= 1700 922 template <
typename U,
typename Rep,
typename Period>
923 inline bool wait_dequeue_timed(U& result, std::chrono::duration<Rep, Period>
const& timeout)
AE_NO_TSAN 925 return wait_dequeue_timed(result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
946 bool result = inner.pop();
958 return sema->availableApprox();
972 return inner.max_capacity();
986 std::unique_ptr<spsc_sema::LightweightSemaphore>
sema;
weak_atomic< Block * > next
AE_FORCEINLINE bool try_enqueue(T const &element) AE_NO_TSAN
AE_FORCEINLINE bool try_enqueue(T &&element) AE_NO_TSAN
::moodycamel::ReaderWriterQueue< T, MAX_BLOCK_SIZE > ReaderWriterQueue
weak_atomic< size_t > tail
weak_atomic< Block * > tailBlock
bool try_dequeue(U &result) AE_NO_TSAN
AE_FORCEINLINE bool pop() AE_NO_TSAN
#define MOODYCAMEL_CACHE_LINE_SIZE
AE_NO_TSAN ~ReaderWriterQueue()
BlockingReaderWriterQueue(BlockingReaderWriterQueue const &)
AE_NO_TSAN ReaderWriterQueue(size_t size=15)
bool wait_dequeue_timed(U &result, std::int64_t timeout_usecs) AE_NO_TSAN
AE_NO_TSAN Block(size_t const &_size, char *_rawThis, char *_data)
static AE_FORCEINLINE size_t ceilToPow2(size_t x)
AE_FORCEINLINE bool try_enqueue(T const &element) AE_NO_TSAN
AE_FORCEINLINE bool enqueue(T const &element) AE_NO_TSAN
weak_atomic< size_t > front
AE_FORCEINLINE bool emplace(Args &&... args) AE_NO_TSAN
AE_FORCEINLINE size_t max_capacity() const
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
ReaderWriterQueue(ReaderWriterQueue const &)
BlockingReaderWriterQueue(size_t size=15) AE_NO_TSAN
size_t max_capacity() const
BlockingReaderWriterQueue & operator=(BlockingReaderWriterQueue &&other) AE_NO_TSAN
char cachelineFiller[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic< Block *>)]
bool try_dequeue(U &result) AE_NO_TSAN
std::unique_ptr< spsc_sema::LightweightSemaphore > sema
static Block * make_block(size_t capacity) AE_NO_TSAN
AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN
AE_FORCEINLINE bool try_enqueue(T &&element) AE_NO_TSAN
BlockingReaderWriterQueue(BlockingReaderWriterQueue &&other) AE_NO_TSAN
AE_FORCEINLINE bool enqueue(T const &element) AE_NO_TSAN
ReentrantGuard & operator=(ReentrantGuard const &)
AE_NO_TSAN ReaderWriterQueue(ReaderWriterQueue &&other)
AE_NO_TSAN ReentrantGuard(bool &_inSection)
size_t size_approx() const AE_NO_TSAN
BlockingReaderWriterQueue & operator=(BlockingReaderWriterQueue const &)
AE_NO_TSAN ~ReentrantGuard()
AE_FORCEINLINE bool try_emplace(Args &&... args) AE_NO_TSAN
void wait_dequeue(U &result) AE_NO_TSAN
bool inner_enqueue(Args &&... args) AE_NO_TSAN
AE_FORCEINLINE bool enqueue(T &&element) AE_NO_TSAN
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
AE_FORCEINLINE bool enqueue(T &&element) AE_NO_TSAN
ReaderWriterQueue & operator=(ReaderWriterQueue const &)
T * peek() const AE_NO_TSAN
ReaderWriterQueue & operator=(ReaderWriterQueue &&other) AE_NO_TSAN
weak_atomic< Block * > frontBlock
static AE_FORCEINLINE char * align_for(char *ptr) AE_NO_TSAN
AE_FORCEINLINE T * peek() const AE_NO_TSAN