// File: alfanick[P]rest-cpp/src/rest/readerwriterqueue/readerwriterqueue.h
// Function: bool moodycamel::ReaderWriterQueue<REST::Request::client, 512ul>::try_dequeue<REST::Request::client>(REST::Request::client&)
bool try_dequeue(U& result)
	{
#ifndef NDEBUG
		ReentrantGuard guard(this->dequeuing);
#endif

		// High-level pseudocode:
		// Remember where the tail block is
		// If the front block has an element in it, dequeue it
		// Else
		//     If front block was the tail block when we entered the function, return false
		//     Else advance to next block and dequeue the item there

		// Note that we have to use the value of the tail block from before we check if the front
		// block is full or not, in case the front block is empty and then, before we check if the
		// tail block is at the front block or not, the producer fills up the front block *and
		// moves on*, which would make us skip a filled block. Seems unlikely, but was consistently
		// reproducible in practice.
		// In order to avoid overhead in the common case, though, we do a double-checked pattern
		// where we have the fast path if the front block is not empty, then read the tail block,
		// then re-read the front block and check if it's not empty again, then check if the tail
		// block has advanced.
		
		Block* frontBlock_ = frontBlock.load();
		size_t blockTail = frontBlock_->localTail;
		size_t blockFront = frontBlock_->front.load();
		
		if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
			fence(memory_order_acquire);
			
		non_empty_front_block:
			// Front block not empty, dequeue from here
			auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
			result = std::move(*element);
			element->~T();

			blockFront = (blockFront + 1) & frontBlock_->sizeMask;

			fence(memory_order_release);
			frontBlock_->front = blockFront;
		}
		else if (frontBlock_ != tailBlock.load()) {
			fence(memory_order_acquire);

			frontBlock_ = frontBlock.load();
			blockTail = frontBlock_->localTail = frontBlock_->tail.load();
			blockFront = frontBlock_->front.load();
			fence(memory_order_acquire);
			
			if (blockFront != blockTail) {
				// Oh look, the front block isn't empty after all
				goto non_empty_front_block;
			}
			
			// Front block is empty but there's another block ahead, advance to it
			Block* nextBlock = frontBlock_->next;
			// Don't need an acquire fence here since next can only ever be set on the tailBlock,
			// and we're not the tailBlock, and we did an acquire earlier after reading tailBlock which
			// ensures next is up-to-date on this CPU in case we recently were at tailBlock.

			size_t nextBlockFront = nextBlock->front.load();
			size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
			fence(memory_order_acquire);

			// Since the tailBlock is only ever advanced after being written to,
			// we know there's for sure an element to dequeue on it
			assert(nextBlockFront != nextBlockTail);
			AE_UNUSED(nextBlockTail);

			// We're done with this block, let the producer use it if it needs
			fence(memory_order_release);		// Expose possibly pending changes to frontBlock->front from last dequeue
			frontBlock = frontBlock_ = nextBlock;

			compiler_fence(memory_order_release);	// Not strictly needed

			auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));
			
			result = std::move(*element);
			element->~T();

			nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
			
			fence(memory_order_release);
			frontBlock_->front = nextBlockFront;
		}
		else {
			// No elements in current block and no other block to advance to
			return false;
		}

		return true;
	}

