// SIMD-accelerated byte-scan and UTF-8 decode helpers for the parser hot path
// (via `@v128`, MoonBit's 128-bit SIMD intrinsics).

///| Index of the first byte that is NOT printable ASCII (`0x20..=0x7e`; DEL

///|
/// `0x7f` is a C0 control), or `bytes.length()` if every byte is printable.
pub fn first_non_printable(bytes : ArrayView[Int]) -> Int {
  // Fast path: the next byte is usually the match on escape-dense streams.
  if bytes.length() > 0 {
    let b0 = bytes[0]
    if !(b0 >= 0x20 && b0 <= 0x7e) {
      return 0
    }
  }
  let n = bytes.length()
  let mut offset = 0
  while offset + 16 <= n {
    let v = load16(bytes, offset)
    // b < 0x20 (control) or b >= 0x7f (DEL + high-bit).
    let special = @v128.v128_or_(
      @v128.i8x16_lt_u(v, @v128.i8x16_splat(0x20)),
      @v128.i8x16_ge_u(v, @v128.i8x16_splat(0x7f)),
    )
    if @v128.v128_any_true(special) {
      let mask = @v128.i8x16_bitmask(special)
      return offset + first_set(mask)
    }
    offset = offset + 16
  }
  // Scalar tail (< 16 bytes).
  while offset < n {
    let b = bytes[offset]
    if !(b >= 0x20 && b <= 0x7e) {
      return offset
    }
    offset = offset + 1
  }
  n
}

///|
/// Index of the first ESC byte (`0x1b`), or `bytes.length()` if none.
pub fn first_esc(bytes : ArrayView[Int]) -> Int {
  let n = bytes.length()
  let mut offset = 0
  while offset + 16 <= n {
    let v = load16(bytes, offset)
    let special = @v128.i8x16_eq(v, @v128.i8x16_splat(0x1b))
    if @v128.v128_any_true(special) {
      let mask = @v128.i8x16_bitmask(special)
      return offset + first_set(mask)
    }
    offset = offset + 16
  }
  while offset < n {
    if bytes[offset] == 0x1b {
      return offset
    }
    offset = offset + 1
  }
  n
}

///| Branchless decode of a UTF-8 code point already validated by the caller.

///| Assumes `b[0]` is a 2/3/4-byte lead with its continuation bytes present.

///|
/// Returns `(code_point, byte_length)`.
pub fn decode_validated(b : ArrayView[Int], pos : Int) -> (Int, Int) {
  let b0 = b[pos]
  match b0 {
    0xc2..=0xdf => (((b0 & 0x1f) << 6) | (b[pos + 1] & 0x3f), 2)
    0xe0..=0xef =>
      (
        ((b0 & 0x0f) << 12) | ((b[pos + 1] & 0x3f) << 6) | (b[pos + 2] & 0x3f),
        3,
      )
    _ =>
      (
        ((b0 & 0x07) << 18) |
        ((b[pos + 1] & 0x3f) << 12) |
        ((b[pos + 2] & 0x3f) << 6) |
        (b[pos + 3] & 0x3f),
        4,
      )
  }
}

///|
/// Load 16 bytes from `bytes` at `offset` into a `V128`.
fn load16(bytes : ArrayView[Int], offset : Int) -> V128 {
  @v128.i8x16_const(
    bytes[offset].to_byte(),
    bytes[offset + 1].to_byte(),
    bytes[offset + 2].to_byte(),
    bytes[offset + 3].to_byte(),
    bytes[offset + 4].to_byte(),
    bytes[offset + 5].to_byte(),
    bytes[offset + 6].to_byte(),
    bytes[offset + 7].to_byte(),
    bytes[offset + 8].to_byte(),
    bytes[offset + 9].to_byte(),
    bytes[offset + 10].to_byte(),
    bytes[offset + 11].to_byte(),
    bytes[offset + 12].to_byte(),
    bytes[offset + 13].to_byte(),
    bytes[offset + 14].to_byte(),
    bytes[offset + 15].to_byte(),
  )
}

///|
/// Index of the first non-zero lane in a 16-bit mask.
fn first_set(mask : Int) -> Int {
  for j = 0; j < 16; j = j + 1 {
    if (mask & (1 << j)) != 0 {
      return j
    }
  }
  16
}