///| CRC32 implementation for gzip

///|
let crc32_poly : UInt = (Int::reinterpret_as_uint(237) << 24) |
  (Int::reinterpret_as_uint(184) << 16) |
  (Int::reinterpret_as_uint(131) << 8) |
  Int::reinterpret_as_uint(32)

///|
fn build_crc32_table() -> FixedArray[UInt] {
  FixedArray::makei(256, fn(i) {
    let mut c = i.reinterpret_as_uint()
    for _ in 0..<8 {
      if (c & Int::reinterpret_as_uint(1)) == Int::reinterpret_as_uint(1) {
        c = (c >> 1) ^ crc32_poly
      } else {
        c = c >> 1
      }
    }
    c
  })
}

///|
let crc32_table : FixedArray[UInt] = build_crc32_table()

///|
/// Reflected CRC-32 (zlib/gzip polynomial 0xEDB88320). Slicing-by-8 bulk
/// path delegates to a target-conditional inner loop (`crc32_bulk_impl`),
/// then finishes the trailing 0–7 bytes with the standard byte table.
///
/// Inner loop dispatch:
///   * wasm     — `crc32_simd.mbt`, inline-WAT with direct `i32.load`s
///                of the input bytes and 8 parallel `i32.load`s from a
///                flattened slicing-by-8 table.
///   * other    — `crc32_scalar.mbt`, pure-MoonBit slicing-by-8.
pub fn crc32(data : Bytes) -> UInt {
  let mut crc : UInt = Int::reinterpret_as_uint(-1)
  let len = data.length()
  let bulk_end = len & -8
  if bulk_end > 0 {
    crc = Int::reinterpret_as_uint(
      crc32_bulk_impl(data, bulk_end, crc.reinterpret_as_int()),
    )
  }
  let mut i = bulk_end
  while i < len {
    let idx = UInt::reinterpret_as_int(
      (crc ^ Int::reinterpret_as_uint(data[i].to_int())) & 0xFFU,
    )
    crc = (crc >> 8) ^ crc32_table[idx]
    i = i + 1
  }
  crc ^ Int::reinterpret_as_uint(-1)
}

///|
pub fn crc32_fixed(data : FixedArray[Byte]) -> UInt {
  crc32(Bytes::from_array(data))
}