// Assembly:
subq $0x98, %rsp
movq %rdi, 0x88(%rsp)
movq %rsi, 0x80(%rsp)
movq 0x88(%rsp), %rsi
movq %rsi, 0x18(%rsp)
addq $0x51, %rsi
leaq 0x78(%rsp), %rdi
callq 0x91dc0
movq 0x18(%rsp), %rdi
callq 0x8f2c0
movq %rax, 0x70(%rsp)
movq 0x70(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x68(%rsp)
movq 0x70(%rsp), %rdi
callq 0x90ae0
movq %rax, 0x60(%rsp)
movq 0x60(%rsp), %rax
cmpq 0x68(%rsp), %rax
jne 0xdb338
movq 0x60(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x70(%rsp), %rdi
addq $0x40, %rdi
callq 0x90ae0
movq %rax, %rcx
movq 0x10(%rsp), %rax
movq 0x70(%rsp), %rdx
movq %rcx, 0x8(%rdx)
cmpq %rcx, %rax
je 0xdb3ae
movl $0x1, %edi
callq 0x96180
movq 0x70(%rsp), %rax
movq 0x88(%rax), %rax
imulq $0x88, 0x60(%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x58(%rsp)
movq 0x58(%rsp), %rsi
movq 0x80(%rsp), %rdi
movl $0x88, %edx
callq 0x91de0
movq 0x60(%rsp), %rax
addq $0x1, %rax
movq 0x70(%rsp), %rcx
andq 0x90(%rcx), %rax
movq %rax, 0x60(%rsp)
movl $0x2, %edi
callq 0x96180
movq 0x70(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x8e530
jmp 0xdb57c
movq 0x18(%rsp), %rdi
movq 0x70(%rsp), %rax
movq %rax, 0x8(%rsp)
addq $0x40, %rdi
callq 0x8f2c0
movq %rax, %rcx
movq 0x8(%rsp), %rax
cmpq %rcx, %rax
je 0xdb568
movl $0x1, %edi
callq 0x96180
movq 0x18(%rsp), %rdi
callq 0x8f2c0
movq %rax, 0x70(%rsp)
movq 0x70(%rsp), %rdi
addq $0x40, %rdi
callq 0x90ae0
movq 0x70(%rsp), %rcx
movq %rax, 0x8(%rcx)
movq %rax, 0x68(%rsp)
movq 0x70(%rsp), %rdi
callq 0x90ae0
movq %rax, 0x60(%rsp)
movl $0x1, %edi
callq 0x96180
movq 0x60(%rsp), %rax
cmpq 0x68(%rsp), %rax
je 0xdb436
jmp 0xdb342
movq 0x70(%rsp), %rdi
subq $-0x80, %rdi
callq 0x96ee0
movq %rax, (%rsp)
jmp 0xdb44a
movq (%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x50(%rsp), %rdi
callq 0x90ae0
movq %rax, 0x38(%rsp)
movq 0x50(%rsp), %rdi
addq $0x40, %rdi
callq 0x90ae0
movq 0x50(%rsp), %rcx
movq %rax, 0x8(%rcx)
movq %rax, 0x30(%rsp)
movl $0x1, %edi
callq 0x96180
movq 0x38(%rsp), %rax
cmpq 0x30(%rsp), %rax
je 0xdb496
jmp 0xdb4d2
leaq 0xb5b6(%rip), %rdi      # 0xe6a53
leaq 0xb04b(%rip), %rsi      # 0xe64ef
movl $0xfc, %edx
leaq 0xb5c3(%rip), %rcx      # 0xe6a73
callq 0x90c40
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x48(%rsp)
movl %eax, 0x44(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x961e0
jmp 0xdb5a7
movl $0x2, %edi
callq 0x96180
movq 0x18(%rsp), %rdi
movq 0x50(%rsp), %rax
movq %rax, 0x70(%rsp)
leaq 0x70(%rsp), %rsi
callq 0x8d1c0
movl $0x2, %edi
callq 0x93c10
movq 0x70(%rsp), %rax
movq 0x88(%rax), %rax
imulq $0x88, 0x38(%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rsi
movq 0x80(%rsp), %rdi
movl $0x88, %edx
callq 0x91de0
movq 0x38(%rsp), %rax
addq $0x1, %rax
movq 0x70(%rsp), %rcx
andq 0x90(%rcx), %rax
movq %rax, 0x38(%rsp)
movl $0x2, %edi
callq 0x96180
movq 0x70(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x8e530
jmp 0xdb57a
movb $0x0, 0x97(%rsp)
movl $0x1, 0x24(%rsp)
jmp 0xdb58c
jmp 0xdb57c
movb $0x1, 0x97(%rsp)
movl $0x1, 0x24(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x961e0
movb 0x97(%rsp), %al
andb $0x1, %al
addq $0x98, %rsp
retq
movq 0x48(%rsp), %rdi
callq 0x981c0
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)