// File: attractivechaos[P]udb2/libcuckoo/./cuckoohash_map.hh
// Function: bool cuckoohash_map<unsigned int, unsigned int, Hash32, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int>>, 4ul>::cuckoopath_move<std::integral_constant<bool, false>>(unsigned long, std::array<cuckoohash_map<unsigned int, unsigned int, Hash32, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int>>, 4ul>::CuckooRecord, 5ul>&, unsigned long, cuckoohash_map<unsigned int, unsigned int, Hash32, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int>>, 4ul>::TwoBuckets&)
bool cuckoopath_move(const size_type hp, CuckooRecords &cuckoo_path,
                       size_type depth, TwoBuckets &b) {
    if (depth == 0) {
      // There is a chance that depth == 0, when try_add_to_bucket sees
      // both buckets as full and cuckoopath_search finds one empty. In
      // this case, we lock both buckets. If the slot that
      // cuckoopath_search found empty isn't empty anymore, we unlock them
      // and return false. Otherwise, the bucket is empty and insertable,
      // so we hold the locks and return true.
      const size_type bucket = cuckoo_path[0].bucket;
      assert(bucket == b.i1 || bucket == b.i2);
      b = lock_two(hp, b.i1, b.i2, TABLE_MODE());
      if (!buckets_[bucket].occupied(cuckoo_path[0].slot)) {
        return true;
      } else {
        b.unlock();
        return false;
      }
    }

    while (depth > 0) {
      CuckooRecord &from = cuckoo_path[depth - 1];
      CuckooRecord &to = cuckoo_path[depth];
      const size_type fs = from.slot;
      const size_type ts = to.slot;
      TwoBuckets twob;
      LockManager extra_manager;
      if (depth == 1) {
        // Even though we are only swapping out of one of the original
        // buckets, we have to lock both of them along with the slot we
        // are swapping to, since at the end of this function, they both
        // must be locked. We store tb inside the extrab container so it
        // is unlocked at the end of the loop.
        std::tie(twob, extra_manager) =
            lock_three(hp, b.i1, b.i2, to.bucket, TABLE_MODE());
      } else {
        twob = lock_two(hp, from.bucket, to.bucket, TABLE_MODE());
      }

      bucket &fb = buckets_[from.bucket];
      bucket &tb = buckets_[to.bucket];

      // We plan to kick out fs, but let's check if it is still there;
      // there's a small chance we've gotten scooped by a later cuckoo. If
      // that happened, just... try again. Also the slot we are filling in
      // may have already been filled in by another thread, or the slot we
      // are moving from may be empty, both of which invalidate the swap.
      // We only need to check that the hash value is the same, because,
      // even if the keys are different and have the same hash value, then
      // the cuckoopath is still valid.
      if (tb.occupied(ts) || !fb.occupied(fs) ||
          hashed_key_only_hash(fb.key(fs)) != from.hv.hash) {
        return false;
      }

      buckets_.setKV(to.bucket, ts, fb.partial(fs), fb.movable_key(fs),
                     std::move(fb.mapped(fs)));
      buckets_.eraseKV(from.bucket, fs);
      if (depth == 1) {
        // Hold onto the locks contained in twob
        b = std::move(twob);
      }
      depth--;
    }
    return true;
  }

