// File: /workspace/github_cpp_makefile_star2_O3/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), %r15
movq 0x8(%rsi), %r13
movq 0x10(%rsi), %r12
movq (%rdx), %rcx
movq %rsi, 0x18(%rsp)
movq %rdx, 0x8(%rsp)
movq %rdx, %r14
movq %rdi, %rbp
movq %rdi, 0x10(%rsp)
cmpq %rcx, %r15
je 0x636d2
movq 0x18(%r15), %rax
movzwl (%rax), %edx
leaq (%rdx,%rdx,4), %rdx
shll $0x3, %edx
addq 0x10(%r15), %rdx
cmpq %rdx, %r13
je 0x636db
movzwl 0x32(%r15), %ecx
movq %rbp, %rdx
movq %r15, %rbx
leaq 0x48(%rdx), %r15
xorl %r14d, %r14d
leaq (%rax,%rcx,2), %rbp
movq (%r13), %rdi
leaq 0x10(%r13), %rax
cmpq %rax, %rdi
je 0x63627
callq 0x41a0
movq %r15, %rdi
movq %r13, %rsi
callq 0x624ec
movzwl 0x2(%r12), %eax
incl %r14d
leaq (%rax,%rax,4), %rcx
leaq 0x2(%r12,%rax,2), %r12
leaq 0x28(%r13,%rcx,8), %r13
cmpq %rbp, %r12
jne 0x63615
movq 0x10(%rsp), %rcx
movzwl %r14w, %eax
subw %r14w, 0x30(%rbx)
xorl %edx, %edx
movl %ebp, %edi
subq %rax, 0x38(%rcx)
movq 0x18(%rsp), %rcx
movq 0x10(%rcx), %rsi
movzwl -0x2(%rsi), %ecx
testl %ecx, %ecx
leal (%rcx,%rcx), %r9d
sete %dl
subl %esi, %edi
shrl %edi
leaq (%rsi,%rdx,2), %rax
subq %r9, %rsi
cmpw $0x1, %cx
leal (%rcx,%rdi), %r8d
adcl $0x0, %ecx
subl %edx, %edi
movzwl %di, %edx
movw %r8w, (%rsi)
cmpl $0x4, %edx
jb 0x636e3
vmovq 0x5417a(%rip), %xmm0    # 0xb7820
movq 0x8(%rsp), %r14
vpbroadcastw %ecx, %xmm1
addl $0xfffc, %edx           # imm = 0xFFFC
vpaddw %xmm0, %xmm1, %xmm1
movzwl %dx, %edx
vmovq %xmm1, (%rax)
addq $0x8, %rax
vpextrw $0x3, %xmm1, %ecx
cmpl $0x3, %edx
ja 0x636ab
jmp 0x636e8
movq 0x8(%r14), %rax
jmp 0x638e2
movq %r15, %r13
jmp 0x637c9
movq 0x8(%rsp), %r14
cmpq %rbp, %rax
je 0x637bd
vpbroadcastw %ecx, %zmm0
vpaddw 0x5313f(%rip), %zmm0, %zmm0 # 0xb6840
vpmovsxbq 0x53fad(%rip), %zmm2 # 0xb76b8
vpmovsxbq 0x53fab(%rip), %zmm3 # 0xb76c0
vpmovsxbq 0x53fa9(%rip), %zmm4 # 0xb76c8
vpmovsxbq 0x53f87(%rip), %zmm5 # 0xb76b0
vpbroadcastw 0x5324d(%rip), %zmm7 # 0xb6980
subq %rax, %rbp
vpternlogd $0xff, %zmm6, %zmm6, %zmm6
xorl %ecx, %ecx
addq $-0x2, %rbp
vpbroadcastq %rbp, %zmm1
shrq %rbp
andq $-0x20, %rbp
vpsrlq $0x1, %zmm1, %zmm1
addq $0x20, %rbp
vpbroadcastq %rcx, %zmm8
vporq %zmm2, %zmm8, %zmm9
vporq %zmm4, %zmm8, %zmm11
vporq %zmm3, %zmm8, %zmm10
vporq %zmm5, %zmm8, %zmm8
vpcmpleuq %zmm1, %zmm8, %k0
vpcmpleuq %zmm1, %zmm11, %k1
vpcmpleuq %zmm1, %zmm9, %k2
vpsubw %zmm6, %zmm0, %zmm8
vpaddw %zmm7, %zmm0, %zmm0
kunpckbw %k0, %k1, %k0
vpcmpleuq %zmm1, %zmm10, %k1
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vmovdqu16 %zmm8, (%rax,%rcx,2) {%k1}
addq $0x20, %rcx
cmpq %rcx, %rbp
jne 0x6375b
movq 0x8(%rbx), %r13
movq (%r14), %rcx
movq 0x10(%rsp), %rbp
movq 0x20(%r13), %rbx
cmpq %rcx, %r13
je 0x63883
movq 0x18(%r13), %rax
movq (%r13), %r14
movzwl (%rax), %ecx
leaq (%rcx,%rcx,4), %r15
leaq (%rax,%rcx,2), %r12
shll $0x3, %r15d
addq 0x10(%r13), %r15
movq (%r15), %rdi
leaq 0x10(%r15), %rax
cmpq %rax, %rdi
je 0x63805
vzeroupper
callq 0x41a0
movzwl 0x2(%r12), %eax
leaq (%rax,%rax,4), %rcx
leaq 0x2(%r12,%rax,2), %r12
leaq 0x28(%r15,%rcx,8), %r15
cmpq %r14, %r15
jne 0x637f1
movl (%r13), %ecx
movq 0x10(%r13), %rdi
movzwl 0x30(%r13), %eax
subl %edi, %ecx
shrl $0x3, %ecx
imull $0xffffcccd, %ecx, %ecx # imm = 0xFFFFCCCD
cmpw %cx, %ax
je 0x63852
movq %rbp, %rdi
movq %r13, %rsi
vzeroupper
callq 0x6261a
movzwl 0x30(%r13), %eax
movq 0x10(%r13), %rdi
movzwl %ax, %eax
subq %rax, 0x38(%rbp)
movq 0x8(%r13), %r15
vzeroupper
callq 0x41a0
movq %r13, %rdi
callq 0x41a0
movq 0x8(%rsp), %r14
movq %r15, %r13
movq (%r14), %rcx
cmpq %rcx, %r15
jne 0x637d6
jmp 0x63886
movq %r13, %r15
movq 0x18(%r15), %rdx
movzwl (%rdx), %esi
leaq (%rsi,%rsi,4), %r13
shll $0x3, %r13d
addq 0x10(%r15), %r13
movq %rbx, 0x20(%r15)
testq %rbx, %rbx
je 0x638ac
movq %r15, 0x8(%rbx)
movq 0x8(%r14), %rax
jmp 0x638c3
movq %r15, 0x30(%rbp)
movq %rcx, 0x18(%rbp)
vmovdqu 0x8(%r14), %xmm0
movq 0x8(%r14), %rax
vmovdqu %xmm0, 0x20(%rbp)
movq 0x18(%rcx), %rdi
movzwl (%rdi), %edi
leaq (%rdi,%rdi,4), %rdi
shll $0x3, %edi
addq 0x10(%rcx), %rdi
cmpq %rax, %rdi
je 0x63b7d
leaq (%rdx,%rsi,2), %r12
cmpq (%r15), %rax
jne 0x63902
movq 0x18(%r15), %rcx
movzwl (%rcx), %ecx
leaq (%rcx,%rcx,4), %rcx
shll $0x3, %ecx
addq 0x10(%r15), %rcx
cmpq %rcx, %r13
je 0x63a27
movq %r15, 0x20(%rsp)
leaq 0x48(%rbp), %r15
xorl %r14d, %r14d
movq %r13, %rbp
movq %r12, %rbx
movq (%rbp), %rdi
leaq 0x10(%rbp), %rax
cmpq %rax, %rdi
je 0x63929
vzeroupper
callq 0x41a0
movq %r15, %rdi
movq %rbp, %rsi
vzeroupper
callq 0x624ec
movzwl 0x2(%rbx), %eax
incl %r14d
leaq (%rax,%rax,4), %rcx
leaq 0x2(%rbx,%rax,2), %rbx
leaq 0x28(%rbp,%rcx,8), %rbp
movq 0x8(%rsp), %rcx
movq 0x8(%rcx), %rax
cmpq %rax, %rbp
jne 0x63914
movq 0x10(%rsp), %rdx
movzwl %r14w, %ecx
movq %r12, %r9
subq %rcx, 0x38(%rdx)
movq 0x20(%rsp), %rdx
subw %cx, 0x30(%rdx)
xorl %ecx, %ecx
cmpq %r12, 0x18(%rdx)
movq %r12, %rdx
setne %cl
xorl %esi, %esi
addl %ecx, %ecx
subq %rcx, %rdx
movzwl (%rdx), %edx
testl %edx, %edx
leal (%rdx,%rdx), %r8d
sete %sil
subq %r13, %rbp
subq %r8, %r9
shrq $0x3, %rbp
imull $0xcccccccd, %ebp, %edi # imm = 0xCCCCCCCD
cmpw $0x1, %dx
leal (%rdx,%rdi), %ecx
adcl $0x0, %edx
subl %esi, %edi
movw %cx, (%r9)
leaq (%r12,%rsi,2), %rcx
movzwl %di, %esi
cmpl $0x4, %esi
jb 0x63a79
vmovq 0x53e55(%rip), %xmm0    # 0xb7820
movq 0x8(%rsp), %r9
vpbroadcastw %edx, %xmm1
addl $0xfffc, %esi           # imm = 0xFFFC
vpaddw %xmm0, %xmm1, %xmm1
movzwl %si, %esi
vmovq %xmm1, (%rcx)
addq $0x8, %rcx
vpextrw $0x3, %xmm1, %edx
cmpl $0x3, %esi
ja 0x639d0
jmp 0x63a7e
movq (%r13), %rdi
leaq 0x10(%r13), %rcx
cmpq %rcx, %rdi
je 0x63a13
vzeroupper
callq 0x41a0
movq 0x8(%r14), %rax
movzwl 0x2(%r12), %ecx
leaq (%rcx,%rcx,4), %rdx
leaq 0x2(%r12,%rcx,2), %r12
leaq 0x28(%r13,%rdx,8), %r13
cmpq %rax, %r13
jne 0x639fa
movzwl 0x30(%r15), %eax
subq %rax, 0x38(%rbp)
jne 0x63b8f
xorl %ebx, %ebx
movq %rbp, %rdi
movq %rbx, 0x30(%rbp)
vzeroupper
callq 0x1a838
leaq 0x48(%rbp), %rdi
callq 0x1a8fc
vpxor %xmm0, %xmm0, %xmm0
movq %rbx, 0x68(%rbp)
vmovdqu %xmm0, 0x58(%rbp)
vpxor %xmm0, %xmm0, %xmm0
movq %rbx, 0x38(%rbp)
vmovdqu %ymm0, (%rbp)
vmovdqu %ymm0, 0x10(%rbp)
jmp 0x63bd7
movq 0x8(%rsp), %r9
movq 0x10(%r9), %rsi
movq 0x10(%rsp), %r8
cmpq %rsi, %rcx
je 0x63b5f
vpbroadcastw %edx, %zmm0
vpaddw 0x52da0(%rip), %zmm0, %zmm0 # 0xb6840
vpmovsxbq 0x53c0e(%rip), %zmm2 # 0xb76b8
vpmovsxbq 0x53c0c(%rip), %zmm3 # 0xb76c0
vpmovsxbq 0x53c0a(%rip), %zmm4 # 0xb76c8
vpmovsxbq 0x53be8(%rip), %zmm5 # 0xb76b0
vpbroadcastw 0x52eae(%rip), %zmm7 # 0xb6980
movq %rsi, %rdi
subq %rcx, %rdi
vpternlogd $0xff, %zmm6, %zmm6, %zmm6
xorl %edx, %edx
addq $-0x2, %rdi
vpbroadcastq %rdi, %zmm1
shrq %rdi
andq $-0x20, %rdi
vpsrlq $0x1, %zmm1, %zmm1
addq $0x20, %rdi
vpbroadcastq %rdx, %zmm8
vporq %zmm2, %zmm8, %zmm9
vporq %zmm4, %zmm8, %zmm11
vporq %zmm3, %zmm8, %zmm10
vporq %zmm5, %zmm8, %zmm8
vpcmpleuq %zmm1, %zmm8, %k0
vpcmpleuq %zmm1, %zmm11, %k1
vpcmpleuq %zmm1, %zmm9, %k2
vpsubw %zmm6, %zmm0, %zmm8
vpaddw %zmm7, %zmm0, %zmm0
kunpckbw %k0, %k1, %k0
vpcmpleuq %zmm1, %zmm10, %k1
kunpckbw %k1, %k2, %k1
kunpckwd %k0, %k1, %k1
vmovdqu16 %zmm8, (%rcx,%rdx,2) {%k1}
addq $0x20, %rdx
cmpq %rdx, %rdi
jne 0x63afd
movq 0x18(%rsp), %rcx
movq 0x8(%rcx), %rcx
cmpq 0x20(%r8), %rcx
jne 0x63b7d
movq (%r9), %rcx
movq %rcx, 0x18(%r8)
movq %rax, 0x20(%r8)
movq %rsi, 0x28(%r8)
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq
movq 0x20(%r15), %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 (%r15), %ecx
subl 0x10(%r15), %ecx
shrl $0x3, %ecx
imull $0xffffcccd, %ecx, %ecx # imm = 0xFFFFCCCD
cmpw %cx, %ax
je 0x63bd7
movq %rbp, %rdi
movq %r15, %rsi
vzeroupper
callq 0x6261a
movq 0x10(%r15), %rdi
vzeroupper
callq 0x41a0
movq %r15, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x41a0