// File: /workspace/github_cpp_makefile_star2_O2/wichtounet[P]articles/plf_colony_alpha/plf_colony.h
// Function: plf::colony<NonTrivialStringMovable, std::allocator<NonTrivialStringMovable>, unsigned short>::erase(plf::colony<NonTrivialStringMovable, std::allocator<NonTrivialStringMovable>, unsigned short>::colony_iterator<std::allocator<NonTrivialStringMovable>, true> const&, plf::colony<NonTrivialStringMovable, std::allocator<NonTrivialStringMovable>, unsigned short>::colony_iterator<std::allocator<NonTrivialStringMovable>, true> const&)
void erase(const const_iterator &iterator1, const const_iterator &iterator2)
	{
		assert(iterator1 != iterator2);
		assert(iterator1 < iterator2);

		iterator current = iterator1;

		if (current.group_pointer != iterator2.group_pointer)
		{
			if (current.element_pointer != current.group_pointer->elements + *(current.group_pointer->skipfield)) // if iterator1 is not the first non-erased element in it's group - most common case
			{
				const skipfield_pointer_type end = iterator1.group_pointer->skipfield + iterator1.group_pointer->size;
				skipfield_type number_of_group_erasures = 0;

				// Destroy elements first:
				do
				{
					#ifdef PLF_COLONY_TYPE_TRAITS_SUPPORT
						if (!(std::is_trivially_destructible<element_type>::value))
					#endif
					{
						PLF_COLONY_DESTROY(element_allocator_type, (*this), current.element_pointer); // Destruct element
					}

        			erased_locations.push(current.element_pointer);

					++current.skipfield_pointer;
					current.element_pointer += 1 + *current.skipfield_pointer;
					current.skipfield_pointer += *current.skipfield_pointer;
					++number_of_group_erasures;
				} while (current.skipfield_pointer != end);

				current.group_pointer->number_of_elements -= number_of_group_erasures;
				total_number_of_elements -= number_of_group_erasures;

				// Now update skipfield:
				skipfield_pointer_type current_skipfield = iterator1.skipfield_pointer;
				skipfield_type node_value = *(current_skipfield - 1); // Find value of left-hand node
				skipfield_type update_count = static_cast<skipfield_type>(end - current_skipfield);

				*(current_skipfield - node_value) = node_value + update_count; // Either set current node as the start node, or if previous node is part of a skipblock, update that skipblock's start node and join to that skipblock
				const bool left_node_is_zero = (node_value == 0);
				node_value += left_node_is_zero; // ie. set node_value to 1 if it was zero
				current_skipfield += left_node_is_zero; // Update current_skipfield in while loop below, if the previous node was non-zero
				update_count -= left_node_is_zero;

				// Vectorize the updates:
				while (update_count >= 4)
				{
					*(current_skipfield) = node_value + 1;
					*(current_skipfield + 1) = node_value + 2;
					*(current_skipfield + 2) = node_value + 3;
					*(current_skipfield + 3) = node_value + 4;

					current_skipfield += 4;
					node_value += 4;
					update_count -= 4;
				}

				while (current_skipfield != end)
				{
					*(current_skipfield++) = ++node_value;
				}

				current.group_pointer = current.group_pointer->next_group;
			}


			// Intermediate groups:
			group_pointer_type current_group, previous_group = current.group_pointer->previous_group;

			while (current.group_pointer != iterator2.group_pointer)
			{
				#ifdef PLF_COLONY_TYPE_TRAITS_SUPPORT
					if (!(std::is_trivially_destructible<element_type>::value)) // This should be removed by the compiler
				#endif
				{
					current.element_pointer = current.group_pointer->elements + *(current.group_pointer->skipfield);
					current.skipfield_pointer = current.group_pointer->skipfield + *(current.group_pointer->skipfield);
					const element_pointer_type end = current.group_pointer->last_endpoint;

					do
					{
						PLF_COLONY_DESTROY(element_allocator_type, (*this), current.element_pointer); // Destruct element
						++current.skipfield_pointer;
						current.element_pointer += 1 + *current.skipfield_pointer;
						current.skipfield_pointer += *current.skipfield_pointer;
					} while (current.element_pointer != end);
				}

				if (current.group_pointer->number_of_elements != static_cast<skipfield_type>(current.group_pointer->last_endpoint - current.group_pointer->elements)) // no erasures
				{
					consolidate_erased_locations(current.group_pointer);
				}

				total_number_of_elements -= current.group_pointer->number_of_elements;
				current_group = current.group_pointer;
				current.group_pointer = current.group_pointer->next_group;

				PLF_COLONY_DESTROY(group_allocator_type, group_allocator_pair, current_group);
				PLF_COLONY_DEALLOCATE(group_allocator_type, group_allocator_pair, current_group, 1);
			}

			current.element_pointer = current.group_pointer->elements + *(current.group_pointer->skipfield);
			current.skipfield_pointer = current.group_pointer->skipfield + *(current.group_pointer->skipfield);
			current.group_pointer->previous_group = previous_group;

			if (previous_group != NULL)
			{
				previous_group->next_group = current.group_pointer;
			}
			else
			{
				first_group = current.group_pointer;
				begin_iterator = iterator2; // This line is included here primarily to avoid a secondary if statement within the if block below - it will not be needed in any other situation
			}

			// If iterator2 is right at the start of the final group (if so, there is nothing more to be erased), return:
			if (iterator2.group_pointer->elements + *(iterator2.group_pointer->skipfield) == iterator2.element_pointer)
			{
				return;
			}
		}


		// Final group:
		// Code explanation:
		// If not erasing entire final group, 1. Destruct elements (if non-trivial destructor) and add locations to erased stack. 2. process skipfield.
		// If erasing entire group, 1. Destruct elements (if non-trivial destructor), 2. if no elements left in colony, clear() 3. otherwise reset end_iterator and consolidate_erased_locations if there were some prior erasures in group


		if (iterator2.element_pointer != current.group_pointer->last_endpoint || current.element_pointer != current.group_pointer->elements + *(current.group_pointer->skipfield)) // ie. not erasing entire group
		{
			skipfield_type number_of_group_erasures = 0;

			element_pointer_type current_element = current.element_pointer;
			skipfield_pointer_type current_skipfield = current.skipfield_pointer;

			do
			{
				#ifdef PLF_COLONY_TYPE_TRAITS_SUPPORT
					if (!(std::is_trivially_destructible<element_type>::value)) // This should be removed by the compiler
				#endif
				{
					PLF_COLONY_DESTROY(element_allocator_type, (*this), current_element);
				}

				erased_locations.push(current_element);

				++current_skipfield;
				current_element += 1 + *current_skipfield;
				current_skipfield += *current_skipfield;
				++number_of_group_erasures;
			} while(current_element != iterator2.element_pointer);

			total_number_of_elements -= number_of_group_erasures;
			current.group_pointer->number_of_elements -= number_of_group_erasures;

			// Update skipfield:
			skipfield_type node_value = *(current.skipfield_pointer - (current.group_pointer->skipfield != current.skipfield_pointer)); // Find value of left-hand node - if current node is at start of skipfield, we check the current node instead, which will always be zero.
			skipfield_type update_count = static_cast<skipfield_type>(iterator2.element_pointer - current.element_pointer);

			*(current.skipfield_pointer - node_value) = node_value + update_count; // Either set current node as the start node, or if previous node is part of a skipblock, update that skipblock's start node
			const bool left_node_is_zero = (node_value == 0);
			node_value += left_node_is_zero; // ie. set node_value to 1 if it was zero
			current.skipfield_pointer += left_node_is_zero; // Update current_skipfield in while loop below, if the previous node was non-zero
			update_count -= left_node_is_zero;

			// Vectorize the updates:
			while (update_count >= 4)
			{
				*(current.skipfield_pointer) = node_value + 1;
				*(current.skipfield_pointer + 1) = node_value + 2;
				*(current.skipfield_pointer + 2) = node_value + 3;
				*(current.skipfield_pointer + 3) = node_value + 4;

				current.skipfield_pointer += 4;
				node_value += 4;
				update_count -= 4;
			}

			while (current.skipfield_pointer != iterator2.skipfield_pointer)
			{
				*(current.skipfield_pointer++) = ++node_value;
			}

			if (iterator1.element_pointer == begin_iterator.element_pointer) // Retaining this check for the case when iterator1 and iterator2 have the same group
			{
				begin_iterator = iterator2;
			}
		}
		else // ie. full group erasure
		{
			#ifdef PLF_COLONY_TYPE_TRAITS_SUPPORT
				if (!(std::is_trivially_destructible<element_type>::value)) // This should be removed by the compiler
			#endif
			{
				while(current.element_pointer != iterator2.element_pointer)
				{
					PLF_COLONY_DESTROY(element_allocator_type, (*this), current.element_pointer);
					++current.skipfield_pointer;
					current.element_pointer += 1 + *current.skipfield_pointer;
					current.skipfield_pointer += *current.skipfield_pointer;
				}
			}

			// Note: it is not possible that next_group != NULL at this point (if it were, iterator2.element_pointer could not be == last_endpoint - which indicates that it is == end())

			if ((total_number_of_elements -= current.group_pointer->number_of_elements) != 0) // ie. previous_group != NULL
			{
				current.group_pointer->previous_group->next_group = NULL;
				end_iterator.group_pointer = current.group_pointer->previous_group;
				end_iterator.element_pointer = current.group_pointer->previous_group->last_endpoint;
				end_iterator.skipfield_pointer = current.group_pointer->previous_group->skipfield + current.group_pointer->previous_group->size;

				if (current.group_pointer->number_of_elements != static_cast<skipfield_type>(current.group_pointer->last_endpoint - current.group_pointer->elements)) // ie. some prior erasures exist in group
				{
					consolidate_erased_locations(current.group_pointer);
				}
			}
			else // ie. colony is now empty
			{
				first_group = NULL;
				clear();
			}

			PLF_COLONY_DESTROY(group_allocator_type, group_allocator_pair, current.group_pointer);
			PLF_COLONY_DEALLOCATE(group_allocator_type, group_allocator_pair, current.group_pointer, 1);
		}
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq (%rsi), %r12
movq 0x8(%rsi), %r13
movq 0x10(%rsi), %rbx
movq %rsi, 0x20(%rsp)
movq %rdi, 0x8(%rsp)
movq %rdx, %r15
movq %rdi, %rbp
movq %rdx, 0x18(%rsp)
cmpq (%rdx), %r12
je 0x4b089
movq 0x18(%r12), %rax
movzwl (%rax), %ecx
imulq $0x28, %rcx, %rcx
addq 0x10(%r12), %rcx
cmpq %rcx, %r13
je 0x4afd5
movzwl 0x32(%r12), %ecx
movq %rbp, %rdx
leaq 0x48(%rdx), %r15
xorl %r14d, %r14d
leaq (%rax,%rcx,2), %rbp
movq %r13, %rdi
callq 0x40b0
movq %r15, %rdi
movq %r13, %rsi
callq 0x4a038
movzwl 0x2(%rbx), %eax
incl %r14d
imulq $0x28, %rax, %rcx
leaq 0x2(%rbx,%rax,2), %rbx
leaq 0x28(%r13,%rcx), %r13
cmpq %rbp, %rbx
jne 0x4af15
movq 0x8(%rsp), %rcx
movzwl %r14w, %eax
subw %r14w, 0x30(%r12)
vmovq 0x3e777(%rip), %xmm0    # 0x896d0
movq 0x18(%rsp), %r15
xorl %esi, %esi
movl %ebp, %edx
subq %rax, 0x38(%rcx)
movq 0x20(%rsp), %rax
movq 0x10(%rax), %rdi
movzwl -0x2(%rdi), %eax
testl %eax, %eax
leal (%rax,%rax), %r9d
sete %sil
subl %edi, %edx
shrl %edx
leaq (%rdi,%rsi,2), %rcx
subq %r9, %rdi
cmpw $0x1, %ax
leal (%rax,%rdx), %r8d
adcl $0x0, %eax
subl %esi, %edx
movw %r8w, (%rdi)
movzwl %dx, %edx
cmpl $0x3, %edx
jbe 0x4afc4
vpbroadcastw %eax, %xmm1
addl $-0x4, %edx
vpaddw %xmm0, %xmm1, %xmm1
vmovq %xmm1, (%rcx)
addq $0x8, %rcx
vpextrw $0x3, %xmm1, %eax
jmp 0x4af99
movw %ax, (%rcx)
addq $0x2, %rcx
incl %eax
cmpq %rbp, %rcx
jne 0x4afbd
movq 0x8(%r12), %r12
movq 0x8(%rsp), %rbp
movq 0x20(%r12), %rax
movq %rax, 0x10(%rsp)
movq 0x18(%r12), %rax
movq (%r15), %rcx
movzwl (%rax), %edx
imulq $0x28, %rdx, %r13
addq 0x10(%r12), %r13
leaq (%rax,%rdx,2), %rbx
cmpq %rcx, %r12
je 0x4b070
movq (%r12), %r14
movq %r13, %rdi
callq 0x40b0
movzwl 0x2(%rbx), %eax
imulq $0x28, %rax, %rcx
leaq 0x2(%rbx,%rax,2), %rbx
leaq 0x28(%r13,%rcx), %r13
cmpq %r14, %r13
jne 0x4b000
movq (%r12), %rax
movzwl 0x30(%r12), %ecx
subq 0x10(%r12), %rax
cqto
pushq $0x28
popq %rsi
idivq %rsi
cmpw %ax, %cx
je 0x4b04c
movq %rbp, %rdi
movq %r12, %rsi
callq 0x4a170
movzwl 0x30(%r12), %ecx
movzwl %cx, %eax
movq %r12, %rdi
subq %rax, 0x38(%rbp)
movq 0x8(%r12), %rbx
callq 0x14d9a
movq %r12, %rdi
callq 0x4180
movq %rbx, %r12
jmp 0x4afdf
movq 0x10(%rsp), %rax
movq %rax, 0x20(%r12)
testq %rax, %rax
je 0x4b08f
movq %r12, 0x8(%rax)
movq 0x8(%r15), %rax
jmp 0x4b0a6
movq 0x8(%r15), %rax
jmp 0x4b0be
movq %r12, 0x30(%rbp)
movq %rcx, 0x18(%rbp)
vmovdqu 0x8(%r15), %xmm0
movq 0x8(%r15), %rax
vmovdqu %xmm0, 0x20(%rbp)
movq 0x18(%rcx), %rdx
movzwl (%rdx), %edx
imulq $0x28, %rdx, %rdx
addq 0x10(%rcx), %rdx
cmpq %rax, %rdx
je 0x4b231
cmpq (%r12), %rax
jne 0x4b0de
movq 0x18(%r12), %rcx
movzwl (%rcx), %ecx
imulq $0x28, %rcx, %rcx
addq 0x10(%r12), %rcx
cmpq %rcx, %r13
je 0x4b1d5
leaq 0x48(%rbp), %rax
xorl %r14d, %r14d
movq %r13, %rbp
movq %rbx, %r15
movq %rax, 0x10(%rsp)
movq %rbp, %rdi
callq 0x40b0
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
callq 0x4a038
movzwl 0x2(%r15), %eax
incl %r14d
imulq $0x28, %rax, %rcx
leaq 0x2(%r15,%rax,2), %r15
leaq 0x28(%rcx,%rbp), %rbp
movq 0x18(%rsp), %rcx
movq 0x8(%rcx), %rcx
cmpq %rcx, %rbp
jne 0x4b0f0
movq 0x8(%rsp), %rdx
movzwl %r14w, %eax
subq %rax, 0x38(%rdx)
subw %ax, 0x30(%r12)
xorl %eax, %eax
movq %rbx, %rdx
cmpq %rbx, 0x18(%r12)
setne %al
xorl %edi, %edi
addl %eax, %eax
subq %rax, %rdx
movzwl (%rdx), %esi
testl %esi, %esi
sete %dil
subq %r13, %rbp
movq %rbp, %rax
cqto
pushq $0x28
popq %r8
idivq %r8
vmovq 0x3e560(%rip), %xmm0    # 0x896d0
leal (%rsi,%rsi), %r8d
movq %rbx, %r9
subq %r8, %r9
movq 0x18(%rsp), %r8
cmpw $0x1, %si
leal (%rsi,%rax), %edx
adcl $0x0, %esi
subl %edi, %eax
movw %dx, (%r9)
leaq (%rbx,%rdi,2), %rdx
movzwl %ax, %eax
cmpl $0x3, %eax
jbe 0x4b1f8
vpbroadcastw %esi, %xmm1
addl $-0x4, %eax
vpaddw %xmm0, %xmm1, %xmm1
vmovq %xmm1, (%rdx)
addq $0x8, %rdx
vpextrw $0x3, %xmm1, %esi
jmp 0x4b193
movq %r13, %rdi
callq 0x40b0
movzwl 0x2(%rbx), %eax
imulq $0x28, %rax, %rcx
leaq 0x2(%rbx,%rax,2), %rbx
movq 0x8(%r15), %rax
leaq 0x28(%r13,%rcx), %r13
cmpq %rax, %r13
jne 0x4b1b7
movzwl 0x30(%r12), %ecx
subq %rcx, 0x38(%rbp)
jne 0x4b240
andq $0x0, 0x30(%rbp)
movq %rbp, %rdi
callq 0x14ce6
jmp 0x4b284
movq 0x10(%r8), %rax
movq 0x8(%rsp), %rdi
incl %esi
cmpq %rax, %rdx
je 0x4b213
movw %si, (%rdx)
addq $0x2, %rdx
incl %esi
jmp 0x4b203
movq 0x20(%rsp), %rdx
movq 0x8(%rdx), %rdx
cmpq 0x20(%rdi), %rdx
jne 0x4b231
movq (%r8), %rdx
movq %rdx, 0x18(%rdi)
movq %rcx, 0x20(%rdi)
movq %rax, 0x28(%rdi)
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x20(%r12), %rax
andq $0x0, 0x8(%rax)
movq %rax, (%rbp)
movq (%rax), %rdx
movq %rdx, 0x8(%rbp)
movzwl 0x32(%rax), %edx
addl %edx, %edx
addq 0x18(%rax), %rdx
movq %rdx, 0x10(%rbp)
movq (%r12), %rax
subq 0x10(%r12), %rax
cqto
pushq $0x28
popq %rsi
idivq %rsi
cmpw %ax, %cx
je 0x4b284
movq %rbp, %rdi
movq %r12, %rsi
callq 0x4a170
movq %r12, %rdi
callq 0x14d9a
movq %r12, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x4180