@@ -13,6 +13,8 @@ import all Init.Data.UInt.BasicAux
1313public import Init.Data.Option.Basic
1414public import Init.Data.Array.Extract
1515
16+ set_option doc.verso true
17+
1618@[expose] public section
1719universe u
1820
@@ -34,18 +36,40 @@ instance : Inhabited ByteArray where
3436instance : EmptyCollection ByteArray where
3537 emptyCollection := ByteArray.empty
3638
39+ /--
40+ Retrieves the size of the array as a platform-specific fixed-width integer.
41+
42+ Because {name}`USize` is big enough to address all memory on every platform that Lean supports,
43+ there are in practice no {name}`ByteArray`s that have more elements that {name}`USize` can count.
44+ -/
3745@[extern " lean_sarray_size" , simp]
3846def usize (a : @& ByteArray) : USize :=
3947 a.size.toUSize
4048
49+ /--
50+ Retrieves the byte at the indicated index. Callers must prove that the index is in bounds. The index
51+ is represented by a platform-specific fixed-width integer (either 32 or 64 bits).
52+
53+ Because {name}`USize` is big enough to address all memory on every platform that Lean supports, there are
54+ in practice no {name}`ByteArray`s for which {name}`uget` cannot retrieve all elements.
55+ -/
4156@[extern " lean_byte_array_uget" ]
4257def uget : (a : @& ByteArray) → (i : USize) → (h : i.toNat < a.size := by get_elem_tactic) → UInt8
4358 | ⟨bs⟩, i, h => bs[i]
4459
60+ /--
61+ Retrieves the byte at the indicated index. Panics if the index is out of bounds.
62+ -/
4563@[extern " lean_byte_array_get" ]
4664def get ! : (@& ByteArray) → (@& Nat) → UInt8
4765 | ⟨bs⟩, i => bs[i]!
4866
67+ /--
68+ Retrieves the byte at the indicated index. Callers must prove that the index is in bounds.
69+
70+ Use {name}`uget` for a more efficient alternative or {name}`get!` for a variant that panics if the
71+ index is out of bounds.
72+ -/
4973@[extern " lean_byte_array_fget" ]
5074def get : (a : @& ByteArray) → (i : @& Nat) → (h : i < a.size := by get_elem_tactic) → UInt8
5175 | ⟨bs⟩, i, _ => bs[i]
@@ -56,34 +80,61 @@ instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
5680instance : GetElem ByteArray USize UInt8 fun xs i => i.toFin < xs.size where
5781 getElem xs i h := xs.uget i h
5882
83+ /--
84+ Replaces the byte at the given index.
85+
86+ The array is modified in-place if there are no other references to it.
87+
88+ If the index is out of bounds, the array is returned unmodified.
89+ -/
5990@[extern " lean_byte_array_set" ]
6091def set ! : ByteArray → (@& Nat) → UInt8 → ByteArray
6192 | ⟨bs⟩, i, b => ⟨bs.set! i b⟩
6293
94+ /--
95+ Replaces the byte at the given index.
96+
97+ No bounds check is performed, but the function requires a proof that the index is in bounds. This
98+ proof can usually be omitted, and will be synthesized automatically.
99+
100+ The array is modified in-place if there are no other references to it.
101+ -/
63102@[extern " lean_byte_array_fset" ]
64103def set : (a : ByteArray) → (i : @& Nat) → UInt8 → (h : i < a.size := by get_elem_tactic) → ByteArray
65104 | ⟨bs⟩, i, b, h => ⟨bs.set i b h⟩
66105
67- @[extern " lean_byte_array_uset" ]
106+ @[extern " lean_byte_array_uset" , inherit_doc ByteArray.set ]
68107def uset : (a : ByteArray) → (i : USize) → UInt8 → (h : i.toNat < a.size := by get_elem_tactic) → ByteArray
69108 | ⟨bs⟩, i, v, h => ⟨bs.uset i v h⟩
70109
110+ /--
111+ Computes a hash for a {name}`ByteArray`.
112+ -/
71113@[extern " lean_byte_array_hash" ]
72114protected opaque hash (a : @& ByteArray) : UInt64
73115
74116instance : Hashable ByteArray where
75117 hash := ByteArray.hash
76118
119+ /--
120+ Returns {name}`true` when {name}`s` contains zero bytes.
121+ -/
77122def isEmpty (s : ByteArray) : Bool :=
78123 s.size == 0
79124
80125/--
81- Copy the slice at `[srcOff, srcOff + len)` in `src` to `[destOff, destOff + len)` in `dest`, growing `dest` if necessary.
82- If `exact` is `false`, the capacity will be doubled when grown. -/
126+ Copies the slice at `[srcOff, srcOff + len)` in {name}`src` to `[destOff, destOff + len)` in
127+ {name}`dest`, growing {name}`dest` if necessary. If {name}`exact` is {name}`false`, the capacity
128+ will be doubled when grown.
129+ -/
83130@[extern " lean_byte_array_copy_slice" ]
84131def copySlice (src : @& ByteArray) (srcOff : Nat) (dest : ByteArray) (destOff len : Nat) (exact : Bool := true) : ByteArray :=
85132 ⟨dest.data.extract 0 destOff ++ src.data.extract srcOff (srcOff + len) ++ dest.data.extract (destOff + min len (src.data.size - srcOff)) dest.data.size⟩
86133
134+ /--
135+ Copies the bytes with indices {name}`b` (inclusive) to {name}`e` (exclusive) to a new
136+ {name}`ByteArray`.
137+ -/
87138def extract (a : ByteArray) (b e : Nat) : ByteArray :=
88139 a.copySlice b empty 0 (e - b)
89140
@@ -114,6 +165,9 @@ theorem append_eq {a b : ByteArray} : a.append b = a ++ b := rfl
114165theorem fastAppend_eq {a b : ByteArray} : a.fastAppend b = a ++ b := by
115166 simp [← append_eq_fastAppend]
116167
168+ /--
169+ Converts a packed array of bytes to a linked list.
170+ -/
117171def toList (bs : ByteArray) : List UInt8 :=
118172 let rec loop (i : Nat) (r : List UInt8) :=
119173 if i < bs.size then
@@ -124,32 +178,46 @@ def toList (bs : ByteArray) : List UInt8 :=
124178 decreasing_by decreasing_trivial_pre_omega
125179 loop 0 []
126180
127- @[inline] def findIdx ? (a : ByteArray) (p : UInt8 → Bool) (start := 0 ) : Option Nat :=
181+ /--
182+ Finds the index of the first byte in {name}`a` for which {name}`p` returns {name}`true`. If no byte
183+ in {name}`a` satisfies {name}`p`, then the result is {name}`none`.
184+
185+ The index is returned along with a proof that it is a valid index in the array.
186+ -/
187+ @[inline] def findFinIdx ? (a : ByteArray) (p : UInt8 → Bool) (start := 0 ) : Option (Fin a.size) :=
128188 let rec @[specialize] loop (i : Nat) :=
129189 if h : i < a.size then
130- if p a[i] then some i else loop (i+1 )
190+ if p a[i] then some ⟨i, h⟩ else loop (i+1 )
131191 else
132192 none
133193 termination_by a.size - i
134194 decreasing_by decreasing_trivial_pre_omega
135195 loop start
136196
137- @[inline] def findFinIdx ? (a : ByteArray) (p : UInt8 → Bool) (start := 0 ) : Option (Fin a.size) :=
197+ /--
198+ Finds the index of the first byte in {name}`a` for which {name}`p` returns {name}`true`. If no byte
199+ in {name}`a` satisfies {name}`p`, then the result is {name}`none`.
200+
201+ The variant {name}`findFinIdx?` additionally returns a proof that the found index is in bounds.
202+ -/
203+ @[inline] def findIdx ? (a : ByteArray) (p : UInt8 → Bool) (start := 0 ) : Option Nat :=
138204 let rec @[specialize] loop (i : Nat) :=
139205 if h : i < a.size then
140- if p a[i] then some ⟨i, h⟩ else loop (i+1 )
206+ if p a[i] then some i else loop (i+1 )
141207 else
142208 none
143209 termination_by a.size - i
144210 decreasing_by decreasing_trivial_pre_omega
145211 loop start
146212
147213/--
148- We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
149- This is similar to the `Array` version .
214+ An efficient implementation of {name}`ForIn.forIn` for {name}`ByteArray` that uses {name}`USize`
215+ rather than {name}`Nat` for indices .
150216
151- TODO: avoid code duplication in the future after we improve the compiler.
217+ We claim this unsafe implementation is correct because an array cannot have more than
218+ {name}`USize.size` elements in our runtime. This is similar to the {name}`Array` version.
152219-/
220+ -- TODO: avoid code duplication in the future after we improve the compiler.
153221@[inline] unsafe def forInUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteArray) (b : β) (f : UInt8 → β → m (ForInStep β)) : m β :=
154222 let sz := as.usize
155223 let rec @[specialize] loop (i : USize) (b : β) : m β := do
@@ -162,7 +230,11 @@ def toList (bs : ByteArray) : List UInt8 :=
162230 pure b
163231 loop 0 b
164232
165- /-- Reference implementation for `forIn` -/
233+ /--
234+ The reference implementation of {name}`ForIn.forIn` for {name}`ByteArray`.
235+
236+ In compiled code, this is replaced by the more efficient {name}`ByteArray.forInUnsafe`.
237+ -/
166238@[implemented_by ByteArray.forInUnsafe]
167239protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteArray) (b : β) (f : UInt8 → β → m (ForInStep β)) : m β :=
168240 let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
@@ -180,7 +252,13 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
180252instance : ForIn m ByteArray UInt8 where
181253 forIn := ByteArray.forIn
182254
183- /-- See comment at `forInUnsafe` -/
255+ /--
256+ An efficient implementation of a monadic left fold on for {name}`ByteArray` that uses {name}`USize`
257+ rather than {name}`Nat` for indices.
258+
259+ We claim this unsafe implementation is correct because an array cannot have more than
260+ {name}`USize.size` elements in our runtime. This is similar to the {name}`Array` version.
261+ -/
184262-- TODO: avoid code duplication.
185263@[inline]
186264unsafe def foldlMUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 → m β) (init : β) (as : ByteArray) (start := 0 ) (stop := as.size) : m β :=
@@ -197,7 +275,14 @@ unsafe def foldlMUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (f : β
197275 else
198276 pure init
199277
200- /-- Reference implementation for `foldlM` -/
278+ /--
279+ A monadic left fold on {name}`ByteArray` that iterates over an array from low to high indices,
280+ computing a running value.
281+
282+ Each element of the array is combined with the value from the prior elements using a monadic
283+ function {name}`f`. The initial value {name}`init` is the starting value before any elements have
284+ been processed.
285+ -/
201286@[implemented_by foldlMUnsafe]
202287def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 → m β) (init : β) (as : ByteArray) (start := 0 ) (stop := as.size) : m β :=
203288 let fold (stop : Nat) (h : stop ≤ as.size) :=
@@ -215,11 +300,23 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
215300 else
216301 fold as.size (Nat.le_refl _)
217302
303+ /--
304+ A left fold on {name}`ByteArray` that iterates over an array from low to high indices, computing a
305+ running value.
306+
307+ Each element of the array is combined with the value from the prior elements using a function
308+ {name}`f`. The initial value {name}`init` is the starting value before any elements have been
309+ processed.
310+
311+ {name}`ByteArray.foldlM` is a monadic variant of this function.
312+ -/
218313@[inline]
219314def foldl {β : Type v} (f : β → UInt8 → β) (init : β) (as : ByteArray) (start := 0 ) (stop := as.size) : β :=
220315 Id.run <| as.foldlM (pure <| f · ·) init start stop
221316
222- /-- Iterator over the bytes (`UInt8`) of a `ByteArray`.
317+ set_option doc.verso false -- Awaiting intra-module forward reference support
318+ /--
319+ Iterator over the bytes (`UInt8`) of a `ByteArray`.
223320
224321Typically created by `arr.iter`, where `arr` is a `ByteArray`.
225322
@@ -243,6 +340,7 @@ structure Iterator where
243340 current byte is `(default : UInt8)`. -/
244341 idx : Nat
245342 deriving Inhabited
343+ set_option doc.verso true
246344
247345/-- Creates an iterator at the beginning of an array. -/
248346def mkIterator (arr : ByteArray) : Iterator :=
@@ -260,16 +358,25 @@ theorem Iterator.sizeOf_eq (i : Iterator) : sizeOf i = i.array.size - i.idx :=
260358
261359namespace Iterator
262360
263- /-- Number of bytes remaining in the iterator. -/
361+ /--
362+ The number of bytes remaining in the iterator.
363+ -/
264364def remainingBytes : Iterator → Nat
265365 | ⟨arr, i⟩ => arr.size - i
266366
267367@[inherit_doc Iterator.idx]
268368def pos := Iterator.idx
269369
270- /-- The byte at the current position.
370+ /-- True if the iterator is past the array's last byte. -/
371+ @[inline]
372+ def atEnd : Iterator → Bool
373+ | ⟨arr, i⟩ => i ≥ arr.size
271374
272- On an invalid position, returns `(default : UInt8)`. -/
375+ /--
376+ The byte at the current position.
377+
378+ On an invalid position, returns {lean}`(default : UInt8)`.
379+ -/
273380@[inline]
274381def curr : Iterator → UInt8
275382 | ⟨arr, i⟩ =>
@@ -278,27 +385,28 @@ def curr : Iterator → UInt8
278385 else
279386 default
280387
281- /-- Moves the iterator's position forward by one byte, unconditionally.
388+ /--
389+ Moves the iterator's position forward by one byte, unconditionally.
282390
283391It is only valid to call this function if the iterator is not at the end of the array, *i.e.*
284- `Iterator.atEnd` is `false`; otherwise, the resulting iterator will be invalid. -/
392+ {name}`Iterator.atEnd` is {name}`false`; otherwise, the resulting iterator will be invalid.
393+ -/
285394@[inline]
286395def next : Iterator → Iterator
287396 | ⟨arr, i⟩ => ⟨arr, i + 1 ⟩
288397
289- /-- Decreases the iterator's position.
398+ /--
399+ Decreases the iterator's position.
290400
291- If the position is zero, this function is the identity. -/
401+ If the position is zero, this function is the identity.
402+ -/
292403@[inline]
293404def prev : Iterator → Iterator
294405 | ⟨arr, i⟩ => ⟨arr, i - 1 ⟩
295406
296- /-- True if the iterator is past the array's last byte. -/
297- @[inline]
298- def atEnd : Iterator → Bool
299- | ⟨arr, i⟩ => i ≥ arr.size
300-
301- /-- True if the iterator is not past the array's last byte. -/
407+ /--
408+ True if the iterator is valid; that is, it is not past the array's last byte.
409+ -/
302410@[inline]
303411def hasNext : Iterator → Bool
304412 | ⟨arr, i⟩ => i < arr.size
@@ -324,27 +432,33 @@ def next' (it : Iterator) (_h : it.hasNext) : Iterator :=
324432def hasPrev : Iterator → Bool
325433 | ⟨_, i⟩ => i > 0
326434
327- /-- Moves the iterator's position to the end of the array.
435+ /--
436+ Moves the iterator's position to the end of the array.
328437
329- Note that `i.toEnd.atEnd` is always `true`. -/
438+ Given {given}`i : ByteArray.Iterator`, note that {lean}`i.toEnd.atEnd` is always {name}`true`.
439+ -/
330440@[inline]
331441def toEnd : Iterator → Iterator
332442 | ⟨arr, _⟩ => ⟨arr, arr.size⟩
333443
334- /-- Moves the iterator's position several bytes forward.
444+ /--
445+ Moves the iterator's position several bytes forward.
335446
336447The resulting iterator is only valid if the number of bytes to skip is less than or equal to
337- the number of bytes left in the iterator. -/
448+ the number of bytes left in the iterator.
449+ -/
338450@[inline]
339451def forward : Iterator → Nat → Iterator
340452 | ⟨arr, i⟩, f => ⟨arr, i + f⟩
341453
342454@[inherit_doc forward, inline]
343455def nextn : Iterator → Nat → Iterator := forward
344456
345- /-- Moves the iterator's position several bytes back.
457+ /--
458+ Moves the iterator's position several bytes back.
346459
347- If asked to go back more bytes than available, stops at the beginning of the array. -/
460+ If asked to go back more bytes than available, stops at the beginning of the array.
461+ -/
348462@[inline]
349463def prevn : Iterator → Nat → Iterator
350464 | ⟨arr, i⟩, f => ⟨arr, i - f⟩
0 commit comments