16 #if __cplusplus > 199711L || _MSC_VER >= 1700
34 #ifndef MOODYCAMEL_CACHE_LINE_SIZE
35 #define MOODYCAMEL_CACHE_LINE_SIZE 64
38 #ifndef MOODYCAMEL_HAS_EMPLACE
39 #if !defined(_MSC_VER) || _MSC_VER >= 1800
40 #define MOODYCAMEL_HAS_EMPLACE 1
46 #pragma warning(disable: 4324)
47 #pragma warning(disable: 4820)
48 #pragma warning(disable: 4127)
51 #define MAX_BLOCK_SIZE 512
85 assert(
MAX_BLOCK_SIZE >= 2 &&
"MAX_BLOCK_SIZE must be at least 2");
87 Block* firstBlock =
nullptr;
98 Block* lastBlock =
nullptr;
99 for (
size_t i = 0; i != initialBlockCount; ++i) {
101 if (block ==
nullptr) {
104 if (firstBlock ==
nullptr) {
108 lastBlock->
next = block;
111 block->
next = firstBlock;
116 if (firstBlock ==
nullptr) {
119 firstBlock->
next = firstBlock;
139 Block* block = frontBlock_;
146 }
while (block != frontBlock_);
186 size_t blockTail = frontBlock_->
localTail;
187 size_t blockFront = frontBlock_->
front.
load();
189 if (blockFront != blockTail || blockFront != (frontBlock_->
localTail = frontBlock_->
tail.
load())) {
192 non_empty_front_block:
194 result = frontBlock_->
data[blockFront];
197 blockFront = (blockFront + 1) & frontBlock_->
sizeMask;
200 frontBlock_->
front = blockFront;
202 else if (frontBlock_ !=
tailBlock.load()) {
210 if (blockFront != blockTail) {
212 goto non_empty_front_block;
221 size_t nextBlockFront = nextBlock->
front.
load();
227 assert(nextBlockFront != nextBlockTail);
236 result = frontBlock_->
data [nextBlockFront];
240 nextBlockFront = (nextBlockFront + 1) & frontBlock_->
sizeMask;
243 frontBlock_->
front = nextBlockFront;
264 size_t blockTail = frontBlock_->
localTail;
265 size_t blockFront = frontBlock_->
front.
load();
267 if (blockFront != blockTail || blockFront != (frontBlock_->
localTail = frontBlock_->
tail.
load())) {
269 non_empty_front_block:
270 return reinterpret_cast<UINT8*
>(frontBlock_->
data + blockFront *
sizeof(
UINT8*));
272 else if (frontBlock_ !=
tailBlock.load()) {
279 if (blockFront != blockTail) {
280 goto non_empty_front_block;
285 size_t nextBlockFront = nextBlock->
front.
load();
288 assert(nextBlockFront != nextBlock->
tail.
load());
289 return reinterpret_cast<UINT8*
>(nextBlock->
data + nextBlockFront *
sizeof(
UINT8*));
303 size_t blockTail = frontBlock_->
localTail;
304 size_t blockFront = frontBlock_->
front.
load();
306 if (blockFront != blockTail || blockFront != (frontBlock_->
localTail = frontBlock_->
tail.
load())) {
309 non_empty_front_block:
310 auto element =
reinterpret_cast<UINT8*
>(frontBlock_->
data + blockFront *
sizeof(
UINT8));
313 blockFront = (blockFront + 1) & frontBlock_->
sizeMask;
316 frontBlock_->
front = blockFront;
318 else if (frontBlock_ !=
tailBlock.load()) {
325 if (blockFront != blockTail) {
326 goto non_empty_front_block;
332 size_t nextBlockFront = nextBlock->
front.
load();
336 assert(nextBlockFront != nextBlockTail);
344 auto element =
reinterpret_cast<UINT8*
>(frontBlock_->
data + nextBlockFront *
sizeof(
UINT8*));
347 nextBlockFront = (nextBlockFront + 1) & frontBlock_->
sizeMask;
350 frontBlock_->
front = nextBlockFront;
366 Block* block = frontBlock_;
370 size_t blockTail = block->
tail.
load();
371 result += (blockTail - blockFront) & block->
sizeMask;
372 block = block->
next.load();
373 }
while (block != frontBlock_);
393 size_t blockTail = tailBlock_->
tail.
load();
395 size_t nextBlockTail = (blockTail + 1) & tailBlock_->
sizeMask;
396 if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->
localFront = tailBlock_->
front.
load())) {
399 tailBlock_->
data[blockTail]= element;
403 tailBlock_->
tail = nextBlockTail;
416 Block* tailBlockNext = tailBlock_->
next.load();
418 nextBlockTail = tailBlockNext->
tail.
load();
423 assert(nextBlockFront == nextBlockTail);
426 tailBlockNext->
data[nextBlockTail] = element;
428 tailBlockNext->
tail = (nextBlockTail + 1) & tailBlockNext->
sizeMask;
437 if (newBlock ==
nullptr) {
444 newBlock->data[0] = element;
445 assert(newBlock->front == 0);
446 newBlock->tail = newBlock->localTail = 1;
448 newBlock->next = tailBlock_->
next.load();
449 tailBlock_->
next = newBlock;
465 assert(
false &&
"Should be unreachable code");
482 for (
size_t i = 1; i <
sizeof(size_t); i <<= 1) {
492 const std::size_t alignment = std::alignment_of<U>::value;
493 return ptr + (alignment - (
reinterpret_cast<std::uintptr_t
>(ptr) % alignment)) % alignment;
535 UINT size =
sizeof(
Block) + std::alignment_of<Block>::value - 1;
536 size +=
sizeof(
UINT8*) * capacity + std::alignment_of<UINT8*>::value - 1;
537 UINT8* newBlockRaw =
static_cast<UINT8*
>(std::malloc(size));
538 if (newBlockRaw ==
nullptr) {
542 UINT8* newBlockAligned = align_for<Block>(newBlockRaw);
543 UINT8* newBlockData = align_for<UINT8*>(newBlockAligned +
sizeof(
Block));
544 return new (newBlockAligned)
Block(capacity, newBlockRaw, newBlockData);
567 :
inner(std::move(other.inner)),
sema(std::move(other.sema))
572 std::swap(
sema, other.sema);
573 std::swap(
inner, other.inner);
596 if (
sema->tryWait()) {
626 if (!
sema->wait(timeout_usecs)) {
637 #if __cplusplus > 199711L || _MSC_VER >= 1700
644 template<
typename Rep,
typename Period>
647 return wait_dequeue_timed(result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
667 if (
sema->tryWait()) {
680 return sema->availableApprox();
687 std::unique_ptr<spsc_sema::LightweightSemaphore>
sema;
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
BlockingReaderWriterQueue(BlockingReaderWriterQueue &&other) AE_NO_TSAN
std::unique_ptr< spsc_sema::LightweightSemaphore > sema
AE_FORCEINLINE bool enqueue(UINT8 *const &element) AE_NO_TSAN
AE_FORCEINLINE UINT8 * peek() AE_NO_TSAN
bool wait_dequeue_timed(UINT8 *&result, std::int64_t timeout_usecs) AE_NO_TSAN
AE_FORCEINLINE bool pop() AE_NO_TSAN
BlockingReaderWriterQueue & operator=(BlockingReaderWriterQueue &&other) AE_NO_TSAN
AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN
BlockingReaderWriterQueue(size_t maxSize=15) AE_NO_TSAN
void wait_dequeue(UINT8 *&result) AE_NO_TSAN
bool try_dequeue(UINT8 *&result) AE_NO_TSAN
char cachelineFiller[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic< Block * >)]
static AE_FORCEINLINE UINT8 * align_for(UINT8 *ptr) AE_NO_TSAN
weak_atomic< Block * > tailBlock
AE_FORCEINLINE bool enqueue(UINT8 *const &element) AE_NO_TSAN
AE_NO_TSAN ReaderWriterQueue(size_t maxSize=15)
AE_NO_TSAN ~ReaderWriterQueue()
bool try_dequeue(UINT8 *&result) AE_NO_TSAN
static Block * make_block(size_t capacity) AE_NO_TSAN
bool inner_enqueue(AllocationMode canAlloc, UINT8 *const &element) AE_NO_TSAN
size_t size_approx() const AE_NO_TSAN
static AE_FORCEINLINE size_t ceilToPow2(size_t x)
UINT8 * peek() AE_NO_TSAN
weak_atomic< Block * > frontBlock
AE_FORCEINLINE T load() const AE_NO_TSAN
#define MOODYCAMEL_CACHE_LINE_SIZE
char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic< size_t >) - sizeof(size_t)]
weak_atomic< size_t > front
weak_atomic< Block * > next
Block & operator=(Block const &)
char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic< size_t >) - sizeof(size_t)]
weak_atomic< size_t > tail
AE_NO_TSAN Block(size_t const &_size, UINT8 *_rawThis, UINT8 *_data)