// File: /workspace/github_c_makefile_star2_O0/jflatow[P]jfdb/src/trie.c
// Function: JFT_cursor_merge
JFT_Status JFT_cursor_merge(JFT_Cursor *cursors,
                            JFT_Amount num,
                            JFT_SpliceFun splice,
                            void *restrict acc,
                            int flags) {
  // cursors are assumed to be at the same initial location (i.e. root)
  // we currently support merging up to 64 cursors at a time
  // JFDB cannot have more than 64 levels, so internally we don't need more
  // more than that and caller can merge in batches
  if (num < 1 || num > JFT_MASK_CAPACITY)
    return ENumCursors;

  // determine the max key size and ensure it is within bounds
  JFT_KeySize maxKeySize = max_key_size(cursors, num);
  if (maxKeySize > JFT_KEY_LIMIT)
    return EKeySize;

  // allocate all the stack space we will need up front
  JFT_MergeFrame *stack = calloc(maxKeySize, sizeof(JFT_MergeFrame)), *frame = stack;
  if (stack == NULL)
    return ENoMem;

  // initialize stack, etc.
  JFT_Status result = Ok;
  JFT_Direction direction = (flags & JFT_FLAGS_REVERSE) ? Reverse : Forward;
  *frame = (JFT_MergeFrame) {
    .bound = JFT_SYMBOL_ANY,
    .active = JFT_MASK_ACTIVE(num),
    .done = 0
  };

  JFT_MergeContext ctx = (JFT_MergeContext) {
    .stack = stack,
    .frame = frame,
    .maxKeySize = maxKeySize,
    .numCursors = num,
    .acc = acc,
    .flags = flags
  };

  // walk all the cursors in parallel, keeping them in sync
  // the point is we visit each path in the merged-trie exactly once
  while (1) {
    // are there any active cursors with discrete symbols?
    while (frame->active && frame->bound != JFT_SYMBOL_NIL) {
      // merge the active set
      switch (result = splice(cursors, &ctx, In)) {
        case Step:
          // push a new frame, get subsequent symbol from all active cursors
          // copy the currently active cursors and offset into the new frame
          (frame + 1)->active = frame->active;
          (frame + 1)->offset = frame->offset;
          frame = ctx.frame = move_into_frame(cursors,
                                              JFT_cursor_step,
                                              frame->active,
                                              frame + 1,
                                              direction);
          break;
        case Next:
          // shift the frame by recomputing active cursors
          // i.e. from those that stepped into this frame that are not done
          // if at the root, there can be no siblings, so we are done
          // reset the offset to that of the parent (in case prev changed it)
          if (frame == stack)
            goto out;
          frame->offset = (frame - 1)->offset;
          frame = ctx.frame = move_into_frame(cursors,
                                              JFT_cursor_next,
                                              (frame - 1)->active & ~frame->done,
                                              frame,
                                              direction);
          break;
        default:
          // early exit, pass the result through
          goto done;
      }
    }

    // we hit a wall, start backing out: pop the frame, call second splice
    // its not possible we are at the root, we would have exited already
    frame = ctx.frame = back_into_frame(cursors, frame - 1, direction);
  out:
    result = splice(cursors, &ctx, Out);

    // we could be at the root now, if so pass the result through
    // otherwise, move on to the next sibling
    if (frame == stack)
      goto done;
    frame->offset = (frame - 1)->offset;
    frame = ctx.frame = move_into_frame(cursors,
                                        JFT_cursor_next,
                                        (frame - 1)->active & ~frame->done,
                                        frame,
                                        direction);
  }

 done:
  free(stack);
  return result;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movl %r8d, -0x2c(%rbp)
cmpq $0x1, -0x18(%rbp)
jb 0x529d
cmpq $0x40, -0x18(%rbp)
jbe 0x52a9
movl $0x4, -0x4(%rbp)
jmp 0x556e
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x5580
movw %ax, -0x2e(%rbp)
movzwl -0x2e(%rbp), %eax
cmpl $0x400, %eax            # imm = 0x400
jle 0x52d1
movl $0x3, -0x4(%rbp)
jmp 0x556e
movzwl -0x2e(%rbp), %eax
movl %eax, %edi
movl $0x20, %esi
callq 0x1120
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x40(%rbp)
cmpq $0x0, -0x38(%rbp)
jne 0x5300
movl $0x5, -0x4(%rbp)
jmp 0x556e
movl $0x0, -0x44(%rbp)
movl -0x2c(%rbp), %edx
andl $0x1, %edx
movl $0x1, %eax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpl $0x0, %edx
cmovnel %ecx, %eax
movl %eax, -0x48(%rbp)
movq -0x40(%rbp), %rax
movq $-0x1, -0x68(%rbp)
movl $0x40, %ecx
subq -0x18(%rbp), %rcx
movq $-0x1, %rdx
shrq %cl, %rdx
movq %rdx, %rcx
movq %rcx, -0x60(%rbp)
movq $0x0, -0x58(%rbp)
movq $0x0, -0x50(%rbp)
movq -0x68(%rbp), %rcx
movq %rcx, (%rax)
movq -0x60(%rbp), %rcx
movq %rcx, 0x8(%rax)
movq -0x58(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq -0x50(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq -0x38(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x90(%rbp)
movw -0x2e(%rbp), %ax
movw %ax, -0x88(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x78(%rbp)
movl -0x2c(%rbp), %eax
movl %eax, -0x70(%rbp)
jmp 0x53ae
movq -0x40(%rbp), %rcx
xorl %eax, %eax
cmpq $0x0, 0x8(%rcx)
movb %al, -0x99(%rbp)
je 0x53d2
movq -0x40(%rbp), %rax
cmpq $-0x2, (%rax)
setne %al
movb %al, -0x99(%rbp)
movb -0x99(%rbp), %al
testb $0x1, %al
jne 0x53e1
jmp 0x54cc
movq -0x20(%rbp), %rax
movq -0x10(%rbp), %rdi
leaq -0x98(%rbp), %rsi
movl $0x1, %edx
callq *%rax
movl %eax, -0x44(%rbp)
movl %eax, %ecx
movl %ecx, -0xa0(%rbp)
subl $0x1, %eax
je 0x5419
jmp 0x5409
movl -0xa0(%rbp), %eax
subl $0x2, %eax
je 0x546a
jmp 0x54c2
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x38(%rax)
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rdx
movq -0x40(%rbp), %rcx
addq $0x20, %rcx
movl -0x48(%rbp), %r8d
leaq -0x5a8(%rip), %rsi      # 0x4eb0
callq 0x5600
movq %rax, -0x90(%rbp)
movq %rax, -0x40(%rbp)
jmp 0x54c7
movq -0x40(%rbp), %rax
cmpq -0x38(%rbp), %rax
jne 0x5476
jmp 0x54eb
movq -0x40(%rbp), %rax
movq -0x8(%rax), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rax
movq -0x18(%rax), %rdx
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
xorq $-0x1, %rax
andq %rax, %rdx
movq -0x40(%rbp), %rcx
movl -0x48(%rbp), %r8d
leaq -0x4e0(%rip), %rsi      # 0x4fd0
callq 0x5600
movq %rax, -0x90(%rbp)
movq %rax, -0x40(%rbp)
jmp 0x54c7
jmp 0x555f
jmp 0x53ae
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rsi
addq $-0x20, %rsi
movl -0x48(%rbp), %edx
callq 0x57a0
movq %rax, -0x90(%rbp)
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rax
movq -0x10(%rbp), %rdi
leaq -0x98(%rbp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq *%rax
movl %eax, -0x44(%rbp)
movq -0x40(%rbp), %rax
cmpq -0x38(%rbp), %rax
jne 0x5510
jmp 0x555f
movq -0x40(%rbp), %rax
movq -0x8(%rax), %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rax
movq -0x18(%rax), %rdx
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
xorq $-0x1, %rax
andq %rax, %rdx
movq -0x40(%rbp), %rcx
movl -0x48(%rbp), %r8d
leaq -0x57a(%rip), %rsi      # 0x4fd0
callq 0x5600
movq %rax, -0x90(%rbp)
movq %rax, -0x40(%rbp)
jmp 0x53ac
movq -0x38(%rbp), %rdi
callq 0x1030
movl -0x44(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xa0, %rsp
popq %rbp
retq
nopw (%rax,%rax)