// File: dgboy2000[P]compress/compress.cpp
// Function: test_bwt()
void test_bwt() {
    int i, n = 6;
    int s[] = {0,1,3,0,2,0};
    int bwt_expected[] = {0,2,INT_MIN,3,0,0,1,0,0,2};
    int *bwt, *decoded;
    
    vector<int> vec_s, vec_bwt, vec_bwt_expected, vec_decoded;
    
    DATCompression dat;
    dat.init();
    
    bwt = dat.burrows_wheeler_encode(s, n);
    decoded = dat.burrows_wheeler_decode(bwt, n);
    
    for (i=0; i<n+4; ++i) {
        if (bwt[i] != bwt_expected[i]) {
            printf("FAIL: bwt[%d] = %d != bwt_expected[%d] = %d\n", i, bwt[i], i, bwt_expected[i]);
            goto test_btw_cleanup;
        }
    }
    printf("PASS: burrows_wheeler_encode is correct\n");
    
    for (i=0; i<n; ++i) {
        if (s[i] != decoded[i]) {
            printf("FAIL: s[%d] = %d != decoded[%d] = %d\n", i, s[i], i, decoded[i]);
            goto test_btw_cleanup;
        }
    }
    printf("PASS: burrows_wheeler_decode is correct\n");
    
    vec_s.reserve(n);
    vec_bwt_expected.reserve(n+4);
    copy(s, s+n, back_inserter(vec_s));
    copy(bwt_expected, bwt_expected+n+4, back_inserter(vec_bwt_expected));
    vec_bwt_expected[vec_bwt_expected.back()] = 0; // In vector bwt, $ is '0' instead of 'INT_MIN'
    
    vec_bwt = dat.burrows_wheeler_encode(vec_s);
    vec_decoded = dat.burrows_wheeler_decode(vec_bwt);
    
    for (i=0; i<n+4; ++i) {
        if (vec_bwt[i] != vec_bwt_expected[i]) {
            printf("FAIL: vec_bwt[%d] = %d != vec_bwt_expected[%d] = %d\n", i, bwt[i], i, bwt_expected[i]);
            goto test_btw_cleanup;
        }
    }
    printf("PASS: vector burrows_wheeler_encode is correct\n");
    
    for (i=0; i<n; ++i) {
        if (vec_s[i] != vec_decoded[i]) {
            printf("FAIL: vec_s[%d] = %d != vec_decoded[%d] = %d\n", i, vec_s[i], i, vec_decoded[i]);
            goto test_btw_cleanup;
        }
    }
    printf("PASS: vector burrows_wheeler_decode is correct\n");
    
    n=1000;
    vec_s.clear();
    vec_s.reserve(n);
    for (i=0; i<n; ++i) vec_s.push_back(rand() % 256);
    vec_bwt = dat.burrows_wheeler_encode(vec_s);
    vec_decoded = dat.burrows_wheeler_decode(vec_bwt);
    for (i=0; i<n; ++i) {
        if (vec_s[i] != vec_decoded[i]) {
            printf("FAIL: random vec_s[%d] = %d != vec_decoded[%d] = %d\n", i, vec_s[i], i, vec_decoded[i]);
            goto test_btw_cleanup;
        }
    }
    printf("PASS: random burrows_wheeler_decode is correct\n");        
    
test_btw_cleanup:
    free(bwt);
    free(decoded);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x270, %rsp            # imm = 0x270
movl $0x6, -0x8(%rbp)
movaps 0x9297(%rip), %xmm0     # 0x10670
movaps %xmm0, -0x20(%rbp)
movq $0x2, -0x10(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0x40(%rbp)
movaps %xmm0, -0x50(%rbp)
movq $0x0, -0x30(%rbp)
movl $0x2, -0x4c(%rbp)
movl $0x80000000, -0x48(%rbp) # imm = 0x80000000
movl $0x3, -0x44(%rbp)
movl $0x1, -0x38(%rbp)
movl $0x2, -0x2c(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x8d20
leaq -0x90(%rbp), %rdi
callq 0x8d20
leaq -0xa8(%rbp), %rdi
callq 0x8d20
leaq -0xc0(%rbp), %rdi
callq 0x8d20
leaq -0xc4(%rbp), %rdi
callq 0x98c0
jmp 0x7456
movl -0x8(%rbp), %edx
leaq -0xc4(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x5fe0
movq %rax, -0x1c8(%rbp)
jmp 0x7472
movq -0x1c8(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rsi
movl -0x8(%rbp), %edx
leaq -0xc4(%rbp), %rdi
callq 0x61b0
movq %rax, -0x1d0(%rbp)
jmp 0x7499
movq -0x1d0(%rbp), %rax
movq %rax, -0x60(%rbp)
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
movl -0x8(%rbp), %ecx
addl $0x4, %ecx
cmpl %ecx, %eax
jge 0x751a
movq -0x58(%rbp), %rax
movslq -0x4(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movslq -0x4(%rbp), %rcx
cmpl -0x50(%rbp,%rcx,4), %eax
je 0x750d
movslq -0x4(%rbp), %rax
movl %eax, %ecx
movq -0x58(%rbp), %rdx
movl (%rdx,%rax,4), %edx
movl -0x50(%rbp,%rax,4), %r8d
leaq 0x8c9c(%rip), %rdi      # 0x10182
xorl %eax, %eax
movl %ecx, %esi
callq 0x2040
jmp 0x74f1
jmp 0x7b66
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
jmp 0x7bae
jmp 0x750f
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x74ab
leaq 0x8c8e(%rip), %rdi      # 0x101af
xorl %eax, %eax
callq 0x2040
jmp 0x752a
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x7584
movslq -0x4(%rbp), %rax
movl -0x20(%rbp,%rax,4), %eax
movq -0x60(%rbp), %rcx
movslq -0x4(%rbp), %rdx
cmpl (%rcx,%rdx,4), %eax
je 0x7577
movslq -0x4(%rbp), %rsi
movl %esi, %ecx
movl -0x20(%rbp,%rsi,4), %edx
movq -0x60(%rbp), %rax
movl (%rax,%rsi,4), %r8d
leaq 0x8c71(%rip), %rdi      # 0x101d8
xorl %eax, %eax
movl %ecx, %esi
callq 0x2040
jmp 0x7572
jmp 0x7b66
jmp 0x7579
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x7531
leaq 0x8c73(%rip), %rdi      # 0x101fe
xorl %eax, %eax
callq 0x2040
jmp 0x7594
movslq -0x8(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x9100
jmp 0x75a3
movl -0x8(%rbp), %eax
addl $0x4, %eax
movslq %eax, %rsi
leaq -0xa8(%rbp), %rdi
callq 0x9100
jmp 0x75ba
leaq -0x20(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movslq -0x8(%rbp), %rax
leaq -0x20(%rbp,%rax,4), %rax
movq %rax, -0x1e0(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x9930
movq %rax, -0x1d8(%rbp)
jmp 0x75e7
movq -0x1e0(%rbp), %rsi
movq -0x1e8(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0xe0(%rbp), %rdx
callq 0x98e0
movq %rax, -0x1f0(%rbp)
jmp 0x7618
movq -0x1f0(%rbp), %rax
movq %rax, -0xe8(%rbp)
leaq -0x50(%rbp), %rax
movq %rax, -0x208(%rbp)
movslq -0x8(%rbp), %rax
leaq -0x40(%rbp,%rax,4), %rax
movq %rax, -0x200(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x9930
movq %rax, -0x1f8(%rbp)
jmp 0x7656
movq -0x200(%rbp), %rsi
movq -0x208(%rbp), %rdi
movq -0x1f8(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rdx
callq 0x98e0
movq %rax, -0x210(%rbp)
jmp 0x7687
movq -0x210(%rbp), %rax
movq %rax, -0xf8(%rbp)
leaq -0xa8(%rbp), %rdi
movq %rdi, -0x218(%rbp)
callq 0x9340
movq -0x218(%rbp), %rdi
movslq (%rax), %rsi
callq 0x8db0
movl $0x0, (%rax)
leaq -0x128(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x8f80
jmp 0x76cf
leaq -0x110(%rbp), %rdi
leaq -0xc4(%rbp), %rsi
leaq -0x128(%rbp), %rdx
callq 0x2ff0
jmp 0x76eb
leaq -0x90(%rbp), %rdi
movq %rdi, -0x220(%rbp)
leaq -0x110(%rbp), %rsi
movq %rsi, -0x228(%rbp)
callq 0x9070
movq -0x228(%rbp), %rdi
callq 0x8f20
leaq -0x128(%rbp), %rdi
callq 0x8f20
movq -0x220(%rbp), %rsi
leaq -0x158(%rbp), %rdi
callq 0x8f80
jmp 0x7739
leaq -0x140(%rbp), %rdi
leaq -0xc4(%rbp), %rsi
leaq -0x158(%rbp), %rdx
callq 0x4c50
jmp 0x7755
leaq -0xc0(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x9070
leaq -0x140(%rbp), %rdi
callq 0x8f20
leaq -0x158(%rbp), %rdi
callq 0x8f20
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
movl -0x8(%rbp), %ecx
addl $0x4, %ecx
cmpl %ecx, %eax
jge 0x784c
movslq -0x4(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x8db0
movl (%rax), %eax
movl %eax, -0x22c(%rbp)
movslq -0x4(%rbp), %rsi
leaq -0xa8(%rbp), %rdi
callq 0x8db0
movq %rax, %rcx
movl -0x22c(%rbp), %eax
cmpl (%rcx), %eax
je 0x783c
movslq -0x4(%rbp), %rax
movl %eax, %ecx
movq -0x58(%rbp), %rdx
movl (%rdx,%rax,4), %edx
movl -0x50(%rbp,%rax,4), %r8d
leaq 0x8a41(%rip), %rdi      # 0x10227
xorl %eax, %eax
movl %ecx, %esi
callq 0x2040
jmp 0x77f1
jmp 0x7b66
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x128(%rbp), %rdi
callq 0x8f20
jmp 0x7bae
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x158(%rbp), %rdi
callq 0x8f20
jmp 0x7bae
jmp 0x783e
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x7787
leaq 0x8a09(%rip), %rdi      # 0x1025c
xorl %eax, %eax
callq 0x2040
jmp 0x785c
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x7910
movslq -0x4(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x8db0
movl (%rax), %eax
movl %eax, -0x230(%rbp)
movslq -0x4(%rbp), %rsi
leaq -0xc0(%rbp), %rdi
callq 0x8db0
movq %rax, %rcx
movl -0x230(%rbp), %eax
cmpl (%rcx), %eax
je 0x7900
movl -0x4(%rbp), %eax
movl %eax, -0x23c(%rbp)
movslq %eax, %rsi
leaq -0x78(%rbp), %rdi
callq 0x8db0
movl (%rax), %eax
movl %eax, -0x238(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x234(%rbp)
movslq %eax, %rsi
leaq -0xc0(%rbp), %rdi
callq 0x8db0
movl -0x23c(%rbp), %esi
movl -0x238(%rbp), %edx
movl -0x234(%rbp), %ecx
movl (%rax), %r8d
leaq 0x899a(%rip), %rdi      # 0x1028c
xorl %eax, %eax
callq 0x2040
jmp 0x78fb
jmp 0x7b66
jmp 0x7902
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x7863
leaq 0x89a3(%rip), %rdi      # 0x102ba
xorl %eax, %eax
callq 0x2040
jmp 0x7920
movl $0x3e8, -0x8(%rbp)      # imm = 0x3E8
leaq -0x78(%rbp), %rdi
movq %rdi, -0x248(%rbp)
callq 0x90c0
movq -0x248(%rbp), %rdi
movslq -0x8(%rbp), %rsi
callq 0x9100
jmp 0x7949
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x7999
callq 0x20a0
movl %eax, %edx
addl $0xff, %edx
testl %eax, %eax
movl %eax, %ecx
cmovsl %edx, %ecx
andl $0xffffff00, %ecx       # imm = 0xFFFFFF00
subl %ecx, %eax
movl %eax, -0x15c(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x15c(%rbp), %rsi
callq 0x8ed0
jmp 0x798c
jmp 0x798e
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x7950
leaq -0x190(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x8f80
jmp 0x79ab
leaq -0x178(%rbp), %rdi
leaq -0xc4(%rbp), %rsi
leaq -0x190(%rbp), %rdx
callq 0x2ff0
jmp 0x79c7
leaq -0x90(%rbp), %rdi
movq %rdi, -0x250(%rbp)
leaq -0x178(%rbp), %rsi
movq %rsi, -0x258(%rbp)
callq 0x9070
movq -0x258(%rbp), %rdi
callq 0x8f20
leaq -0x190(%rbp), %rdi
callq 0x8f20
movq -0x250(%rbp), %rsi
leaq -0x1c0(%rbp), %rdi
callq 0x8f80
jmp 0x7a15
leaq -0x1a8(%rbp), %rdi
leaq -0xc4(%rbp), %rsi
leaq -0x1c0(%rbp), %rdx
callq 0x4c50
jmp 0x7a31
leaq -0xc0(%rbp), %rdi
leaq -0x1a8(%rbp), %rsi
callq 0x9070
leaq -0x1a8(%rbp), %rdi
callq 0x8f20
leaq -0x1c0(%rbp), %rdi
callq 0x8f20
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x7b54
movslq -0x4(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x8db0
movl (%rax), %eax
movl %eax, -0x25c(%rbp)
movslq -0x4(%rbp), %rsi
leaq -0xc0(%rbp), %rdi
callq 0x8db0
movq %rax, %rcx
movl -0x25c(%rbp), %eax
cmpl (%rcx), %eax
je 0x7b44
movl -0x4(%rbp), %eax
movl %eax, -0x268(%rbp)
movslq %eax, %rsi
leaq -0x78(%rbp), %rdi
callq 0x8db0
movl (%rax), %eax
movl %eax, -0x264(%rbp)
movl -0x4(%rbp), %eax
movl %eax, -0x260(%rbp)
movslq %eax, %rsi
leaq -0xc0(%rbp), %rdi
callq 0x8db0
movl -0x268(%rbp), %esi
movl -0x264(%rbp), %edx
movl -0x260(%rbp), %ecx
movl (%rax), %r8d
leaq 0x87f4(%rip), %rdi      # 0x102ea
xorl %eax, %eax
callq 0x2040
jmp 0x7aff
jmp 0x7b66
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x190(%rbp), %rdi
callq 0x8f20
jmp 0x7bae
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xd0(%rbp)
movl %eax, -0xd4(%rbp)
leaq -0x1c0(%rbp), %rdi
callq 0x8f20
jmp 0x7bae
jmp 0x7b46
movl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4(%rbp)
jmp 0x7a63
leaq 0x87c4(%rip), %rdi      # 0x1031f
xorl %eax, %eax
callq 0x2040
jmp 0x7b64
jmp 0x7b66
movq -0x58(%rbp), %rdi
callq 0x22a0
movq -0x60(%rbp), %rdi
callq 0x22a0
leaq -0xc0(%rbp), %rdi
callq 0x8f20
leaq -0xa8(%rbp), %rdi
callq 0x8f20
leaq -0x90(%rbp), %rdi
callq 0x8f20
leaq -0x78(%rbp), %rdi
callq 0x8f20
addq $0x270, %rsp            # imm = 0x270
popq %rbp
retq
leaq -0xc0(%rbp), %rdi
callq 0x8f20
leaq -0xa8(%rbp), %rdi
callq 0x8f20
leaq -0x90(%rbp), %rdi
callq 0x8f20
leaq -0x78(%rbp), %rdi
callq 0x8f20
movq -0xd0(%rbp), %rdi
callq 0x2380
nopw (%rax,%rax)