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

		// High-level pseudocode (assuming we're allowed to alloc a new block):
		// If room in tail block, add to tail
		// Else check next block
		//     If next block is not the head block, enqueue on next block
		//     Else create a new block and enqueue there
		//     Advance tail to the block we just enqueued to

		Block* tailBlock_ = tailBlock.load();
		size_t blockFront = tailBlock_->localFront;
		size_t blockTail = tailBlock_->tail.load();

		size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
		if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) {
			fence(memory_order_acquire);
			// This block has room for at least one more element
			char* location = tailBlock_->data + blockTail * sizeof(T);
			new (location) T(std::forward<U>(element));

			fence(memory_order_release);
			tailBlock_->tail = nextBlockTail;
		}
		else {
			fence(memory_order_acquire);
			if (tailBlock_->next.load() != frontBlock) {
				// Note that the reason we can't advance to the frontBlock and start adding new entries there
				// is because if we did, then dequeue would stay in that block, eventually reading the new values,
				// instead of advancing to the next full block (whose values were enqueued first and so should be
				// consumed first).
				
				fence(memory_order_acquire);		// Ensure we get latest writes if we got the latest frontBlock

				// tailBlock is full, but there's a free block ahead, use it
				Block* tailBlockNext = tailBlock_->next.load();
				size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load();
				nextBlockTail = tailBlockNext->tail.load();
				fence(memory_order_acquire);

				// This block must be empty since it's not the head block and we
				// go through the blocks in a circle
				assert(nextBlockFront == nextBlockTail);
				tailBlockNext->localFront = nextBlockFront;

				char* location = tailBlockNext->data + nextBlockTail * sizeof(T);
				new (location) T(std::forward<U>(element));

				tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;

				fence(memory_order_release);
				tailBlock = tailBlockNext;
			}
			else if (canAlloc == CanAlloc) {
				// tailBlock is full and there's no free block ahead; create a new block
				auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
				auto newBlock = make_block(newBlockSize);
				if (newBlock == nullptr) {
					// Could not allocate a block!
					return false;
				}
				largestBlockSize = newBlockSize;

				new (newBlock->data) T(std::forward<U>(element));

				assert(newBlock->front == 0);
				newBlock->tail = newBlock->localTail = 1;

				newBlock->next = tailBlock_->next.load();
				tailBlock_->next = newBlock;

				// Might be possible for the dequeue thread to see the new tailBlock->next
				// *without* seeing the new tailBlock value, but this is OK since it can't
				// advance to the next block until tailBlock is set anyway (because the only
				// case where it could try to read the next is if it's already at the tailBlock,
				// and it won't advance past tailBlock in any circumstance).
				
				fence(memory_order_release);
				tailBlock = newBlock;
			}
			else if (canAlloc == CannotAlloc) {
				// Would have had to allocate a new block to enqueue, but not allowed
				return false;
			}
			else {
				assert(false && "Should be unreachable code");
				return false;
			}
		}

		return true;
	}

