// File: /workspace/github_cpp_makefile_star2_O1/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 %rdx, %r14
movq %rdi, %rbp
movq (%rsi), %r12
movq 0x8(%rsi), %r15
movq %rsi, 0x20(%rsp)
movq 0x10(%rsi), %r13
cmpq (%rdx), %r12
movq %rdx, 0x8(%rsp)
movq %rdi, 0x18(%rsp)
je 0x63ef7
movq 0x18(%r12), %rax
movzwl (%rax), %ecx
leaq (%rcx,%rcx,4), %rcx
shll $0x3, %ecx
addq 0x10(%r12), %rcx
cmpq %rcx, %r15
je 0x63de0
movzwl 0x32(%r12), %ecx
movq %rbp, %rdx
leaq (%rax,%rcx,2), %rbp
leaq 0x48(%rdx), %rbx
xorl %r14d, %r14d
movq (%r15), %rdi
leaq 0x10(%r15), %rax
cmpq %rax, %rdi
je 0x63c51
callq 0x41a0
movq %rbx, %rdi
movq %r15, %rsi
callq 0x62b3e
movzwl 0x2(%r13), %eax
leaq (%rax,%rax,4), %rcx
leaq 0x28(%r15,%rcx,8), %r15
leaq 0x2(%r13,%rax,2), %r13
incl %r14d
cmpq %rbp, %r13
jne 0x63c40
subw %r14w, 0x30(%r12)
movzwl %r14w, %eax
movq 0x18(%rsp), %rcx
subq %rax, 0x38(%rcx)
movq 0x20(%rsp), %rax
movq 0x10(%rax), %rsi
movzwl -0x2(%rsi), %ecx
xorl %edx, %edx
testl %ecx, %ecx
sete %dl
movl %ebp, %edi
subl %esi, %edi
shrl %edi
leal (%rcx,%rdi), %r8d
leal (%rcx,%rcx), %r9d
leaq (%rsi,%rdx,2), %rax
subq %r9, %rsi
movw %r8w, (%rsi)
cmpw $0x1, %cx
adcl $0x0, %ecx
subl %edx, %edi
movzwl %di, %edx
cmpl $0x4, %edx
jb 0x63cfc
vmovq 0x54c90(%rip), %xmm0    # 0xb8960
movq 0x8(%rsp), %r14
vpbroadcastw %ecx, %xmm1
vpaddw %xmm0, %xmm1, %xmm1
vmovq %xmm1, (%rax)
addq $0x8, %rax
addl $0xfffc, %edx           # imm = 0xFFFC
movzwl %dx, %edx
vpextrw $0x3, %xmm1, %ecx
cmpl $0x3, %edx
ja 0x63cd5
jmp 0x63d01
movq 0x8(%rsp), %r14
cmpq %rbp, %rax
je 0x63dd6
subq %rax, %rbp
addq $-0x2, %rbp
vpbroadcastq %rbp, %zmm1
shrq %rbp
andq $-0x20, %rbp
vpbroadcastw %ecx, %zmm0
vpaddw 0x53c92(%rip), %zmm0, %zmm0 # 0xb79c0
vpsrlq $0x1, %zmm1, %zmm1
addq $0x20, %rbp
xorl %ecx, %ecx
vpmovsxbq 0x54ab3(%rip), %zmm2 # 0xb87f8
vpmovsxbq 0x54ab1(%rip), %zmm3 # 0xb8800
vpmovsxbq 0x54aaf(%rip), %zmm4 # 0xb8808
vpmovsxbq 0x54a8d(%rip), %zmm5 # 0xb87f0
vpternlogd $0xff, %zmm6, %zmm6, %zmm6
vpbroadcastw 0x53d8c(%rip), %zmm7 # 0xb7b00
vpbroadcastq %rcx, %zmm8
vporq %zmm2, %zmm8, %zmm9
vporq %zmm3, %zmm8, %zmm10
vporq %zmm4, %zmm8, %zmm11
vporq %zmm5, %zmm8, %zmm8
vpcmpleuq %zmm1, %zmm8, %k0
vpcmpleuq %zmm1, %zmm11, %k1
kunpckbw %k0, %k1, %k0
vpcmpleuq %zmm1, %zmm10, %k1
vpcmpleuq %zmm1, %zmm9, %k2
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vpsubw %zmm6, %zmm0, %zmm8
vmovdqu16 %zmm8, (%rax,%rcx,2) {%k1}
addq $0x20, %rcx
vpaddw %zmm7, %zmm0, %zmm0
cmpq %rcx, %rbp
jne 0x63d74
movq 0x8(%r12), %r12
movq 0x18(%rsp), %rbp
movq 0x20(%r12), %rbx
movq (%r14), %rax
cmpq %rax, %r12
je 0x63e9c
movq (%r12), %r14
movq 0x18(%r12), %rax
movzwl (%rax), %ecx
leaq (%rcx,%rcx,4), %r15
shll $0x3, %r15d
addq 0x10(%r12), %r15
leaq (%rax,%rcx,2), %r13
movq (%r15), %rdi
leaq 0x10(%r15), %rax
cmpq %rax, %rdi
je 0x63e22
vzeroupper
callq 0x41a0
movzwl 0x2(%r13), %eax
leaq (%rax,%rax,4), %rcx
leaq 0x28(%r15,%rcx,8), %r15
leaq 0x2(%r13,%rax,2), %r13
cmpq %r14, %r15
jne 0x63e0e
movl (%r12), %eax
subl 0x10(%r12), %eax
shrl $0x3, %eax
imull $0xffffcccd, %eax, %eax # imm = 0xFFFFCCCD
cmpw %ax, 0x30(%r12)
je 0x63e62
movq %rbp, %rdi
movq %r12, %rsi
vzeroupper
callq 0x62c6a
movzwl 0x30(%r12), %eax
subq %rax, 0x38(%rbp)
movq 0x8(%r12), %r13
movq 0x10(%r12), %rdi
vzeroupper
callq 0x41a0
movq %r12, %rdi
callq 0x41a0
movq 0x8(%rsp), %r14
movq (%r14), %rax
movq %r13, %r12
cmpq %rax, %r13
jne 0x63df1
jmp 0x63e9f
movq %r12, %r13
movq 0x18(%r13), %rcx
movzwl (%rcx), %edx
leaq (%rdx,%rdx,4), %r15
shll $0x3, %r15d
addq 0x10(%r13), %r15
movq %rbx, 0x20(%r13)
testq %rbx, %rbx
je 0x63ec1
movq %r13, 0x8(%rbx)
jmp 0x63ed4
movq %r13, 0x30(%rbp)
movq %rax, 0x18(%rbp)
vmovdqu 0x8(%r14), %xmm0
vmovdqu %xmm0, 0x20(%rbp)
movq 0x18(%rax), %rsi
movzwl (%rsi), %esi
leaq (%rsi,%rsi,4), %rsi
shll $0x3, %esi
addq 0x10(%rax), %rsi
cmpq 0x8(%r14), %rsi
je 0x6419b
movq %r13, %r12
leaq (%rcx,%rdx,2), %r13
movq 0x8(%r14), %rax
movq %r12, 0x10(%rsp)
cmpq (%r12), %rax
jne 0x63f26
movq 0x10(%rsp), %rcx
movq 0x18(%rcx), %rax
movzwl (%rax), %eax
leaq (%rax,%rax,4), %rax
shll $0x3, %eax
addq 0x10(%rcx), %rax
cmpq %rax, %r15
je 0x64044
leaq 0x48(%rbp), %r12
xorl %r14d, %r14d
movq %r15, %rbp
movq %r13, %rbx
movq (%rbp), %rdi
leaq 0x10(%rbp), %rax
cmpq %rax, %rdi
je 0x63f48
vzeroupper
callq 0x41a0
movq %r12, %rdi
movq %rbp, %rsi
vzeroupper
callq 0x62b3e
movzwl 0x2(%rbx), %eax
leaq (%rax,%rax,4), %rcx
leaq 0x28(%rbp,%rcx,8), %rbp
leaq 0x2(%rbx,%rax,2), %rbx
incl %r14d
movq 0x8(%rsp), %rax
movq 0x8(%rax), %rax
cmpq %rax, %rbp
jne 0x63f33
movzwl %r14w, %ecx
movq 0x18(%rsp), %r10
subq %rcx, 0x38(%r10)
movq 0x10(%rsp), %rdx
subw %cx, 0x30(%rdx)
xorl %ecx, %ecx
cmpq %r13, 0x18(%rdx)
setne %cl
addl %ecx, %ecx
movq %r13, %rdx
subq %rcx, %rdx
movzwl (%rdx), %edx
xorl %esi, %esi
testl %edx, %edx
sete %sil
movq %rax, %rcx
subq %r15, %rcx
shrq $0x3, %rcx
imull $0xcccccccd, %ecx, %edi # imm = 0xCCCCCCCD
leal (%rdx,%rdi), %ecx
leal (%rdx,%rdx), %r8d
movq %r13, %r9
subq %r8, %r9
movw %cx, (%r9)
cmpw $0x1, %dx
adcl $0x0, %edx
leaq (%r13,%rsi,2), %rcx
subl %esi, %edi
movzwl %di, %esi
cmpl $0x4, %esi
jb 0x6409c
vmovq 0x54972(%rip), %xmm0    # 0xb8960
movq 0x8(%rsp), %r8
vpbroadcastw %edx, %xmm1
vpaddw %xmm0, %xmm1, %xmm1
vmovq %xmm1, (%rcx)
addq $0x8, %rcx
addl $0xfffc, %esi           # imm = 0xFFFC
movzwl %si, %esi
vpextrw $0x3, %xmm1, %edx
cmpl $0x3, %esi
ja 0x63ff3
jmp 0x640a1
movq (%r15), %rdi
leaq 0x10(%r15), %rax
cmpq %rax, %rdi
je 0x64031
vzeroupper
callq 0x41a0
movzwl 0x2(%r13), %eax
leaq (%rax,%rax,4), %rcx
leaq 0x28(%r15,%rcx,8), %r15
leaq 0x2(%r13,%rax,2), %r13
cmpq 0x8(%r14), %r15
jne 0x6401d
movq 0x10(%rsp), %r14
movzwl 0x30(%r14), %eax
subq %rax, 0x38(%rbp)
jne 0x641ad
xorl %ebx, %ebx
movq %rbx, 0x30(%rbp)
movq %rbp, %rdi
vzeroupper
callq 0x1a796
leaq 0x48(%rbp), %rdi
callq 0x1a85a
movq %rbx, 0x68(%rbp)
vpxor %xmm0, %xmm0, %xmm0
vmovdqu %xmm0, 0x58(%rbp)
movq %rbx, 0x38(%rbp)
vpxor %xmm0, %xmm0, %xmm0
vmovdqu %ymm0, (%rbp)
vmovdqu %ymm0, 0x10(%rbp)
jmp 0x641f5
movq 0x8(%rsp), %r8
movq 0x10(%r8), %rsi
cmpq %rsi, %rcx
je 0x6417d
movq %rsi, %rdi
subq %rcx, %rdi
addq $-0x2, %rdi
vpbroadcastq %rdi, %zmm1
shrq %rdi
andq $-0x20, %rdi
vpbroadcastw %edx, %zmm0
vpaddw 0x538eb(%rip), %zmm0, %zmm0 # 0xb79c0
vpsrlq $0x1, %zmm1, %zmm1
addq $0x20, %rdi
xorl %edx, %edx
vpmovsxbq 0x5470c(%rip), %zmm2 # 0xb87f8
vpmovsxbq 0x5470a(%rip), %zmm3 # 0xb8800
vpmovsxbq 0x54708(%rip), %zmm4 # 0xb8808
vpmovsxbq 0x546e6(%rip), %zmm5 # 0xb87f0
vpternlogd $0xff, %zmm6, %zmm6, %zmm6
vpbroadcastw 0x539e5(%rip), %zmm7 # 0xb7b00
vpbroadcastq %rdx, %zmm8
vporq %zmm2, %zmm8, %zmm9
vporq %zmm3, %zmm8, %zmm10
vporq %zmm4, %zmm8, %zmm11
vporq %zmm5, %zmm8, %zmm8
vpcmpleuq %zmm1, %zmm8, %k0
vpcmpleuq %zmm1, %zmm11, %k1
kunpckbw %k0, %k1, %k0
vpcmpleuq %zmm1, %zmm10, %k1
vpcmpleuq %zmm1, %zmm9, %k2
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vpsubw %zmm6, %zmm0, %zmm8
vmovdqu16 %zmm8, (%rcx,%rdx,2) {%k1}
addq $0x20, %rdx
vpaddw %zmm7, %zmm0, %zmm0
cmpq %rdx, %rdi
jne 0x6411b
movq 0x20(%rsp), %rcx
movq 0x8(%rcx), %rcx
cmpq 0x20(%r10), %rcx
jne 0x6419b
movq (%r8), %rcx
movq %rcx, 0x18(%r10)
movq %rax, 0x20(%r10)
movq %rsi, 0x28(%r10)
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq
movq 0x20(%r14), %rcx
movq $0x0, 0x8(%rcx)
movq %rcx, (%rbp)
movq (%rcx), %rdx
movq %rdx, 0x8(%rbp)
movzwl 0x32(%rcx), %edx
addl %edx, %edx
addq 0x18(%rcx), %rdx
movq %rdx, 0x10(%rbp)
movl (%r14), %ecx
subl 0x10(%r14), %ecx
shrl $0x3, %ecx
imull $0xffffcccd, %ecx, %ecx # imm = 0xFFFFCCCD
cmpw %cx, %ax
je 0x641f5
movq %rbp, %rdi
movq %r14, %rsi
vzeroupper
callq 0x62c6a
movq 0x10(%r14), %rdi
vzeroupper
callq 0x41a0
movq %r14, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x41a0