libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
crc_tables_generate.c
1#if 0
2 cc --std=c23 "$0" -O3 -o "$0.out"
3 ./"$0.out"
4 rm "$0.out"
5 exit
6#endif
7
8#include <string.h>
9#include <inttypes.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <ctype.h>
13
15 const char *name;
16 uint8_t bits;
17 uint64_t polynomial;
18 bool reflect;
19};
20
21const char *capitalise(const char *str) {
22 static char ret[64];
23 int i = 0;
24 while (i < 64 && i < strlen(str)) {
25 ret[i] = toupper(str[i]);
26 i++;
27 }
28 ret[i] = '\0';
29 return ret;
30}
31
32#define TABLE_LEN(details) ((details).bits >= 8 ? 256u : 1u << (details).bits)
33#define MASK(details) ((details).bits == 64 ? ~UINT64_C(0) : (UINT64_C(1) << (details).bits) - UINT64_C(1))
34#define HIGH_BIT(details) (UINT64_C(1) << ((details).bits - 1))
35#define HIGH_BYTE_OFFSET(details) ((details).bits - 8)
36#define TYPE_NAME(details) (\
37 (details).bits > 32 ? "uint64_t" :\
38 (details).bits > 16 ? "uint32_t" :\
39 (details).bits > 8 ? "uint16_t" :\
40 "uint8_t"\
41)
42#define LITERAL_WRAPPER(details) (\
43 (details).bits > 32 ? "UINT64_C" :\
44 (details).bits > 16 ? "UINT32_C" :\
45 (details).bits > 8 ? "UINT16_C" :\
46 "UINT8_C"\
47)
48
49uint64_t reflect(const uint64_t n, const uint8_t bits) {
50 uint64_t r = 0;
51 for (uint8_t i = 0; i < bits; i++) {
52 r |= (n >> i & 1) << (bits - i - 1);
53 }
54 if (bits == 64)
55 return r;
56 return r & ((UINT64_C(1) << bits) - 1);
57}
58void table_gen(uint64_t *table, const struct crc_details details) {
59 const uint64_t polynomial = details.polynomial & MASK(details);
60
61 uint64_t crc;
62 for (uint64_t i = 0; i < TABLE_LEN(details); i++) {
63 if (details.reflect)
64 crc = reflect(i, details.bits);
65 else
66 crc = i << HIGH_BYTE_OFFSET(details);
67
68 for (int bit = 0; bit < 8; bit++) {
69 if (crc & HIGH_BIT(details))
70 crc = crc << 1 ^ polynomial;
71 else
72 crc <<= 1;
73 }
74
75 if (details.reflect)
76 table[i] = reflect(crc, details.bits);
77 else
78 table[i] = crc & MASK(details);
79 }
80}
81void power_table_gen(uint64_t *table, uint8_t bits, const struct crc_details details) {
82 uint64_t power = (details.bits <= 8) ? details.polynomial : 0x100;
83 for (uint8_t i = 0; i < bits; i++) {
84 table[i] = power;
85 uint64_t n = power, res = 0;
86 for (uint64_t j = 0; j < details.bits; j++) {
87 if (power & (UINT64_C(1) << j))
88 res ^= n;
89 if (n & HIGH_BIT(details))
90 n = (n << 1) ^ details.polynomial;
91 else
92 n <<= 1;
93 n &= MASK(details);
94 }
95 power = res;
96 }
97}
98void inverse_table_gen(uint64_t *table, const struct crc_details details) {
99 // I gave up here.
100 // There are some optimisations to be had for other crc manipulation methods,
101 // but they are not implemented in libclod yet (probably never).
102}
103void write_details(const struct crc_details details) {
104 const char *caps = capitalise(details.name);
105 printf("#define %s_BITS %d\n", caps, details.bits);
106 printf("#define %s_POLYNOMIAL %s(0x%"PRIX64")\n", caps, LITERAL_WRAPPER(details), details.polynomial);
107 printf("#define %s_NORMALISED_POLYNOMIAL %s(0x%"PRIX64")\n",
108 caps, LITERAL_WRAPPER(details), details.reflect ? reflect(details.polynomial, details.bits) : details.polynomial);
109 printf("#define %s_REFLECTED %s\n", caps, details.reflect ? "true" : "false");
110}
111void write_table(const uint64_t *table, size_t table_len, const char *suffix, const struct crc_details details) {
112 printf("static constexpr %s %s_%s[%"PRIu64"] = {\n\t", TYPE_NAME(details), details.name, suffix, (uint64_t)table_len);
113 for (size_t i = 0; i < table_len; i++) {
114 printf("%s(0x%" PRIX64 "),", LITERAL_WRAPPER(details), table[i]);
115 if (i != table_len - 1) {
116 if (i%4 == 3) {
117 printf("\n\t");
118 } else {
119 printf(" ");
120 }
121 }
122 }
123 printf("\n};\n");
124}
125int main() {
126 const struct crc_details details[] = {
127 {
128 .name = "crc64",
129 .bits = 64,
130 .polynomial = UINT64_C(0x42F0E1EBA9EA3693),
131 .reflect = false
132 },
133 {
134 .name = "crc32",
135 .bits = 32,
136 .polynomial = UINT64_C(0x1EDC6F41),
137 .reflect = true
138 },
139 {
140 .name = "crc24",
141 .bits = 24,
142 .polynomial = UINT64_C(0x864CFB),
143 .reflect = false
144 },
145 {
146 .name = "crc16",
147 .bits = 16,
148 .polynomial = UINT64_C(0x1021),
149 .reflect = true
150 },
151 {
152 .name = "crc8",
153 .bits = 8,
154 .polynomial = UINT64_C(0x07),
155 .reflect = false
156 }
157 };
158 constexpr size_t details_len = sizeof(details)/sizeof(details[0]);
159 uint64_t table[256];
160
161 printf("// generated by "__FILE__"\n");
162 printf("#ifndef LIBCLOD_CRC_TABLES_H\n");
163 printf("#define LIBCLOD_CRC_TABLES_H\n");
164 printf("#include <stdint.h>\n\n");
165 for (unsigned i = 0; i < details_len; i++) {
166 write_details(details[i]);
167
168 table_gen(table, details[i]);
169 write_table(table, 256, "table", details[i]);
170
171 power_table_gen(table, 64, details[i]);
172 write_table(table, 64, "power_table", details[i]);
173
174 if (i != details_len - 1) printf("\n");
175 }
176 printf("#endif\n");
177}
Sized string helpers.