lean4-htt/src/Init/Data/String/Lemmas/Pattern/Memcmp.lean
Markus Himmel 57a6d89f57
feat: verification of BEq String.Slice (#12346)
This PR shows `s == t ↔ s.copy = t.copy` for `s t : String.Slice` and
establishes the right-hand side as the simp normal form.
2026-02-06 11:56:01 +00:00

65 lines
3 KiB
Text

/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Markus Himmel
-/
module
prelude
public import Init.Data.String.Pattern.Basic
import all Init.Data.String.Pattern.Basic
import Init.Data.ByteArray.Lemmas
import Init.ByCases
import Init.Data.Nat.MinMax
public section
namespace String.Slice.Pattern.Internal
theorem memcmpStr_eq_true_iff {lhs rhs : String} {lstart rstart len : String.Pos.Raw}
{h₁ h₂} : memcmpStr lhs rhs lstart rstart len h₁ h₂ = true ↔
lhs.toByteArray.extract lstart.byteIdx (len.offsetBy lstart).byteIdx =
rhs.toByteArray.extract rstart.byteIdx (len.offsetBy rstart).byteIdx := by
suffices ∀ (curr : String.Pos.Raw),
memcmpStr.go lhs rhs lstart rstart len h₁ h₂ curr = true ↔
lhs.toByteArray.extract (curr.offsetBy lstart).byteIdx (len.offsetBy lstart).byteIdx =
rhs.toByteArray.extract (curr.offsetBy rstart).byteIdx (len.offsetBy rstart).byteIdx by
simp [memcmpStr, this]
intro curr
simp [Pos.Raw.le_iff] at h₁ h₂
by_cases hc : len.byteIdx < curr.byteIdx
· rw [ByteArray.extract_eq_empty_iff.2, ByteArray.extract_eq_empty_iff.2, memcmpStr.go,
dif_neg (Std.not_lt.2 (Std.le_of_lt (Pos.Raw.lt_iff.2 hc)))]
simp only
all_goals simp; omega
· simp only [Pos.Raw.byteIdx_offsetBy]
rw [(by omega : len.byteIdx = curr.byteIdx + (len.byteIdx - curr.byteIdx)),
← Nat.add_assoc, ← Nat.add_assoc,
ByteArray.extract_eq_extract_iff_getElem (by simp; omega) (by simp; omega)]
fun_induction memcmpStr.go with
| case1 p h₃ h₄ h₅ h ih =>
rw [Pos.Raw.lt_iff] at h₃
rw [ih (by simp; omega)]
simp only [String.getUTF8Byte, Pos.Raw.byteIdx_offsetBy, beq_iff_eq] at h
simp only [Pos.Raw.byteIdx_inc, Nat.add_assoc, Nat.add_comm 1]
refine ⟨fun h k hk => ?_, fun h k hk => h (k + 1) (by omega)⟩
match k with
| 0 => simpa
| k + 1 => exact h k (by omega)
| case2 p h₃ h₄ h₅ h => simpa using ⟨0, by rw [Pos.Raw.lt_iff] at h₃; omega, by simpa using h⟩
| case3 p hp => simp [(by rw [Pos.Raw.lt_iff] at hp; omega : len.byteIdx = p.byteIdx)]
theorem memcmpSlice_eq_true_iff {lhs rhs : Slice} {lstart rstart len : String.Pos.Raw} {h₁ h₂} :
memcmpSlice lhs rhs lstart rstart len h₁ h₂ = true ↔
lhs.copy.toByteArray.extract lstart.byteIdx (len.offsetBy lstart).byteIdx =
rhs.copy.toByteArray.extract rstart.byteIdx (len.offsetBy rstart).byteIdx := by
rw [memcmpSlice, memcmpStr_eq_true_iff, toByteArray_copy, toByteArray_copy,
ByteArray.extract_extract, ByteArray.extract_extract]
simp only [Pos.Raw.byteIdx_offsetBy, Nat.add_assoc]
have h₃ := lhs.startInclusive_le_endExclusive
have h₄ := rhs.startInclusive_le_endExclusive
simp only [Pos.Raw.le_iff, Pos.Raw.byteIdx_offsetBy, byteIdx_rawEndPos, utf8ByteSize_eq,
String.Pos.le_iff] at h₁ h₂ h₃ h₄
rw [Nat.min_eq_left (by omega), Nat.min_eq_left (by omega)]
end String.Slice.Pattern.Internal