// File: /workspace/github_cpp_makefile_star2_O2/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:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
movq %rsi, %r14
leaq 0x50(%rdi), %rsi
movq %rdi, %rbx
movq %rsp, %rdi
callq 0x31720
movq 0x40(%rbx), %r12
movq 0x48(%r12), %rdx
movq 0x40(%r12), %rcx
leaq 0x1(%rcx), %rax
andq 0x90(%r12), %rax
cmpq %rdx, %rax
jne 0x46645
movq (%r12), %rsi
movq %rsi, 0x48(%r12)
cmpq %rsi, %rdx
jne 0x46645
movq 0x80(%r12), %rax
movq (%rbx), %rcx
cmpq %rcx, %rax
jne 0x46686
movq 0x48(%rbx), %rax
cmpq $0x200, %rax            # imm = 0x200
setb %cl
shlxq %rcx, %rax, %r15
movq %r15, %rdi
callq 0x32ea0
testq %rax, %rax
je 0x46705
movq %r15, 0x48(%rbx)
movq 0x88(%rax), %rcx
movq 0x80(%r14), %rdx
movq %rdx, 0x80(%rcx)
vmovups (%r14), %zmm0
vmovups 0x40(%r14), %zmm1
vmovups %zmm1, 0x40(%rcx)
vmovups %zmm0, (%rcx)
movq (%rax), %rcx
testq %rcx, %rcx
jne 0x46728
movq $0x1, 0x8(%rax)
movq $0x1, 0x40(%rax)
movq 0x80(%r12), %rcx
movq %rcx, 0x80(%rax)
movq %rax, 0x80(%r12)
jmp 0x466e9
movq 0x88(%r12), %rdx
movq 0x80(%r14), %rsi
imulq $0x88, %rcx, %rcx
movq %rsi, 0x80(%rdx,%rcx)
vmovups (%r14), %zmm0
vmovups 0x40(%r14), %zmm1
vmovups %zmm1, 0x40(%rdx,%rcx)
vmovups %zmm0, (%rdx,%rcx)
movq %rax, 0x40(%r12)
jmp 0x466ed
movq 0x80(%r12), %rax
movq (%rax), %rcx
movq %rcx, 0x48(%rax)
movq 0x40(%rax), %rdx
cmpq %rdx, %rcx
jne 0x46709
movq %rcx, 0x48(%rax)
imulq $0x88, %rcx, %rsi
incq %rcx
movq 0x88(%rax), %rdx
movq 0x80(%r14), %rdi
movq %rdi, 0x80(%rdx,%rsi)
vmovups (%r14), %zmm0
vmovups 0x40(%r14), %zmm1
vmovups %zmm1, 0x40(%rdx,%rsi)
vmovups %zmm0, (%rdx,%rsi)
andq 0x90(%rax), %rcx
movq %rcx, 0x40(%rax)
movq %rax, 0x40(%rbx)
movb $0x1, %al
movq (%rsp), %rcx
movb $0x0, (%rcx)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
vzeroupper
retq
xorl %eax, %eax
jmp 0x466ef
leaq 0x5c48(%rip), %rdi      # 0x4c358
leaq 0x5af2(%rip), %rsi      # 0x4c209
leaq 0x5c5a(%rip), %rcx      # 0x4c378
movl $0x1cb, %edx            # imm = 0x1CB
callq 0x31260
leaq 0x5d38(%rip), %rdi      # 0x4c467
leaq 0x5ad3(%rip), %rsi      # 0x4c209
leaq 0x5c3b(%rip), %rcx      # 0x4c378
movl $0x1e2, %edx            # imm = 0x1E2
vzeroupper
callq 0x31260
movq (%rsp), %rcx
movq %rax, %rdi
movb $0x0, (%rcx)
callq 0x33510
nop