// File: nvanbenschoten[P]total-order-multicast/src/process.cc
// Function: process::HoldBackQueue::SetDeliverable(msg::SeqMessage const&, std::function<void (msg::SeqMessage&)>)
void HoldBackQueue::SetDeliverable(const msg::SeqMessage& seq_msg,
                                   const deliverMsgFn deliver) {
  // Look up the messages old sequence information in the sequence map using the
  // messages uniquely defining information. This allows us to find the pending
  // message in the ordered set faster.
  PendingMessageKey pmk;
  pmk.sender = seq_msg.sender;
  pmk.msg_id = seq_msg.msg_id;

  auto old_pms_it = pending_seqs_.find(pmk);
  if (old_pms_it == pending_seqs_.end()) {
    // Return without error to permit message replays.
    logging::out << "Unknown SeqMessage " << seq_msg << "...\n";
    return;
  }

  // Remove the message from the sequence cache.
  PendingMessageSeq old_pms = old_pms_it->second;
  pending_seqs_.erase(old_pms_it);

  // Remove old pending message.
  PendingMessage pm;
  pm.pmk = pmk;
  pm.pms = old_pms;
  pm.deliverable = false;
  ordering_.erase(pm);

  // Update with the new information and reinsert.
  PendingMessageSeq pms;
  pms.seq = seq_msg.final_seq;
  pms.seq_proposer = seq_msg.final_seq_proposer;

  pm.pms = pms;
  pm.deliverable = true;
  ordering_.insert(pm);

  // Iterate through map and deliver messages that can be delivered.
  for (auto it = ordering_.begin(); it != ordering_.end() /* not hoisted */;) {
    if (!it->deliverable) {
      break;
    }
    // Deliver and delete for as long as the head of the queue is deliverable.
    msg::SeqMessage to_deliver;
    to_deliver.sender = it->pmk.sender;
    to_deliver.msg_id = it->pmk.msg_id;
    to_deliver.final_seq = it->pms.seq;
    to_deliver.final_seq_proposer = it->pms.seq_proposer;
    deliver(to_deliver);

    // Erase and move to next message in ordered map.
    it = ordering_.erase(it);
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xc0, %rsp
movq %rdx, -0xc0(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0xb8(%rbp)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x20(%rbp)
movq -0x10(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x1c(%rbp)
leaq -0x20(%rbp), %rsi
callq 0xa820
movq -0xb8(%rbp), %rdi
movq %rax, -0x28(%rbp)
callq 0xa880
movq %rax, -0x30(%rbp)
leaq -0x28(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0xa850
testb $0x1, %al
jne 0x7ecd
jmp 0x7f00
leaq 0x3e724(%rip), %rdi     # 0x465f8
leaq 0x273bf(%rip), %rsi     # 0x2f29a
callq 0xa9f0
movq %rax, %rdi
movq -0x10(%rbp), %rsi
callq 0xaa40
movq %rax, %rdi
leaq 0x273b8(%rip), %rsi     # 0x2f2ae
callq 0xaa90
jmp 0x807b
leaq -0x28(%rbp), %rdi
callq 0xa8b0
movq -0xb8(%rbp), %rdi
movq 0x8(%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rsi
callq 0xaae0
movq -0xb8(%rbp), %rdi
movq %rax, -0x48(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x58(%rbp)
movb $0x0, -0x4c(%rbp)
addq $0x38, %rdi
leaq -0x60(%rbp), %rsi
callq 0xab20
movq -0xb8(%rbp), %rdi
movq -0x10(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x68(%rbp)
movq -0x10(%rbp), %rax
movl 0x10(%rax), %eax
movl %eax, -0x64(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x58(%rbp)
movb $0x1, -0x4c(%rbp)
addq $0x38, %rdi
leaq -0x60(%rbp), %rsi
callq 0xa9a0
movq -0xb8(%rbp), %rdi
movq %rax, -0x78(%rbp)
movb %dl, -0x70(%rbp)
addq $0x38, %rdi
callq 0xab50
movq %rax, -0x80(%rbp)
movq -0xb8(%rbp), %rdi
addq $0x38, %rdi
callq 0xabb0
movq %rax, -0x88(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x88(%rbp), %rsi
callq 0xab80
testb $0x1, %al
jne 0x7fd4
jmp 0x807b
leaq -0x80(%rbp), %rdi
callq 0xabe0
testb $0x1, 0x14(%rax)
jne 0x7fe8
jmp 0x807b
leaq -0x80(%rbp), %rdi
callq 0xabe0
movl (%rax), %eax
movl %eax, -0x98(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xabe0
movl 0x4(%rax), %eax
movl %eax, -0x94(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xabe0
movl 0x8(%rax), %eax
movl %eax, -0x90(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xabe0
movq -0xc0(%rbp), %rdi
movl 0xc(%rax), %eax
movl %eax, -0x8c(%rbp)
leaq -0x9c(%rbp), %rsi
callq 0xac00
movq -0xb8(%rbp), %rdi
addq $0x38, %rdi
movq -0x80(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rsi
callq 0xac40
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x80(%rbp)
jmp 0x7fa4
addq $0xc0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)