// Assembly:
subq $0x1a8, %rsp            # imm = 0x1A8
movq %rdi, 0x198(%rsp)
movq %rsi, 0x190(%rsp)
movq %rdx, 0x188(%rsp)
movq %rcx, 0x180(%rsp)
movq %r8, 0x178(%rsp)
movq 0x198(%rsp), %rax
movq %rax, 0x68(%rsp)
cmpq $0x0, 0x180(%rsp)
jne 0x6bf1
movq 0x188(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x6fd0
movq (%rax), %rax
movq %rax, 0x170(%rsp)
movq 0x170(%rsp), %rcx
movq 0x178(%rsp), %rdx
movb $0x1, %al
cmpq (%rdx), %rcx
movb %al, 0x67(%rsp)
je 0x6b0d
movq 0x170(%rsp), %rax
movq 0x178(%rsp), %rcx
cmpq 0x8(%rcx), %rax
sete %al
movb %al, 0x67(%rsp)
movb 0x67(%rsp), %al
testb $0x1, %al
jne 0x6b17
jmp 0x6b19
jmp 0x6b38
leaq 0x85e9(%rip), %rdi      # 0xf109
leaq 0x7787(%rip), %rsi      # 0xe2ae
movl $0x55a, %edx            # imm = 0x55A
leaq 0x85f7(%rip), %rcx      # 0xf12a
callq 0x2110
movq 0x68(%rsp), %rsi
movq 0x190(%rsp), %rdx
movq 0x178(%rsp), %rax
movq (%rax), %rcx
movq 0x178(%rsp), %rax
movq 0x8(%rax), %r8
leaq 0x150(%rsp), %rdi
callq 0x4fe0
movq 0x178(%rsp), %rdi
leaq 0x150(%rsp), %rsi
callq 0x5d00
leaq 0x150(%rsp), %rdi
callq 0x4e70
movq 0x68(%rsp), %rdi
addq $0x8, %rdi
movq 0x170(%rsp), %rsi
callq 0x4db0
movq %rax, 0x58(%rsp)
movq 0x188(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x6fd0
movq 0x58(%rsp), %rdi
movq 0x8(%rax), %rsi
callq 0x3590
testb $0x1, (%rax)
jne 0x6bd7
movb $0x1, 0x1a7(%rsp)
jmp 0x6fab
movq 0x178(%rsp), %rdi
callq 0x6430
movb $0x0, 0x1a7(%rsp)
jmp 0x6fab
jmp 0x6bf3
cmpq $0x0, 0x180(%rsp)
jbe 0x6fa3
movq 0x188(%rsp), %rdi
movq 0x180(%rsp), %rsi
subq $0x1, %rsi
callq 0x6fd0
movq %rax, 0x140(%rsp)
movq 0x188(%rsp), %rdi
movq 0x180(%rsp), %rsi
callq 0x6fd0
movq %rax, 0x138(%rsp)
movq 0x140(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x130(%rsp)
movq 0x138(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x128(%rsp)
leaq 0x108(%rsp), %rdi
callq 0x7900
leaq 0x100(%rsp), %rdi
callq 0x7930
cmpq $0x1, 0x180(%rsp)
jne 0x6d3e
movq 0x68(%rsp), %rsi
movq 0x190(%rsp), %rdx
movq 0x178(%rsp), %rax
movq (%rax), %rcx
movq 0x8(%rax), %r8
movq 0x138(%rsp), %rax
movq (%rax), %r9
leaq 0xd8(%rsp), %rdi
callq 0x7960
jmp 0x6cc7
leaq 0xb0(%rsp), %rdi
leaq 0x108(%rsp), %rsi
leaq 0x100(%rsp), %rdx
callq 0x7e10
leaq 0xb0(%rsp), %rdi
leaq 0xd8(%rsp), %rsi
callq 0x7e50
leaq 0xd8(%rsp), %rdi
callq 0x7ec0
jmp 0x6d92
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
leaq 0x100(%rsp), %rdi
callq 0x7580
leaq 0x108(%rsp), %rdi
callq 0x4e70
jmp 0x6fbc
movq 0x68(%rsp), %rsi
movq 0x190(%rsp), %rdx
movq 0x140(%rsp), %rax
movq (%rax), %rcx
movq 0x138(%rsp), %rax
movq (%rax), %r8
leaq 0x90(%rsp), %rdi
callq 0x4fe0
jmp 0x6d70
leaq 0x108(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x5d00
leaq 0x90(%rsp), %rdi
callq 0x4e70
movq 0x68(%rsp), %rdi
addq $0x8, %rdi
movq 0x140(%rsp), %rax
movq (%rax), %rsi
callq 0x4db0
movq %rax, 0x50(%rsp)
jmp 0x6db2
movq 0x68(%rsp), %rdi
movq 0x50(%rsp), %rax
movq %rax, 0x80(%rsp)
addq $0x8, %rdi
movq 0x138(%rsp), %rax
movq (%rax), %rsi
callq 0x4db0
movq %rax, 0x48(%rsp)
jmp 0x6ddf
movq 0x48(%rsp), %rax
movq %rax, 0x78(%rsp)
movq 0x78(%rsp), %rdi
movq 0x128(%rsp), %rsi
callq 0x3590
testb $0x1, (%rax)
jne 0x6e5f
movq 0x80(%rsp), %rdi
movq 0x130(%rsp), %rsi
callq 0x3590
testb $0x1, (%rax)
je 0x6e5f
movq 0x80(%rsp), %rdi
movq 0x130(%rsp), %rsi
callq 0x6370
movq %rax, 0x40(%rsp)
jmp 0x6e36
movq 0x40(%rsp), %rsi
movq 0x68(%rsp), %rdi
callq 0x7ef0
movq %rax, 0x38(%rsp)
jmp 0x6e4c
movq 0x38(%rsp), %rax
movq 0x140(%rsp), %rcx
cmpq 0x10(%rcx), %rax
je 0x6e74
movb $0x0, 0x1a7(%rsp)
movl $0x1, 0x74(%rsp)
jmp 0x6f78
movq 0x68(%rsp), %rax
addq $0x8, %rax
movq %rax, 0x10(%rsp)
movq 0x138(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x18(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x80(%rsp), %rdi
movq 0x130(%rsp), %rsi
callq 0x7840
movb (%rax), %al
movb %al, 0x2f(%rsp)
movq 0x80(%rsp), %rdi
movq 0x130(%rsp), %rsi
callq 0x8020
movq %rax, 0x30(%rsp)
jmp 0x6ed6
movq 0x80(%rsp), %rdi
movq 0x130(%rsp), %rsi
callq 0x4dd0
movq %rax, 0x8(%rsp)
jmp 0x6ef2
movq 0x8(%rsp), %r9
movq 0x30(%rsp), %r8
movq 0x20(%rsp), %rdx
movq 0x18(%rsp), %rsi
movq 0x10(%rsp), %rdi
movb 0x2f(%rsp), %al
movzbl %al, %ecx
callq 0x7f20
jmp 0x6f19
movq 0x68(%rsp), %rdi
addq $0x8, %rdi
movq 0x140(%rsp), %rax
movq (%rax), %rsi
movq 0x130(%rsp), %rdx
callq 0x35c0
jmp 0x6f3c
cmpq $0x1, 0x180(%rsp)
jne 0x6f5c
movq 0x178(%rsp), %rdi
leaq 0x108(%rsp), %rsi
callq 0x5d00
movq 0x180(%rsp), %rax
addq $-0x1, %rax
movq %rax, 0x180(%rsp)
movl $0x0, 0x74(%rsp)
leaq 0x100(%rsp), %rdi
callq 0x7580
leaq 0x108(%rsp), %rdi
callq 0x4e70
movl 0x74(%rsp), %eax
testl %eax, %eax
je 0x6f9e
jmp 0x6f9c
jmp 0x6fab
jmp 0x6bf3
movb $0x1, 0x1a7(%rsp)
movb 0x1a7(%rsp), %al
andb $0x1, %al
addq $0x1a8, %rsp            # imm = 0x1A8
retq
movq 0xc8(%rsp), %rdi
callq 0x2240
nopl (%rax)