// File: ALSchwalm[P]entrospy/entrospy/shannon.cpp
// Function: shannon_score(std::array<unsigned long, 256ul> const&, unsigned long, DataFormat)
double shannon_score(const counter_t& counts, std::size_t total_size,
                     DataFormat format) {
    const allowed_t* allowed = nullptr;
    switch (format) {
    case DataFormat::DATA:
        allowed = &ALLOWED_DATA;
        break;
    case DataFormat::TEXT:
        allowed = &ALLOWED_TEXT;
        break;
    case DataFormat::BASE64:
        allowed = &ALLOWED_BASE64;
        break;
    }

    double score = 0;
    for (std::size_t index = 0; index < counts.size(); ++index) {
        auto count = counts[index];
        if (count == 0 || !(*allowed)[index])
            continue;
        double p_i = count / static_cast<double>(total_size);
        score += p_i * log2(p_i);
    }

    switch (format) {
    case DataFormat::DATA:
        return std::abs(score) / 8.0;
    case DataFormat::TEXT:
        return std::abs(score) / 7.0;
    case DataFormat::BASE64:
        return std::abs(score) / 6.0;
    }
    return 0.0;
}

// Assembly:
subq $0x68, %rsp
movq %rdi, 0x58(%rsp)
movq %rsi, 0x50(%rsp)
movl %edx, 0x4c(%rsp)
movq $0x0, 0x40(%rsp)
movl 0x4c(%rsp), %eax
movl %eax, 0x1c(%rsp)
subl $0x40, %eax
je 0x31f30
jmp 0x31efa
movl 0x1c(%rsp), %eax
subl $0x80, %eax
je 0x31f22
jmp 0x31f07
movl 0x1c(%rsp), %eax
subl $0x100, %eax            # imm = 0x100
jne 0x31f3c
jmp 0x31f14
leaq 0x66de(%rip), %rax      # 0x385f9
movq %rax, 0x40(%rsp)
jmp 0x31f3c
leaq 0x67d0(%rip), %rax      # 0x386f9
movq %rax, 0x40(%rsp)
jmp 0x31f3c
leaq 0x68c2(%rip), %rax      # 0x387f9
movq %rax, 0x40(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x38(%rsp)
movq $0x0, 0x30(%rsp)
movq 0x30(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x58(%rsp), %rdi
callq 0x32760
movq %rax, %rcx
movq 0x10(%rsp), %rax
cmpq %rcx, %rax
jae 0x3203a
movq 0x58(%rsp), %rdi
movq 0x30(%rsp), %rsi
callq 0x32770
movq (%rax), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, 0x28(%rsp)
je 0x31fa6
movq 0x40(%rsp), %rdi
movq 0x30(%rsp), %rsi
callq 0x327a0
testb $0x1, (%rax)
jne 0x31fa8
jmp 0x32027
movq 0x28(%rsp), %xmm0
movaps 0x641b(%rip), %xmm3     # 0x383d0
punpckldq %xmm3, %xmm0    # xmm0 = xmm0[0],xmm3[0],xmm0[1],xmm3[1]
movapd 0x641f(%rip), %xmm2     # 0x383e0
subpd %xmm2, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movq 0x50(%rsp), %xmm1
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
subpd %xmm2, %xmm1
movaps %xmm1, %xmm2
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x20(%rsp), %xmm0
callq 0xa9e0
movaps %xmm0, %xmm2
movsd 0x8(%rsp), %xmm0
movsd 0x38(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movq 0x30(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x30(%rsp)
jmp 0x31f4e
movl 0x4c(%rsp), %eax
movl %eax, 0x4(%rsp)
subl $0x40, %eax
je 0x320a1
jmp 0x32049
movl 0x4(%rsp), %eax
subl $0x80, %eax
je 0x32082
jmp 0x32056
movl 0x4(%rsp), %eax
subl $0x100, %eax            # imm = 0x100
jne 0x320c0
jmp 0x32063
movsd 0x38(%rsp), %xmm0
callq 0x327d0
movsd 0x649a(%rip), %xmm1     # 0x38510
divsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
jmp 0x320c9
movsd 0x38(%rsp), %xmm0
callq 0x327d0
movsd 0x6473(%rip), %xmm1     # 0x38508
divsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
jmp 0x320c9
movsd 0x38(%rsp), %xmm0
callq 0x327d0
movsd 0x644c(%rip), %xmm1     # 0x38500
divsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
jmp 0x320c9
xorps %xmm0, %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0x60(%rsp), %xmm0
addq $0x68, %rsp
retq
nopw %cs:(%rax,%rax)