// Assembly:
subq $0xd8, %rsp
movq %rdi, 0xc8(%rsp)
movq %rsi, 0xc0(%rsp)
movq 0xc8(%rsp), %rsi
movq %rsi, 0x38(%rsp)
addq $0x50, %rsi
leaq 0xb8(%rsp), %rdi
callq 0x91dc0
movq 0x38(%rsp), %rdi
addq $0x40, %rdi
callq 0x8f2c0
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
movq 0x48(%rax), %rax
movq %rax, 0xa8(%rsp)
movq 0xb0(%rsp), %rdi
addq $0x40, %rdi
callq 0x90ae0
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rax
addq $0x1, %rax
movq 0xb0(%rsp), %rcx
andq 0x90(%rcx), %rax
movq %rax, 0x98(%rsp)
movq 0x98(%rsp), %rax
cmpq 0xa8(%rsp), %rax
jne 0xda6a4
movq 0x98(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0xb0(%rsp), %rdi
callq 0x90ae0
movq %rax, %rcx
movq 0x30(%rsp), %rax
movq 0xb0(%rsp), %rdx
movq %rcx, 0x48(%rdx)
cmpq %rcx, %rax
je 0xda766
movl $0x1, %edi
callq 0x96180
movq 0xb0(%rsp), %rax
movq 0x88(%rax), %rax
movq 0xa0(%rsp), %rdx
movq %rdx, %rcx
shlq $0x7, %rcx
leaq (%rcx,%rdx,8), %rcx
addq %rcx, %rax
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rax
movq 0xc0(%rsp), %rcx
movq 0x80(%rcx), %rdx
movq %rdx, 0x80(%rax)
vmovdqu64 (%rcx), %zmm0
vmovdqu64 0x40(%rcx), %zmm1
vmovdqu64 %zmm1, 0x40(%rax)
vmovdqu64 %zmm0, (%rax)
movl $0x2, %edi
vzeroupper
callq 0x96180
movq 0xb0(%rsp), %rdi
addq $0x40, %rdi
leaq 0x98(%rsp), %rsi
callq 0x8e530
jmp 0xda73b
jmp 0xdaa7b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x88(%rsp)
movl %eax, 0x84(%rsp)
leaq 0xb8(%rsp), %rdi
callq 0x961e0
jmp 0xdaaa9
movl $0x1, %edi
callq 0x96180
movq 0xb0(%rsp), %rdi
subq $-0x80, %rdi
callq 0x8f2c0
movq 0x38(%rsp), %rdi
movq %rax, 0x20(%rsp)
callq 0x96ee0
movq %rax, 0x28(%rsp)
jmp 0xda797
movq 0x20(%rsp), %rax
movq 0x28(%rsp), %rcx
cmpq %rcx, %rax
je 0xda8f8
movl $0x1, %edi
callq 0x96180
movq 0xb0(%rsp), %rdi
addq $0x80, %rdi
callq 0x8f2c0
movq %rax, 0x78(%rsp)
movq 0x78(%rsp), %rdi
callq 0x90ae0
movq 0x78(%rsp), %rcx
movq %rax, 0x48(%rcx)
movq %rax, 0x70(%rsp)
movq 0x78(%rsp), %rdi
addq $0x40, %rdi
callq 0x90ae0
movq %rax, 0x98(%rsp)
movl $0x1, %edi
callq 0x96180
movq 0x70(%rsp), %rax
cmpq 0x98(%rsp), %rax
jne 0xda816
jmp 0xda835
leaq 0xbe9b(%rip), %rdi      # 0xe66b8
leaq 0xbccb(%rip), %rsi      # 0xe64ef
movl $0x1cb, %edx            # imm = 0x1CB
leaq 0xbea8(%rip), %rcx      # 0xe66d8
callq 0x90c40
movq 0x70(%rsp), %rcx
movq 0x78(%rsp), %rax
movq %rcx, 0x48(%rax)
movq 0x78(%rsp), %rax
movq 0x88(%rax), %rax
movq 0x98(%rsp), %rdx
movq %rdx, %rcx
shlq $0x7, %rcx
leaq (%rcx,%rdx,8), %rcx
addq %rcx, %rax
movq %rax, 0x68(%rsp)
movq 0x68(%rsp), %rax
movq 0xc0(%rsp), %rcx
movq 0x80(%rcx), %rdx
movq %rdx, 0x80(%rax)
vmovdqu64 (%rcx), %zmm0
vmovdqu64 0x40(%rcx), %zmm1
vmovdqu64 %zmm1, 0x40(%rax)
vmovdqu64 %zmm0, (%rax)
movq 0x98(%rsp), %rax
incq %rax
movq 0x78(%rsp), %rcx
movq 0x90(%rcx), %rcx
andq %rcx, %rax
movq %rax, 0x60(%rsp)
movq 0x78(%rsp), %rdi
addq $0x40, %rdi
leaq 0x60(%rsp), %rsi
vzeroupper
callq 0x8e440
jmp 0xda8d6
movl $0x2, %edi
callq 0x96180
movq 0x38(%rsp), %rdi
addq $0x40, %rdi
leaq 0x78(%rsp), %rsi
callq 0x8d1c0
jmp 0xdaa79
movq 0x38(%rsp), %rax
cmpq $0x200, 0x48(%rax)      # imm = 0x200
jb 0xda917
movq 0x38(%rsp), %rax
movq 0x48(%rax), %rax
movq %rax, 0x18(%rsp)
jmp 0xda928
movq 0x38(%rsp), %rax
movq 0x48(%rax), %rax
shlq %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x58(%rsp), %rdi
callq 0x96d30
movq %rax, 0x10(%rsp)
jmp 0xda943
movq 0x10(%rsp), %rax
movq %rax, 0x50(%rsp)
cmpq $0x0, 0x50(%rsp)
jne 0xda96a
movb $0x0, 0xd7(%rsp)
movl $0x1, 0x4c(%rsp)
jmp 0xdaa8b
movq 0x38(%rsp), %rax
movq 0x58(%rsp), %rcx
movq %rcx, 0x48(%rax)
movq 0x50(%rsp), %rax
movq 0x88(%rax), %rax
movq 0xc0(%rsp), %rcx
movq 0x80(%rcx), %rdx
movq %rdx, 0x80(%rax)
vmovdqu64 (%rcx), %zmm0
vmovdqu64 0x40(%rcx), %zmm1
vmovdqu64 %zmm1, 0x40(%rax)
vmovdqu64 %zmm0, (%rax)
movq 0x50(%rsp), %rdi
vzeroupper
callq 0x99670
movq %rax, 0x8(%rsp)
jmp 0xda9c8
movq 0x8(%rsp), %rax
cmpq $0x0, %rax
jne 0xda9d5
jmp 0xda9f4
leaq 0xbdeb(%rip), %rdi      # 0xe67c7
leaq 0xbb0c(%rip), %rsi      # 0xe64ef
movl $0x1e2, %edx            # imm = 0x1E2
leaq 0xbce9(%rip), %rcx      # 0xe66d8
callq 0x90c40
movq 0x50(%rsp), %rax
movq %rax, %rsi
addq $0x8, %rsi
movq $0x1, 0x8(%rax)
movq 0x50(%rsp), %rdi
addq $0x40, %rdi
callq 0x8e530
jmp 0xdaa18
movq 0xb0(%rsp), %rdi
subq $-0x80, %rdi
callq 0x8f2c0
movq %rax, 0x40(%rsp)
movq 0x50(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x40(%rsp), %rsi
callq 0x93a90
jmp 0xdaa43
movq 0xb0(%rsp), %rdi
addq $0x80, %rdi
leaq 0x50(%rsp), %rsi
callq 0x8d1c0
movl $0x2, %edi
callq 0x96180
movq 0x38(%rsp), %rdi
addq $0x40, %rdi
leaq 0x50(%rsp), %rsi
callq 0x8d1c0
jmp 0xdaa7b
movb $0x1, 0xd7(%rsp)
movl $0x1, 0x4c(%rsp)
leaq 0xb8(%rsp), %rdi
callq 0x961e0
movb 0xd7(%rsp), %al
andb $0x1, %al
addq $0xd8, %rsp
retq
movq 0x88(%rsp), %rdi
callq 0x981c0
nopw %cs:(%rax,%rax)