Skip to content

Commit 8d0bf2f

Browse files
chore: docstring review for ByteArray
This PR adds missing docstrings for ByteArray and makes existing ones consistent with our style.
1 parent d88e417 commit 8d0bf2f

File tree

6 files changed

+204
-41
lines changed

6 files changed

+204
-41
lines changed

src/Init/Data/ByteArray/Basic.lean

Lines changed: 147 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import all Init.Data.UInt.BasicAux
1313
public import Init.Data.Option.Basic
1414
public import Init.Data.Array.Extract
1515

16+
set_option doc.verso true
17+
1618
@[expose] public section
1719
universe u
1820

@@ -34,18 +36,40 @@ instance : Inhabited ByteArray where
3436
instance : 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]
3846
def 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"]
4257
def 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"]
4664
def 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"]
5074
def 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
5680
instance : 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"]
6091
def 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"]
64103
def 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]
68107
def 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"]
72114
protected opaque hash (a : @& ByteArray) : UInt64
73115

74116
instance : Hashable ByteArray where
75117
hash := ByteArray.hash
76118

119+
/--
120+
Returns {name}`true` when {name}`s` contains zero bytes.
121+
-/
77122
def 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"]
84131
def 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+
-/
87138
def 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
114165
theorem 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+
-/
117171
def 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]
167239
protected 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
180252
instance : 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]
186264
unsafe 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]
202287
def 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]
219314
def 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
224321
Typically 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. -/
248346
def mkIterator (arr : ByteArray) : Iterator :=
@@ -260,16 +358,25 @@ theorem Iterator.sizeOf_eq (i : Iterator) : sizeOf i = i.array.size - i.idx :=
260358

261359
namespace Iterator
262360

263-
/-- Number of bytes remaining in the iterator. -/
361+
/--
362+
The number of bytes remaining in the iterator.
363+
-/
264364
def remainingBytes : Iterator → Nat
265365
| ⟨arr, i⟩ => arr.size - i
266366

267367
@[inherit_doc Iterator.idx]
268368
def 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]
274381
def 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
283391
It 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]
286395
def 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]
293404
def 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]
303411
def hasNext : Iterator → Bool
304412
| ⟨arr, i⟩ => i < arr.size
@@ -324,27 +432,33 @@ def next' (it : Iterator) (_h : it.hasNext) : Iterator :=
324432
def 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]
331441
def 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
336447
The 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]
339451
def forward : Iterator → Nat → Iterator
340452
| ⟨arr, i⟩, f => ⟨arr, i + f⟩
341453

342454
@[inherit_doc forward, inline]
343455
def 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]
349463
def prevn : Iterator → Nat → Iterator
350464
| ⟨arr, i⟩, f => ⟨arr, i - f⟩

src/Init/Data/ByteArray/Bootstrap.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@ public import Init.Prelude
1010
public import Init.Data.List.Basic
1111

1212
public section
13+
set_option doc.verso true
1314

1415
namespace ByteArray
1516

1617
@[simp]
1718
theorem data_push {a : ByteArray} {b : UInt8} : (a.push b).data = a.data.push b := rfl
1819

20+
/--
21+
Appends two byte arrays.
22+
23+
In compiled code, calls to {name}`ByteArray.append` are replaced with the much more efficient
24+
{name (scope:="Init.Data.ByteArray.Basic")}`ByteArray.fastAppend`.
25+
-/
1926
@[expose]
2027
protected def append (a b : ByteArray) : ByteArray :=
2128
⟨⟨a.data.toList ++ b.data.toList⟩⟩

0 commit comments

Comments
 (0)