diff --git a/src/lake/Lake/Build/Trace.lean b/src/lake/Lake/Build/Trace.lean index 891ee54d85..43a0052d4d 100644 --- a/src/lake/Lake/Build/Trace.lean +++ b/src/lake/Lake/Build/Trace.lean @@ -9,7 +9,7 @@ prelude public import Lean.Data.Json import Init.Data.Nat.Fold meta import Init.Data.Nat.Fold -import Lake.Util.String +public import Lake.Util.String public import Init.Data.String.Search public import Init.Data.String.Extra import Init.Data.Option.Coe @@ -141,8 +141,8 @@ public def ofHex? (s : String) : Option Hash := if s.utf8ByteSize = 16 && isHex s then ofHex s else none /-- Returns the hash as 16-digit lowercase hex string. -/ -public def hex (self : Hash) : String := - lpad (String.ofList <| Nat.toDigits 16 self.val.toNat) '0' 16 +@[inline] public def hex (self : Hash) : String := + lowerHexUInt64 self.val /-- Parse a hash from a string of decimal digits. -/ public def ofDecimal? (s : String) : Option Hash := diff --git a/src/lake/Lake/Util/String.lean b/src/lake/Lake/Util/String.lean index c0e6e7bff2..5fc925216f 100644 --- a/src/lake/Lake/Util/String.lean +++ b/src/lake/Lake/Util/String.lean @@ -7,6 +7,7 @@ module prelude public import Init.Data.ToString.Basic +import Init.Data.UInt.Lemmas import Init.Data.String.Basic import Init.Data.Nat.Fold @@ -33,3 +34,38 @@ public def isHex (s : String) : Bool := 65 ≤ c -- 'A' else false + +def lowerHexByte (n : UInt8) : UInt8 := + if n ≤ 9 then + n + 48 -- + '0' + else + n + 87 -- + ('a' - 10) + +theorem isValidChar_of_lt_256 (h : n < 256) : isValidChar n := + Or.inl <| Nat.lt_trans h (by decide) + +def lowerHexChar (n : UInt8) : Char := + ⟨lowerHexByte n |>.toUInt32, isValidChar_of_lt_256 <| + UInt32.lt_iff_toNat_lt.mpr <| (lowerHexByte n).toNat_lt⟩ + +public def lowerHexUInt64 (n : UInt64) : String := + String.ofByteArray (ByteArray.emptyWithCapacity 16) ByteArray.isValidUTF8_empty + |>.push (lowerHexChar (n >>> 60 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 56 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 52 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 48 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 44 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 40 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 36 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 32 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 28 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 24 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 20 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 16 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 12 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 8 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n >>> 4 &&& 0xf).toUInt8) + |>.push (lowerHexChar (n &&& 0xf).toUInt8) + +-- sanity check +example : "0123456789abcdef" = lowerHexUInt64 0x0123456789abcdef := by decide