1import sys
2import os
3
4nbits = int(sys.argv[1])
5
6for block_size in range(1, nbits + 1):
7    if (block_size * 8) % nbits == 0:
8        break
9
10def gen_pack_bytes(num_values):
11    code = []
12    nbytes = (num_values * nbits + 7) // 8
13    for i in range(num_values):
14        code.append('const unsigned char s{} = *src++;'.format(i))
15    for i in range(nbytes):
16        byte_shift = i * 8
17        byte_mask = 0xff << byte_shift
18        values = []
19        for j in range(num_values):
20            value_shift = j * nbits
21            value_mask = ((1 << nbits) - 1) << value_shift
22            mask = value_mask & byte_mask
23            if not mask:
24                continue
25            if value_shift == byte_shift:
26                values.append('((s{} & 0x{:02x}))'.format(j, mask >> value_shift))
27            elif value_shift > byte_shift:
28                values.append('((s{} & 0x{:02x}) << {})'.format(j, mask >> value_shift, value_shift - byte_shift))
29            else:
30                values.append('((s{} & 0x{:02x}) >> {})'.format(j, mask >> value_shift, byte_shift - value_shift))
31        code.append('*dest++ = (unsigned char) {};'.format(' | '.join(values)))
32    return i + 1, code
33
34print '// Copyright (C) 2016  Lukas Lalinsky'
35print '// Distributed under the MIT license, see the LICENSE file for details.'
36print
37print '// This file was automatically generate using {}, do not edit.'.format(os.path.basename(__file__))
38print
39print '#ifndef CHROMAPRINT_UTILS_PACK_INT{}_ARRAY_H_'.format(nbits)
40print '#define CHROMAPRINT_UTILS_PACK_INT{}_ARRAY_H_'.format(nbits)
41print
42print '#include <algorithm>'
43print
44print 'namespace chromaprint {'
45print
46print 'inline size_t GetPackedInt{}ArraySize(size_t size) {{'.format(nbits)
47print '\treturn (size * {} + {}) / {};'.format(block_size, block_size * 8 // nbits - 1, block_size * 8 // nbits)
48print '}'
49print
50print 'template <typename InputIt, typename OutputIt>'
51print 'inline OutputIt PackInt{}Array(const InputIt first, const InputIt last, OutputIt dest) {{'.format(nbits)
52print '\tauto size = std::distance(first, last);'
53print '\tauto src = first;'
54first_if = True
55for nbytes in range(block_size * 8 // nbits, 0, -1):
56    if nbytes == block_size * 8 // nbits:
57        print '\twhile (size >= {}) {{'.format(nbytes)
58    else:
59        if not first_if:
60            print 'else',
61        else:
62            print '\t',
63        print 'if (size == {}) {{'.format(nbytes)
64        first_if = False
65    packed_bits, code = gen_pack_bytes(nbytes)
66    for line in code:
67        print '\t\t{}'.format(line)
68    if nbytes == block_size * 8 // nbits:
69        print '\t\tsize -= {};'.format(nbytes)
70    if nbytes == block_size * 8 // nbits or nbytes == 1:
71        print '\t}'
72    else:
73        print '\t}',
74print '\t return dest;'
75print '}'
76print
77print '}; // namespace chromaprint'
78print
79print '#endif'
80