// File: lemire[P]fastscancount/include/fastscancount.h
// Function: fastscancount::fastscancount(std::vector<std::vector<unsigned int, std::allocator<unsigned int>> const*, std::allocator<std::vector<unsigned int, std::allocator<unsigned int>> const*>> const&, std::vector<unsigned int, std::allocator<unsigned int>>&, unsigned char)
void fastscancount(const std::vector<const std::vector<uint32_t>*> &data,
                   std::vector<uint32_t> &out, uint8_t threshold) {
  size_t cache_size = 65536;
  size_t range = cache_size;
  std::vector<uint8_t> counters(cache_size);
  size_t ds = data.size();
  out.resize( 4 * range); // let us add lots of capacity
  uint32_t *output = out.data();
  uint32_t *initout = out.data();
  std::vector<size_t> iters(ds);
  size_t countsofar = 0;
  uint32_t largest = 0;
  for (size_t c = 0; c < ds; c++) {
    if (largest < (*data[c])[data[c]->size() - 1])
      largest = (*data[c])[data[c]->size() - 1];
  }
  // we are assuming that all vectors in data are non-empty
  for (size_t start = 0; start < largest; start += range) {
    // make sure that the capacity is sufficient
    countsofar = output - initout;
    if (out.size() - countsofar < range) {
      out.resize(out.size() + 4 * range);
      initout = out.data();
      output = out.data() + countsofar;
    }
    memset(counters.data(), 0, range);
    for (size_t c = 0; c < ds; c++) {
      size_t it = iters[c]; // recover where we were
      const std::vector<uint32_t> &d = *data[c];
      const size_t itend = d.size();
      if (it == itend) // check that there is data to be processed
        continue;      // exhausted
      // check if we need to be careful:
      bool near_the_end = (d[itend - 1] < start + range);
      if (near_the_end) {
        output = natefastscancount_finalcheck(counters.data(), it, d.data(),
                                              start, itend, threshold, output);
      } else {
        output = natefastscancount_maincheck(counters.data(), it, d.data(),
                                             start, range, threshold, output);
      }
      iters[c] = it; // store it for next round
    }
  }
  countsofar = output - initout;
  out.resize(countsofar);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movb %dl, %al
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movb %al, -0x11(%rbp)
movq $0x10000, -0x20(%rbp)   # imm = 0x10000
movq -0x20(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0xe8(%rbp)
leaq -0x41(%rbp), %rdi
movq %rdi, -0xe0(%rbp)
callq 0x77d0
movq -0xe8(%rbp), %rsi
movq -0xe0(%rbp), %rdx
leaq -0x40(%rbp), %rdi
callq 0x77f0
jmp 0x368c
leaq -0x41(%rbp), %rdi
callq 0x7860
movq -0x8(%rbp), %rdi
callq 0x7880
movq %rax, -0x60(%rbp)
movq -0x10(%rbp), %rdi
movq -0x28(%rbp), %rsi
shlq $0x2, %rsi
callq 0x78a0
jmp 0x36b5
movq -0x10(%rbp), %rdi
callq 0x7930
movq %rax, -0x68(%rbp)
movq -0x10(%rbp), %rdi
callq 0x7930
movq %rax, -0x70(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0xf8(%rbp)
leaq -0x89(%rbp), %rdi
movq %rdi, -0xf0(%rbp)
callq 0x7950
movq -0xf8(%rbp), %rsi
movq -0xf0(%rbp), %rdx
leaq -0x88(%rbp), %rdi
callq 0x7970
jmp 0x3709
leaq -0x89(%rbp), %rdi
callq 0x79e0
movq $0x0, -0x98(%rbp)
movl $0x0, -0x9c(%rbp)
movq $0x0, -0xa8(%rbp)
movq -0xa8(%rbp), %rax
cmpq -0x60(%rbp), %rax
jae 0x3858
movl -0x9c(%rbp), %eax
movl %eax, -0xfc(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x7a00
movq (%rax), %rax
movq %rax, -0x108(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x7a00
movq (%rax), %rdi
callq 0x7a40
movq -0x108(%rbp), %rdi
movq %rax, %rsi
subq $0x1, %rsi
callq 0x7a20
movq %rax, %rcx
movl -0xfc(%rbp), %eax
cmpl (%rcx), %eax
jae 0x383f
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x7a00
movq (%rax), %rax
movq %rax, -0x110(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x7a00
movq (%rax), %rdi
callq 0x7a40
movq -0x110(%rbp), %rdi
movq %rax, %rsi
subq $0x1, %rsi
callq 0x7a20
movl (%rax), %eax
movl %eax, -0x9c(%rbp)
jmp 0x383f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x41(%rbp), %rdi
callq 0x7860
jmp 0x3b4e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x3b45
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x89(%rbp), %rdi
callq 0x79e0
jmp 0x3b45
jmp 0x3841
movq -0xa8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xa8(%rbp)
jmp 0x3735
movq $0x0, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
movl -0x9c(%rbp), %ecx
cmpq %rcx, %rax
jae 0x3aff
movq -0x68(%rbp), %rax
movq -0x70(%rbp), %rcx
subq %rcx, %rax
sarq $0x2, %rax
movq %rax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
callq 0x7a40
subq -0x98(%rbp), %rax
cmpq -0x28(%rbp), %rax
jae 0x3912
movq -0x10(%rbp), %rdi
movq %rdi, -0x118(%rbp)
callq 0x7a40
movq -0x118(%rbp), %rdi
movq -0x28(%rbp), %rcx
leaq (%rax,%rcx,4), %rsi
callq 0x78a0
jmp 0x38cb
movq -0x10(%rbp), %rdi
callq 0x7930
movq %rax, -0x70(%rbp)
movq -0x10(%rbp), %rdi
callq 0x7930
movq -0x98(%rbp), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x68(%rbp)
jmp 0x3912
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x7ac0
jmp 0x3b45
leaq -0x40(%rbp), %rdi
callq 0x7a60
movq %rax, %rdi
movq -0x28(%rbp), %rdx
xorl %esi, %esi
callq 0x3180
movq $0x0, -0xb8(%rbp)
movq -0xb8(%rbp), %rax
cmpq -0x60(%rbp), %rax
jae 0x3ae6
movq -0xb8(%rbp), %rsi
leaq -0x88(%rbp), %rdi
callq 0x7a80
movq (%rax), %rax
movq %rax, -0xc0(%rbp)
movq -0x8(%rbp), %rdi
movq -0xb8(%rbp), %rsi
callq 0x7a00
movq (%rax), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rdi
callq 0x7a40
movq %rax, -0xd0(%rbp)
movq -0xc0(%rbp), %rax
cmpq -0xd0(%rbp), %rax
jne 0x39a4
jmp 0x3acf
movq -0xc8(%rbp), %rdi
movq -0xd0(%rbp), %rsi
subq $0x1, %rsi
callq 0x7a20
movl (%rax), %eax
movq -0xb0(%rbp), %rcx
addq -0x28(%rbp), %rcx
cmpq %rcx, %rax
setb %al
andb $0x1, %al
movb %al, -0xd1(%rbp)
testb $0x1, -0xd1(%rbp)
je 0x3a44
leaq -0x40(%rbp), %rdi
callq 0x7a60
movq %rax, -0x128(%rbp)
movq -0xc8(%rbp), %rdi
callq 0x7aa0
movq -0x128(%rbp), %rdi
movq %rax, %rdx
movq -0xb0(%rbp), %rcx
movq -0xd0(%rbp), %r8
movzbl -0x11(%rbp), %r9d
movq -0x68(%rbp), %rsi
movq %rsp, %rax
movq %rsi, (%rax)
leaq -0xc0(%rbp), %rsi
callq 0x3b60
movq %rax, -0x120(%rbp)
jmp 0x3a37
movq -0x120(%rbp), %rax
movq %rax, -0x68(%rbp)
jmp 0x3aa4
leaq -0x40(%rbp), %rdi
callq 0x7a60
movq %rax, -0x138(%rbp)
movq -0xc8(%rbp), %rdi
callq 0x7aa0
movq -0x138(%rbp), %rdi
movq %rax, %rdx
movq -0xb0(%rbp), %rcx
movq -0x28(%rbp), %r8
movzbl -0x11(%rbp), %r9d
movq -0x68(%rbp), %rsi
movq %rsp, %rax
movq %rsi, (%rax)
leaq -0xc0(%rbp), %rsi
callq 0x3c20
movq %rax, -0x130(%rbp)
jmp 0x3a99
movq -0x130(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0xc0(%rbp), %rax
movq %rax, -0x140(%rbp)
movq -0xb8(%rbp), %rsi
leaq -0x88(%rbp), %rdi
callq 0x7a80
movq -0x140(%rbp), %rcx
movq %rcx, (%rax)
movq -0xb8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb8(%rbp)
jmp 0x3934
jmp 0x3ae8
movq -0x28(%rbp), %rax
addq -0xb0(%rbp), %rax
movq %rax, -0xb0(%rbp)
jmp 0x3863
movq -0x68(%rbp), %rax
movq -0x70(%rbp), %rcx
subq %rcx, %rax
sarq $0x2, %rax
movq %rax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
movq -0x98(%rbp), %rsi
callq 0x78a0
jmp 0x3b27
leaq -0x88(%rbp), %rdi
callq 0x7ac0
leaq -0x40(%rbp), %rdi
callq 0x7b20
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
leaq -0x40(%rbp), %rdi
callq 0x7b20
movq -0x50(%rbp), %rdi
callq 0x3470
nopw (%rax,%rax)