absl::Status RangeDecoder::CheckForErrorInternal()

in tensorflow_compression/cc/lib/range_coder.cc [325:365]


absl::Status RangeDecoder::CheckForErrorInternal(absl::Span<const T> cdf,
                                                 int precision,
                                                 bool allow_zero) const {
  if (ABSL_PREDICT_FALSE(!(0 < precision && precision <= 16))) {
    return absl::InvalidArgumentError(absl::StrCat(
        "precision not in (0, 16]: ", precision));
  }
  if (ABSL_PREDICT_FALSE(cdf.size() <= 1)) {
    return absl::InvalidArgumentError(absl::StrCat(
        "cdf.size() = ", cdf.size(), " <= 1"));
  }

  for (typename absl::Span<const T>::size_type i = 0; i + 1 < cdf.size(); ++i) {
    bool monotonic = cdf[i] < cdf[i + 1];
    monotonic |= (allow_zero && cdf[i] == cdf[i + 1]);
    if (ABSL_PREDICT_FALSE(!monotonic)) {
      return absl::InvalidArgumentError("cdf is not monotonic");
    }
  }

  const T first = cdf[0];
  const T last = cdf[cdf.size() - 1];
  if (ABSL_PREDICT_FALSE(!(0 <= first && last <= (1 << precision)))) {
    return absl::InvalidArgumentError(absl::StrCat(
        "cdf values must be between 0 and ", 1 << precision));
  }

  const uint64_t size = static_cast<uint64_t>(size_minus1_) + 1;
  const uint64_t smallest = (static_cast<uint64_t>(value_ - base_) + 1)
                            << precision;
  if (ABSL_PREDICT_FALSE(!(size * static_cast<uint64_t>(first) < smallest))) {
    return absl::InvalidArgumentError(absl::StrCat(
        "cdf[0]=", first, " is too large and there was a decode error"));
  }
  if (ABSL_PREDICT_FALSE(!(smallest <= size * static_cast<uint64_t>(last)))) {
    return absl::InvalidArgumentError(absl::StrCat(
        "cdf[^1]=", last, " is too small and there was a decode error"));
  }

  return absl::OkStatus();
}