#include "crc32i.h"

/* This builds our CRC table at compile-time rather than runtime.
 * Note: We should have a way to change the polynomial at runtime too. */

#define CRC32_MASK(crc) (-((crc) & 1))

/* Does one iteration of the 8-time loop to generate one byte of the CRC table. */
#define CRC32_PRECALC_EX(crc) (((crc) >> 1) ^ ((CRC32_POLYNOMIAL) & CRC32_MASK(crc)))

/* Does all eight iterations of the loop to generate one byte. */
#define CRC32_PRECALC_E(byte) \
	(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(CRC32_PRECALC_EX(byte)))))))))

/* Simple wrapper of CRC32_PRECALC_E that converts everything to uint32_t */
#define CRC32_PRECALC(byte) \
	CRC32_PRECALC_E((uint32_t)(byte))

#define CRC32_PRECALC_0(byte) \
	CRC32_PRECALC(byte), CRC32_PRECALC((byte) | 0x01)

#define CRC32_PRECALC_1(byte) \
	CRC32_PRECALC_0(byte), CRC32_PRECALC_0((byte) | UINT32_C(0x02))

#define CRC32_PRECALC_2(byte) \
	CRC32_PRECALC_1(byte), CRC32_PRECALC_1((byte) | UINT32_C(0x04))

#define CRC32_PRECALC_3(byte) \
	CRC32_PRECALC_2(byte), CRC32_PRECALC_2((byte) | UINT32_C(0x08))

#define CRC32_PRECALC_4(byte) \
	CRC32_PRECALC_3(byte), CRC32_PRECALC_3((byte) | UINT32_C(0x10))

#define CRC32_PRECALC_5(byte) \
	CRC32_PRECALC_4(byte), CRC32_PRECALC_4((byte) | UINT32_C(0x20))

#define CRC32_PRECALC_6(byte) \
	CRC32_PRECALC_5(byte), CRC32_PRECALC_5((byte) | UINT32_C(0x40))

#define CRC32_PRECALC_7(byte) \
	CRC32_PRECALC_6(byte), CRC32_PRECALC_6((byte) | UINT32_C(0x80))

const uint32_t crc32_tab[256] = {
	CRC32_PRECALC_7(0)
};

#undef CRC32_MASK
#undef CRC32_PRECALC_EX
#undef CRC32_PRECALC_E
#undef CRC32_PRECALC
#undef CRC32_PRECALC_0
#undef CRC32_PRECALC_1
#undef CRC32_PRECALC_2
#undef CRC32_PRECALC_3
#undef CRC32_PRECALC_4
#undef CRC32_PRECALC_5
#undef CRC32_PRECALC_6
#undef CRC32_PRECALC_7
