// File: wichtounet[P]articles/plf_colony_alpha/plf_colony.h
// Function: plf::colony<NonTrivialStringMovable, std::allocator<NonTrivialStringMovable>, unsigned short>::insert(NonTrivialStringMovable const&)
iterator insert(const element_type &element)
	{
		if (end_iterator.element_pointer != NULL)
		{
			switch(((erased_locations.total_number_of_elements != 0) << 1) | (end_iterator.element_pointer == reinterpret_cast<element_pointer_type>(end_iterator.group_pointer->skipfield)))
			{
				case 0: // ie. erased_locations is empty and end_iterator is not at end of current final group
				{
					const iterator return_iterator = end_iterator; /* Make copy for return before adjusting components */
					PLF_COLONY_CONSTRUCT(element_allocator_type, (*this), end_iterator.element_pointer, element);

					++end_iterator.element_pointer; // not postfix incrementing prev statement as it would necessitate a try-catch block to reverse increment if necessary (which would decrease speed by increasing code size)
					++end_iterator.skipfield_pointer;
					++(end_iterator.group_pointer->last_endpoint);
					++(end_iterator.group_pointer->number_of_elements);
					++total_number_of_elements;

					return return_iterator; // return value before incrementing
				}
				case 1:	// ie. erased_locations is empty and end_iterator is at end of current final group - ie. colony is full - create new group
				{
					end_iterator.group_pointer->next_group = PLF_COLONY_ALLOCATE(group_allocator_type, group_allocator_pair, 1, end_iterator.group_pointer);
					group &next_group = *(end_iterator.group_pointer->next_group);

					try
					{
						#ifdef PLF_COLONY_VARIADICS_SUPPORT
							PLF_COLONY_CONSTRUCT(group_allocator_type, group_allocator_pair, &next_group, (total_number_of_elements < static_cast<size_type>(group_allocator_pair.max_elements_per_group)) ? static_cast<const skipfield_type>(total_number_of_elements) : group_allocator_pair.max_elements_per_group, end_iterator.group_pointer);
						#else // C++03 only supports copy construction
							PLF_COLONY_CONSTRUCT(group_allocator_type, group_allocator_pair, &next_group, group((total_number_of_elements < static_cast<size_type>(group_allocator_pair.max_elements_per_group)) ? static_cast<const skipfield_type>(total_number_of_elements) : group_allocator_pair.max_elements_per_group, end_iterator.group_pointer));
						#endif
					}
					catch (...)
					{
						PLF_COLONY_DEALLOCATE(group_allocator_type, group_allocator_pair, &next_group, 1);
						end_iterator.group_pointer->next_group = NULL;
						throw;
					}

					try
					{
						PLF_COLONY_CONSTRUCT(element_allocator_type, (*this), next_group.elements, element);
					}
					catch (...)
					{
						PLF_COLONY_DESTROY(group_allocator_type, group_allocator_pair, &next_group);
						PLF_COLONY_DEALLOCATE(group_allocator_type, group_allocator_pair, &next_group, 1);
						end_iterator.group_pointer->next_group = NULL;
						throw;
					}

					end_iterator.group_pointer = &next_group;
					end_iterator.element_pointer = next_group.last_endpoint;
					end_iterator.skipfield_pointer = next_group.skipfield + 1;
					++total_number_of_elements;

					return iterator(end_iterator.group_pointer, next_group.elements, next_group.skipfield); /* returns value before incrementation */
				}
				default: // ie. erased_locations is not empty, reuse previous-erased element locations
				{
					iterator new_location;
					new_location.element_pointer = *erased_locations.top_element;
					PLF_COLONY_CONSTRUCT(element_allocator_type, (*this), new_location.element_pointer, element);
					erased_locations.pop();

					new_location.group_pointer = end_iterator.group_pointer; // Start with last group first, as will be the largest group

					while (new_location.element_pointer < new_location.group_pointer->elements || new_location.element_pointer >= reinterpret_cast<element_pointer_type>(new_location.group_pointer->skipfield))
					{
						new_location.group_pointer = new_location.group_pointer->previous_group;
					}

					new_location.skipfield_pointer = new_location.group_pointer->skipfield + (new_location.element_pointer - new_location.group_pointer->elements);

					++(new_location.group_pointer->number_of_elements);

					if (new_location.group_pointer == first_group && new_location.element_pointer < begin_iterator.element_pointer)
					{ /* ie. begin_iterator was moved forwards as the result of an erasure at some point, this erased element is before the current begin, hence, set current begin iterator to this element */
						begin_iterator = new_location;
					}

					++total_number_of_elements;

					// Code logic for next section:
					// ============================
					// check whether location we are restoring to has a skipfield node before or after which is erased
					// if it has only a node before which is erased (ie. at end of erasure block), update the prime erasure point
					// if it only has a node after it which is erased, (ie. this is the prime erasure point), change next node to prime erasure point and update all subsequent erasure points (ie. decrement by 1)
					// if it has both a node before and after which is erased (ie. is in middle of erasure block), do both of the above

					// Explanation of the following optimization: we must avoid testing the left-hand skipfield node if we are already at the beginning of the skipfield, otherwise we create an out-of-bounds memory access.
					// To avoid this would Normally require a branching test ie. !is_at_start && left-hand-node != 0 (&& and || operations are conditional executation of the right-hand instruction, which causes branching). But instead we subtract 'test' (which is 0 if the skipfield node is at start of skipfield, 1 if not) from the skipfield node.
					// If not start of skipfield, this means we check to see if left-hand node is == 0 (value * 0).
					// If at start of skipfield, we perform an unneccesary test to see if the current skipfield node's value (*(skipfield - 0))
					// is == it's own value (value * 1). This may seem ridiculous, but it's less costly than branching - and since
					// node == skipfield_start is almost always going to be false, this needless check is only occasional.
					const skipfield_type value = *(new_location.skipfield_pointer);
					const bool test = (new_location.skipfield_pointer == new_location.group_pointer->skipfield);
					const unsigned char prev_skipfield = *(new_location.skipfield_pointer - !test) != value * test;
					const unsigned char after_skipfield = *(new_location.skipfield_pointer + 1) != 0; // NOTE: first test removed due to extra unused node in skipfield (required by operator ++)

					// Now we create a switch for the four different possible states (there are no additional instructions for state 0) depending on
					// whether the left and right-hand skipfield nodes are non-zero (or out-of-bounds), by bit-shifting the right-hand test and
					// logical-OR'ing it with the left-hand test:
					switch (prev_skipfield | (after_skipfield << 1))
					{
						case 1: // previous erased consecutive elements, none following
						{
							*(new_location.skipfield_pointer - (value - 1)) = value - 1;
							break;
						}
						case 2: // No previous consecutive erased points, at least one following ie. this was the prime erasure point
						{
							std::memmove(&*(new_location.skipfield_pointer + 2), &*(new_location.skipfield_pointer + 1), sizeof(skipfield_type) * (value - 2));
							*(new_location.skipfield_pointer + 1) = value - 1;
							break;
						}
						case 3: // both preceding and following consecutive erased elements
						{
							const skipfield_pointer_type start_node = new_location.skipfield_pointer - (value - 1);
							const skipfield_type update_count = *start_node - value;
							*start_node = value - 1;

							std::memmove(&*(new_location.skipfield_pointer + 2), &*(start_node + 1), sizeof(skipfield_type) * (update_count - 1));
							*(new_location.skipfield_pointer + 1) = update_count;
						}
					}

					*new_location.skipfield_pointer = 0;
					return new_location;
				}
			}
		}
		else // ie. newly-constructed colony, no insertions yet and no groups
		{
			initialize(min_elements_per_group);

			try
			{
				PLF_COLONY_CONSTRUCT(element_allocator_type, (*this), end_iterator.element_pointer++, element);
			}
			catch (...)
			{
				clear();
				throw;
			}

			++end_iterator.skipfield_pointer;
			total_number_of_elements = 1;

			return begin_iterator; // returns value before incrementation
		}
	}

