// File: HQarroum[P]thread-pool/examples/one-producer-many-consumers/./../../includes/concurrent_queue.hpp
// Function: moodycamel::ConcurrentQueue<std::function<void ()>, moodycamel::ConcurrentQueueDefaultTraits>::ImplicitProducer::~ImplicitProducer()
~ImplicitProducer()
		{
			// Note that since we're in the destructor we can assume that all enqueue/dequeue operations
			// completed already; this means that all undequeued elements are placed contiguously across
			// contiguous blocks, and that only the first and last remaining blocks can be only partially
			// empty (all other remaining blocks must be completely full).
			
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
			// Unregister ourselves for thread termination notification
			if (!this->inactive.load(std::memory_order_relaxed)) {
				details::ThreadExitNotifier::unsubscribe(&threadExitListener);
			}
#endif
			
			// Destroy all remaining elements!
			auto tail = this->tailIndex.load(std::memory_order_relaxed);
			auto index = this->headIndex.load(std::memory_order_relaxed);
			Block* block = nullptr;
			assert(index == tail || details::circular_less_than(index, tail));
			bool forceFreeLastBlock = index != tail;		// If we enter the loop, then the last (tail) block will not be freed
			while (index != tail) {
				if ((index & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 || block == nullptr) {
					if (block != nullptr) {
						// Free the old block
						this->parent->add_block_to_free_list(block);
					}
					
					block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed);
				}
				
				((*block)[index])->~T();
				++index;
			}
			// Even if the queue is empty, there's still one block that's not on the free list
			// (unless the head index reached the end of it, in which case the tail will be poised
			// to create a new block).
			if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast<index_t>(BLOCK_SIZE - 1)) != 0)) {
				this->parent->add_block_to_free_list(this->tailBlock);
			}
			
			// Destroy block index
			auto localBlockIndex = blockIndex.load(std::memory_order_relaxed);
			if (localBlockIndex != nullptr) {
				for (size_t i = 0; i != localBlockIndex->capacity; ++i) {
					localBlockIndex->index[i]->~BlockIndexEntry();
				}
				do {
					auto prev = localBlockIndex->prev;
					localBlockIndex->~BlockIndexHeader();
					(Traits::free)(localBlockIndex);
					localBlockIndex = prev;
				} while (localBlockIndex != nullptr);
			}
		}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x38(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x88(%rbp)
leaq 0xe9df(%rip), %rcx      # 0x23d10
movq %rcx, (%rax)
addq $0x20, %rax
movq %rax, -0x8(%rbp)
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x80(%rbp)
movl -0xc(%rbp), %edi
movl $0xffff, %esi           # imm = 0xFFFF
callq 0x58d0
movl %eax, -0x10(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x74(%rbp)
decl %eax
subl $0x2, %eax
jb 0x15381
jmp 0x1536a
movl -0x74(%rbp), %eax
subl $0x5, %eax
je 0x1538e
jmp 0x15374
movq -0x80(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
jmp 0x15399
movq -0x80(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
jmp 0x15399
movq -0x80(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x88(%rbp), %rax
movq -0x18(%rbp), %rcx
movq %rcx, -0x40(%rbp)
addq $0x28, %rax
movq %rax, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x98(%rbp)
movl -0x24(%rbp), %edi
movl $0xffff, %esi           # imm = 0xFFFF
callq 0x58d0
movl %eax, -0x28(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0x8c(%rbp)
decl %eax
subl $0x2, %eax
jb 0x15401
jmp 0x153e4
movl -0x8c(%rbp), %eax
subl $0x5, %eax
je 0x15411
jmp 0x153f1
movq -0x98(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x1541f
movq -0x98(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x1541f
movq -0x98(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x48(%rbp)
movq $0x0, -0x50(%rbp)
movq -0x48(%rbp), %rcx
movb $0x1, %al
cmpq -0x40(%rbp), %rcx
movb %al, -0x99(%rbp)
je 0x15454
movq -0x48(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x3800
movb %al, -0x99(%rbp)
movb -0x99(%rbp), %al
testb $0x1, %al
jne 0x15460
jmp 0x15462
jmp 0x15481
leaq 0x39ec(%rip), %rdi      # 0x18e55
leaq 0x2f36(%rip), %rsi      # 0x183a6
movl $0x982, %edx            # imm = 0x982
leaq 0x3a13(%rip), %rcx      # 0x18e8f
callq 0x3180
movq -0x48(%rbp), %rax
cmpq -0x40(%rbp), %rax
setne %al
andb $0x1, %al
movb %al, -0x51(%rbp)
movq -0x48(%rbp), %rax
cmpq -0x40(%rbp), %rax
je 0x15528
movq -0x48(%rbp), %rax
andq $0x1f, %rax
cmpq $0x0, %rax
je 0x154b4
cmpq $0x0, -0x50(%rbp)
jne 0x15502
cmpq $0x0, -0x50(%rbp)
je 0x154d3
movq -0x88(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x50(%rbp), %rsi
callq 0xb130
jmp 0x154d1
jmp 0x154d3
movq -0x88(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x156d0
movq %rax, -0xa8(%rbp)
jmp 0x154ec
movq -0xa8(%rbp), %rdi
addq $0x8, %rdi
xorl %esi, %esi
callq 0x6210
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0xa830
movq %rax, %rdi
callq 0x6fc0
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
jmp 0x15491
movq -0x88(%rbp), %rax
cmpq $0x0, 0x40(%rax)
je 0x15562
testb $0x1, -0x51(%rbp)
jne 0x1554a
movq -0x40(%rbp), %rax
andq $0x1f, %rax
cmpq $0x0, %rax
je 0x15562
movq -0x88(%rbp), %rax
movq 0x40(%rax), %rsi
movq 0x50(%rax), %rdi
callq 0xb130
jmp 0x15560
jmp 0x15562
movq -0x88(%rbp), %rdi
addq $0x60, %rdi
xorl %esi, %esi
callq 0xb160
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x60(%rbp)
je 0x155ca
movq $0x0, -0x68(%rbp)
movq -0x68(%rbp), %rax
movq -0x60(%rbp), %rcx
cmpq (%rcx), %rax
je 0x155a2
movq -0x68(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x68(%rbp)
jmp 0x15587
jmp 0x155a4
movq -0x60(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x70(%rbp)
movq -0x60(%rbp), %rdi
callq 0x5cc0
movq -0x70(%rbp), %rax
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x60(%rbp)
jne 0x155a4
jmp 0x155ca
movq -0x88(%rbp), %rdi
callq 0x14c50
addq $0xb0, %rsp
popq %rbp
retq
movq %rax, %rdi
callq 0x4410
nopw (%rax,%rax)