///|
/// Check whether a floating-point value is finite (not NaN, not Inf).
pub fn is_finite(value : Double) -> Bool {
  !value.is_nan() && !value.is_inf()
}

///|
/// Check whether a floating-point value is finite and strictly positive.
pub fn is_finite_positive(value : Double) -> Bool {
  !value.is_nan() && !value.is_inf() && value > 0.0
}

///|
/// Compute the effective number of samples to process, bounded by both
/// the context block size and the buffer length.
pub fn effective_sample_count(
  context : DspContext,
  buffer : AudioBuffer,
) -> Int {
  if buffer.length() < context.block_size() {
    buffer.length()
  } else {
    context.block_size()
  }
}

///|
/// Replace non-finite samples (NaN, Inf) with 0.0 in-place.
/// Returns the number of samples replaced. This is the output firewall —
/// the last line of defense before samples leave the DSP engine.
pub fn sanitize_buffer(buffer : AudioBuffer, sample_count : Int) -> Int {
  let count = if sample_count > buffer.length() {
    buffer.length()
  } else if sample_count < 0 {
    0
  } else {
    sample_count
  }
  let mut sanitized = 0
  for i = 0; i < count; i = i + 1 {
    if !is_finite(buffer.get(i)) {
      buffer.set(i, 0.0)
      sanitized = sanitized + 1
    }
  }
  sanitized
}