// File: attractivechaos[P]udb2/verstable/./verstable.h
// Function: intmap_t_erase_itr_raw
VT_API_FN_QUALIFIERS bool VT_CAT( NAME, _erase_itr_raw ) ( NAME *table, VT_CAT( NAME, _itr ) itr )
{
  --table->key_count;
  size_t itr_bucket = itr.metadatum - table->metadata;

  #ifdef KEY_DTOR_FN
  KEY_DTOR_FN( table->buckets[ itr_bucket ].key );
  #endif
  #ifdef VAL_DTOR_FN
  VAL_DTOR_FN( table->buckets[ itr_bucket ].val );
  #endif

  // Case 1: The key is the only one in its chain, so just remove it.
  if(
    table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK &&
    ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK
  )
  {
    table->metadata[ itr_bucket ] = VT_EMPTY;
    return true;
  }

  // Case 2 and 3 require that we know the key's home bucket, which the iterator may not have recorded.
  if( itr.home_bucket == SIZE_MAX )
  {
    if( table->metadata[ itr_bucket ] & VT_IN_HOME_BUCKET_MASK )
      itr.home_bucket = itr_bucket;
    else
      itr.home_bucket = HASH_FN( table->buckets[ itr_bucket ].key ) & ( table->bucket_count - 1 );
  }

  // Case 2: The key is the last in a multi-key chain.
  // Traverse the chain from the beginning and find the penultimate key.
  // Then disconnect the key and erase.
  if( ( table->metadata[ itr_bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK )
  {
    size_t bucket = itr.home_bucket;
    while( true )
    {
      uint16_t displacement = table->metadata[ bucket ] & VT_DISPLACEMENT_MASK;
      size_t next = ( itr.home_bucket + VT_QUADRATIC( displacement ) ) & ( table->bucket_count - 1 );
      if( next == itr_bucket )
      {
        table->metadata[ bucket ] |= VT_DISPLACEMENT_MASK;
        table->metadata[ itr_bucket ] = VT_EMPTY;
        return true;
      }

      bucket = next;
    }
  }

  // Case 3: The chain has multiple keys, and the key is not the last one.
  // Traverse the chain from the key to be erased and find the last and penultimate keys.
  // Disconnect the last key from the chain, and swap it with the key to erase.
  size_t bucket = itr_bucket;
  while( true )
  {
    size_t prev = bucket;
    bucket = ( itr.home_bucket + VT_QUADRATIC( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) ) & (
      table->bucket_count - 1 );

    if( ( table->metadata[ bucket ] & VT_DISPLACEMENT_MASK ) == VT_DISPLACEMENT_MASK )
    {
      table->buckets[ itr_bucket ] = table->buckets[ bucket ];

      table->metadata[ itr_bucket ] = ( table->metadata[ itr_bucket ] & ~VT_HASH_FRAG_MASK ) | (
        table->metadata[ bucket ] & VT_HASH_FRAG_MASK );

      table->metadata[ prev ] |= VT_DISPLACEMENT_MASK;
      table->metadata[ bucket ] = VT_EMPTY;

      // Whether the iterator should be incremented depends on whether the key moved to the iterator bucket came from
      // before or after that bucket.
      // In the former case, the iteration would already have hit the moved key, so the iterator should still be
      // incremented.
      if( bucket > itr_bucket )
        return false;

      return true;
    }
  }
}

// Assembly:
subq $0x58, %rsp
leaq 0x60(%rsp), %rax
movq %rax, 0x10(%rsp)
movq %rdi, 0x48(%rsp)
movq 0x48(%rsp), %rcx
movq (%rcx), %rdx
addq $-0x1, %rdx
movq %rdx, (%rcx)
movq 0x8(%rax), %rax
movq 0x48(%rsp), %rcx
movq 0x10(%rcx), %rcx
subq %rcx, %rax
sarq %rax
movq %rax, 0x40(%rsp)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x800, %eax            # imm = 0x800
cmpl $0x0, %eax
je 0x25f2
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x7ff, %eax            # imm = 0x7FF
cmpl $0x7ff, %eax            # imm = 0x7FF
jne 0x25f2
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movw $0x0, (%rax,%rcx,2)
movb $0x1, 0x57(%rsp)
jmp 0x28be
movq 0x10(%rsp), %rax
cmpq $-0x1, 0x18(%rax)
jne 0x265f
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x800, %eax            # imm = 0x800
cmpl $0x0, %eax
je 0x262a
movq 0x10(%rsp), %rax
movq 0x40(%rsp), %rcx
movq %rcx, 0x18(%rax)
jmp 0x265d
movq 0x48(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x40(%rsp), %rcx
movl (%rax,%rcx,8), %edi
callq 0x21c0
movl %eax, %ecx
movq 0x10(%rsp), %rax
movl %ecx, %ecx
movq 0x48(%rsp), %rdx
movq 0x8(%rdx), %rdx
subq $0x1, %rdx
andq %rdx, %rcx
movq %rcx, 0x18(%rax)
jmp 0x265f
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x7ff, %eax            # imm = 0x7FF
cmpl $0x7ff, %eax            # imm = 0x7FF
jne 0x274d
movq 0x10(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x38(%rsp)
movq 0x10(%rsp), %rax
movq 0x48(%rsp), %rcx
movq 0x10(%rcx), %rcx
movq 0x38(%rsp), %rdx
movzwl (%rcx,%rdx,2), %ecx
andl $0x7ff, %ecx            # imm = 0x7FF
movw %cx, 0x36(%rsp)
movq 0x18(%rax), %rax
movq %rax, 0x8(%rsp)
movzwl 0x36(%rsp), %eax
movzwl 0x36(%rsp), %ecx
imull %ecx, %eax
movzwl 0x36(%rsp), %ecx
addl %ecx, %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq 0x8(%rsp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq 0x48(%rsp), %rcx
movq 0x8(%rcx), %rcx
subq $0x1, %rcx
andq %rcx, %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
cmpq 0x40(%rsp), %rax
jne 0x273e
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x38(%rsp), %rcx
movzwl (%rax,%rcx,2), %edx
orl $0x7ff, %edx            # imm = 0x7FF
movw %dx, (%rax,%rcx,2)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movw $0x0, (%rax,%rcx,2)
movb $0x1, 0x57(%rsp)
jmp 0x28be
movq 0x28(%rsp), %rax
movq %rax, 0x38(%rsp)
jmp 0x268f
movq 0x40(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x10(%rsp), %rax
movq 0x20(%rsp), %rcx
movq %rcx, 0x18(%rsp)
movq 0x18(%rax), %rax
movq %rax, (%rsp)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x7ff, %eax            # imm = 0x7FF
movq 0x48(%rsp), %rcx
movq 0x10(%rcx), %rcx
movq 0x20(%rsp), %rdx
movzwl (%rcx,%rdx,2), %ecx
andl $0x7ff, %ecx            # imm = 0x7FF
imull %ecx, %eax
movq 0x48(%rsp), %rcx
movq 0x10(%rcx), %rcx
movq 0x20(%rsp), %rdx
movzwl (%rcx,%rdx,2), %ecx
andl $0x7ff, %ecx            # imm = 0x7FF
addl %ecx, %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq (%rsp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq 0x48(%rsp), %rcx
movq 0x8(%rcx), %rcx
subq $0x1, %rcx
andq %rcx, %rax
movq %rax, 0x20(%rsp)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0x7ff, %eax            # imm = 0x7FF
cmpl $0x7ff, %eax            # imm = 0x7FF
jne 0x28b9
movq 0x48(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x40(%rsp), %rcx
movq 0x48(%rsp), %rdx
movq 0x18(%rdx), %rdx
movq 0x20(%rsp), %rsi
movq (%rdx,%rsi,8), %rdx
movq %rdx, (%rax,%rcx,8)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movzwl (%rax,%rcx,2), %eax
andl $0xffff0fff, %eax       # imm = 0xFFFF0FFF
movq 0x48(%rsp), %rcx
movq 0x10(%rcx), %rcx
movq 0x20(%rsp), %rdx
movzwl (%rcx,%rdx,2), %ecx
andl $0xf000, %ecx           # imm = 0xF000
orl %ecx, %eax
movw %ax, %dx
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x40(%rsp), %rcx
movw %dx, (%rax,%rcx,2)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x18(%rsp), %rcx
movzwl (%rax,%rcx,2), %edx
orl $0x7ff, %edx            # imm = 0x7FF
movw %dx, (%rax,%rcx,2)
movq 0x48(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x20(%rsp), %rcx
movw $0x0, (%rax,%rcx,2)
movq 0x20(%rsp), %rax
cmpq 0x40(%rsp), %rax
jbe 0x28b2
movb $0x0, 0x57(%rsp)
jmp 0x28be
movb $0x1, 0x57(%rsp)
jmp 0x28be
jmp 0x2757
movb 0x57(%rsp), %al
andb $0x1, %al
addq $0x58, %rsp
retq
nopl (%rax)