// Assembly:
subq $0xa8, %rsp
movq %rdi, 0x40(%rsp)
movq %rdi, %rax
movq %rax, 0x48(%rsp)
movq %rdi, 0xa0(%rsp)
movq %rsi, 0x98(%rsp)
movq %rdx, 0x90(%rsp)
movq 0x98(%rsp), %rax
movq %rax, 0x50(%rsp)
cmpq $0x0, 0x8(%rax)
je 0x3c3e5
movq 0x50(%rsp), %rcx
movq 0x70(%rcx), %rax
testq %rax, %rax
setne %al
movzbl %al, %eax
addl %eax, %eax
movq (%rcx), %rdx
movq 0x8(%rcx), %rcx
movq 0x18(%rdx), %rdx
subq %rdx, %rcx
sete %cl
movzbl %cl, %ecx
orl %ecx, %eax
movl %eax, 0x3c(%rsp)
je 0x3be94
jmp 0x3be86
movl 0x3c(%rsp), %eax
subl $0x1, %eax
je 0x3bf03
jmp 0x3c122
movq 0x50(%rsp), %rsi
movq 0x40(%rsp), %rdi
callq 0x3c4a0
movq 0x50(%rsp), %rdi
movq 0x8(%rdi), %rsi
movq 0x90(%rsp), %rdx
callq 0x39250
movq 0x50(%rsp), %rax
movq 0x8(%rax), %rcx
addq $0x28, %rcx
movq %rcx, 0x8(%rax)
movq 0x10(%rax), %rcx
addq $0x2, %rcx
movq %rcx, 0x10(%rax)
movq (%rax), %rcx
movq (%rcx), %rdx
addq $0x28, %rdx
movq %rdx, (%rcx)
movq (%rax), %rcx
movw 0x30(%rcx), %dx
addw $0x1, %dx
movw %dx, 0x30(%rcx)
movq 0x38(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x38(%rax)
jmp 0x3c481
movq 0x50(%rsp), %rax
movq %rax, %rdi
addq $0x42, %rdi
movq (%rax), %rdx
movl $0x1, %esi
callq 0x3c4e0
movq 0x50(%rsp), %rcx
movq %rax, %rdx
movq (%rcx), %rax
movq %rdx, 0x8(%rax)
movq (%rcx), %rax
movq 0x8(%rax), %rax
movq %rax, 0x88(%rsp)
movq %rcx, %rax
addq $0x42, %rax
movq %rax, 0x28(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x38(%rcx), %rax
movzwl 0x42(%rcx), %ecx
cmpq %rcx, %rax
jae 0x3bf70
movq 0x50(%rsp), %rax
movq 0x38(%rax), %rax
movw %ax, 0x26(%rsp)
jmp 0x3bf7e
movq 0x50(%rsp), %rax
movw 0x42(%rax), %ax
movw %ax, 0x26(%rsp)
movq 0x50(%rsp), %rcx
movq 0x30(%rsp), %rsi
movq 0x28(%rsp), %rdi
movw 0x26(%rsp), %ax
movw %ax, 0x86(%rsp)
leaq 0x86(%rsp), %rdx
callq 0x3c510
jmp 0x3bfa9
jmp 0x3c014
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
movq 0x78(%rsp), %rdi
callq 0x50b0
movq 0x50(%rsp), %rdi
addq $0x42, %rdi
movq 0x88(%rsp), %rsi
movl $0x1, %edx
callq 0x3c550
jmp 0x3bfe0
movq 0x50(%rsp), %rax
movq (%rax), %rax
movq $0x0, 0x8(%rax)
callq 0x52d0
jmp 0x3c4a0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
callq 0x5350
jmp 0x3c00f
jmp 0x3c48e
movq 0x50(%rsp), %rdi
movq 0x88(%rsp), %rax
movq 0x10(%rax), %rsi
movq 0x90(%rsp), %rdx
callq 0x39250
jmp 0x3c034
jmp 0x3c0b9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
movq 0x78(%rsp), %rdi
callq 0x50b0
movq 0x50(%rsp), %rdi
addq $0x42, %rdi
movq %rdi, 0x18(%rsp)
movq 0x88(%rsp), %rsi
callq 0x3c580
movq 0x18(%rsp), %rdi
movq 0x88(%rsp), %rsi
movl $0x1, %edx
callq 0x3c550
jmp 0x3c085
movq 0x50(%rsp), %rax
movq (%rax), %rax
movq $0x0, 0x8(%rax)
callq 0x52d0
jmp 0x3c4a0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
callq 0x5350
jmp 0x3c0b4
jmp 0x3c48e
movq 0x40(%rsp), %rdi
movq 0x50(%rsp), %rax
movq 0x88(%rsp), %rcx
movq %rcx, (%rax)
movq 0x88(%rsp), %rcx
movq (%rcx), %rcx
movq %rcx, 0x8(%rax)
movq 0x88(%rsp), %rcx
movq 0x18(%rcx), %rcx
addq $0x2, %rcx
movq %rcx, 0x10(%rax)
movq 0x38(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x38(%rax)
movq (%rax), %rsi
movq 0x88(%rsp), %rax
movq 0x10(%rax), %rdx
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rcx
callq 0x3c5b0
jmp 0x3c481
movq 0x40(%rsp), %rdi
callq 0x3bbc0
movq 0x50(%rsp), %rdi
movq 0x40(%rsp), %rax
movq 0x58(%rdi), %rcx
movq (%rcx), %rcx
movq %rcx, 0x8(%rax)
movq 0x8(%rax), %rsi
movq 0x90(%rsp), %rdx
callq 0x39250
movq 0x50(%rsp), %rdi
addq $0x48, %rdi
callq 0x3c5f0
movq 0x50(%rsp), %rcx
movq 0x40(%rsp), %rax
movq (%rcx), %rcx
movq %rcx, (%rax)
movq 0x40(%rsp), %rax
movq 0x8(%rax), %rcx
movq (%rax), %rdx
movb $0x1, %al
cmpq 0x10(%rdx), %rcx
movb %al, 0x17(%rsp)
jb 0x3c19f
movq 0x40(%rsp), %rcx
movq 0x8(%rcx), %rax
movq (%rcx), %rcx
cmpq 0x18(%rcx), %rax
setae %al
movb %al, 0x17(%rsp)
movb 0x17(%rsp), %al
testb $0x1, %al
jne 0x3c1a9
jmp 0x3c1ba
movq 0x40(%rsp), %rax
movq (%rax), %rcx
movq 0x20(%rcx), %rcx
movq %rcx, (%rax)
jmp 0x3c170
movq 0x50(%rsp), %rcx
movq 0x40(%rsp), %rdx
movq (%rdx), %rax
movq 0x18(%rax), %rax
movq %rax, 0x8(%rsp)
movq 0x8(%rdx), %rax
movq (%rdx), %rdx
movq 0x10(%rdx), %rdx
subq %rdx, %rax
movl $0x28, %esi
cqto
idivq %rsi
movq 0x8(%rsp), %rdx
movq %rax, %rsi
movq 0x40(%rsp), %rax
shlq %rsi
addq %rsi, %rdx
movq %rdx, 0x10(%rax)
movq (%rax), %rdx
movw 0x30(%rdx), %si
addw $0x1, %si
movw %si, 0x30(%rdx)
movq (%rax), %rax
cmpq 0x30(%rcx), %rax
jne 0x3c23e
movq 0x50(%rsp), %rcx
movq 0x40(%rsp), %rax
movq 0x8(%rax), %rax
cmpq 0x20(%rcx), %rax
jae 0x3c23e
movq 0x40(%rsp), %rsi
movq 0x50(%rsp), %rdi
addq $0x18, %rdi
callq 0x3c660
movq 0x40(%rsp), %rax
movq 0x50(%rsp), %rcx
movq 0x38(%rcx), %rdx
incq %rdx
movq %rdx, 0x38(%rcx)
movq 0x10(%rax), %rcx
movw (%rcx), %cx
movw %cx, 0x72(%rsp)
movq (%rax), %rdx
movq 0x10(%rax), %rcx
movq 0x18(%rdx), %rdx
subq %rdx, %rcx
sete 0x71(%rsp)
movq 0x10(%rax), %rcx
movzbl 0x71(%rsp), %esi
movb %sil, %dl
notb %dl
movzbl %dl, %edx
andl $0x1, %edx
addl %edx, %edx
subq %rdx, %rcx
movzwl (%rcx), %ecx
movzwl 0x72(%rsp), %edx
andl $0x1, %esi
imull %esi, %edx
subl %edx, %ecx
setne 0x70(%rsp)
movq 0x10(%rax), %rax
movw 0x2(%rax), %ax
testw %ax, %ax
setne 0x6f(%rsp)
movzbl 0x70(%rsp), %eax
movzbl 0x6f(%rsp), %ecx
addl %ecx, %ecx
orl %ecx, %eax
movl %eax, 0x4(%rsp)
subl $0x1, %eax
je 0x3c2e2
jmp 0x3c2c9
movl 0x4(%rsp), %eax
subl $0x2, %eax
je 0x3c30f
jmp 0x3c2d4
movl 0x4(%rsp), %eax
subl $0x3, %eax
je 0x3c351
jmp 0x3c3d2
movq 0x40(%rsp), %rax
movzwl 0x72(%rsp), %ecx
subl $0x1, %ecx
movw %cx, %dx
movq 0x10(%rax), %rax
movzwl 0x72(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rsi
xorl %ecx, %ecx
subq %rsi, %rcx
movw %dx, (%rax,%rcx,2)
jmp 0x3c3d2
movq 0x40(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x4, %rdi
movq 0x10(%rax), %rsi
addq $0x2, %rsi
movzwl 0x72(%rsp), %eax
subl $0x2, %eax
movslq %eax, %rdx
shlq %rdx
callq 0x5330
movq 0x40(%rsp), %rax
movzwl 0x72(%rsp), %ecx
subl $0x1, %ecx
movq 0x10(%rax), %rax
movw %cx, 0x2(%rax)
jmp 0x3c3d2
movq 0x40(%rsp), %rax
movq 0x10(%rax), %rcx
movzwl 0x72(%rsp), %edx
subl $0x1, %edx
movslq %edx, %rsi
xorl %edx, %edx
subq %rsi, %rdx
shlq %rdx
addq %rdx, %rcx
movq %rcx, 0x60(%rsp)
movq 0x60(%rsp), %rcx
movzwl (%rcx), %ecx
movzwl 0x72(%rsp), %edx
subl %edx, %ecx
movw %cx, 0x5e(%rsp)
movzwl 0x72(%rsp), %ecx
subl $0x1, %ecx
movw %cx, %dx
movq 0x60(%rsp), %rcx
movw %dx, (%rcx)
movq 0x10(%rax), %rdi
addq $0x4, %rdi
movq 0x60(%rsp), %rsi
addq $0x2, %rsi
movzwl 0x5e(%rsp), %eax
subl $0x1, %eax
movslq %eax, %rdx
shlq %rdx
callq 0x5330
movq 0x40(%rsp), %rax
movw 0x5e(%rsp), %cx
movq 0x10(%rax), %rax
movw %cx, 0x2(%rax)
movq 0x40(%rsp), %rax
movq 0x10(%rax), %rax
movw $0x0, (%rax)
jmp 0x3c481
movq 0x50(%rsp), %rdi
movzwl 0x40(%rdi), %esi
callq 0x3c6a0
movq 0x50(%rsp), %rdi
movq 0x8(%rdi), %rsi
movq %rsi, %rax
addq $0x28, %rax
movq %rax, 0x8(%rdi)
movq 0x90(%rsp), %rdx
callq 0x39250
jmp 0x3c416
jmp 0x3c45a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
movq 0x78(%rsp), %rdi
callq 0x50b0
movq 0x50(%rsp), %rdi
callq 0x3c7a0
jmp 0x3c43c
callq 0x52d0
jmp 0x3c4a0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
callq 0x5350
jmp 0x3c458
jmp 0x3c48e
movq 0x40(%rsp), %rdi
movq 0x50(%rsp), %rsi
movq 0x10(%rsi), %rax
addq $0x2, %rax
movq %rax, 0x10(%rsi)
movq $0x1, 0x38(%rsi)
addq $0x18, %rsi
callq 0x3c4a0
movq 0x48(%rsp), %rax
addq $0xa8, %rsp
retq
movq 0x78(%rsp), %rdi
callq 0x5360
movq %rax, %rdi
callq 0x14670