This PR migrates usages of `Std.Range` to the new polymorphic ranges. This PR unfortunately increases the transitive imports for frequently-used parts of `Init` because the ranges now rely on iterators in order to provide their functionality for types other than `Nat`. However, iteration over ranges in compiled code is as efficient as before in the examples I checked. This is because of a special `IteratorLoop` implementation provided in the PR for this purpose. There were two issues that were uncovered during migration: * In `IndPredBelow.lean`, migrating the last remaining range causes `compilerTest1.lean` to break. I have minimized the issue and came to the conclusion it's a compiler bug. Therefore, I have not replaced said old range usage yet (see #9186). * In `BRecOn.lean`, we are publicly importing the ranges. Making this import private should theoretically work, but there seems to be a problem with the module system, causing the build to panic later in `Init.Data.Grind.Poly` (see #9185). * In `FuzzyMatching.lean`, inlining fails with the new ranges, which would have led to significant slowdown. Therefore, I have not migrated this file either.
150 lines
5.4 KiB
Text
150 lines
5.4 KiB
Text
import Std.Sync
|
||
|
||
open Std
|
||
|
||
def assertBEq [BEq α] [ToString α] (is should : α) : IO Unit := do
|
||
if is != should then
|
||
throw <| .userError s!"{is} should be {should}"
|
||
|
||
def closeClose (ch : CloseableChannel Nat) : IO Unit := do
|
||
assertBEq (← ch.isClosed) false
|
||
assertBEq ((← EIO.toBaseIO ch.close) matches .ok ()) true
|
||
assertBEq (← ch.isClosed) true
|
||
assertBEq ((← EIO.toBaseIO ch.close) matches .error .alreadyClosed) true
|
||
assertBEq (← ch.isClosed) true
|
||
|
||
def paired (ch : CloseableChannel Nat) : IO Unit := do
|
||
let sendTask ← ch.send 37
|
||
let recvTask ← ch.recv
|
||
assertBEq ((← IO.wait sendTask) matches .ok ()) true
|
||
assertBEq (← IO.wait recvTask) (some 37)
|
||
|
||
def syncPaired (ch : CloseableChannel.Sync Nat) : IO Unit := do
|
||
let sendTask ← IO.asTask (prio := .dedicated) (EIO.toBaseIO (ch.send 37))
|
||
let recvTask ← IO.asTask (prio := .dedicated) (ch.recv)
|
||
assertBEq ((← IO.ofExcept (← IO.wait sendTask)) matches .ok ()) true
|
||
assertBEq (← IO.ofExcept (← IO.wait recvTask)) (some 37)
|
||
|
||
def trySend (ch : CloseableChannel Nat) (capacity : Option Nat) : IO Unit := do
|
||
-- ready a receiver ahead of time
|
||
let recvTask ← ch.recv
|
||
assertBEq (← ch.trySend 37) true
|
||
assertBEq (← IO.wait recvTask) (some 37)
|
||
|
||
-- the unbounded CloseableChannel cannot go out of space so it is pointless to fill it up
|
||
let some capacity := capacity | return ()
|
||
for i in *...capacity do
|
||
assertBEq (← ch.trySend i) true
|
||
|
||
assertBEq (← ch.trySend (capacity + 1)) false
|
||
|
||
def tryRecv (ch : CloseableChannel Nat) : IO Unit := do
|
||
assertBEq (← ch.tryRecv) none
|
||
let sendTask ← ch.send 37
|
||
assertBEq (← ch.tryRecv) (some 37)
|
||
assertBEq ((← IO.wait sendTask) matches .ok ()) true
|
||
|
||
def sendRecvClose (ch : CloseableChannel Nat) : IO Unit := do
|
||
let sendTask ← ch.send 37
|
||
assertBEq ((← EIO.toBaseIO ch.close) matches .ok ()) true
|
||
let recvTask ← ch.recv
|
||
assertBEq ((← IO.wait sendTask) matches .ok ()) true
|
||
assertBEq (← IO.wait recvTask) (some 37)
|
||
|
||
let sendTask ← ch.send 37
|
||
assertBEq ((← IO.wait sendTask) matches .error .closed) true
|
||
let recvTask ← ch.recv
|
||
assertBEq (← IO.wait recvTask) none
|
||
assertBEq (← ch.trySend 37) false
|
||
assertBEq (← ch.tryRecv) none
|
||
|
||
def sendIt (ch : CloseableChannel Nat) (messages : List Nat) : BaseIO (Task (Option Unit)) := do
|
||
match messages with
|
||
| [] => return .pure <| some ()
|
||
| msg :: messages =>
|
||
BaseIO.bindTask (← ch.send msg) fun
|
||
| .error .. =>
|
||
return .pure <| none
|
||
| .ok .. =>
|
||
sendIt ch messages
|
||
|
||
partial def recvIt (ch : CloseableChannel Nat) (messages : List Nat) : BaseIO (Task (List Nat)) := do
|
||
BaseIO.bindTask (← ch.recv) fun
|
||
| none => return .pure messages.reverse
|
||
| some msg => recvIt ch (msg :: messages)
|
||
|
||
def sendLots (ch : CloseableChannel Nat) : IO Unit := do
|
||
let messages := List.range 1000
|
||
let sendTask ← sendIt ch messages
|
||
let recvTask ← recvIt ch []
|
||
assertBEq (← IO.wait sendTask) (some ())
|
||
discard <| ch.close
|
||
assertBEq (← IO.wait recvTask) messages
|
||
|
||
def sendItSync (ch : CloseableChannel.Sync Nat) (messages : List Nat) : IO Unit := do
|
||
for msg in messages do
|
||
ch.send msg
|
||
return ()
|
||
|
||
def recvItSync (ch : CloseableChannel.Sync Nat) : IO (List Nat) := do
|
||
let mut messages := []
|
||
for msg in ch do
|
||
messages := msg :: messages
|
||
return messages.reverse
|
||
|
||
def sendLotsSync (ch : CloseableChannel.Sync Nat) : IO Unit := do
|
||
let messages := List.range 1000
|
||
let sendTask ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
|
||
let recvTask ← IO.asTask (prio := .dedicated) (recvItSync ch)
|
||
IO.ofExcept (← IO.wait sendTask)
|
||
discard <| ch.close
|
||
assertBEq (← IO.ofExcept (← IO.wait recvTask)) messages
|
||
|
||
partial def sendLotsMulti (ch : CloseableChannel Nat) : IO Unit := do
|
||
let messages := List.range 1000
|
||
let sendTask1 ← sendIt ch messages
|
||
let sendTask2 ← sendIt ch messages
|
||
let recvTask1 ← recvIt ch []
|
||
let recvTask2 ← recvIt ch []
|
||
assertBEq (← IO.wait sendTask1) (some ())
|
||
assertBEq (← IO.wait sendTask2) (some ())
|
||
discard <| ch.close
|
||
let msg1 ← IO.wait recvTask1
|
||
let msg2 ← IO.wait recvTask2
|
||
assertBEq (msg1.sum + msg2.sum) (2 * messages.sum)
|
||
|
||
partial def sendLotsMultiSync (ch : CloseableChannel.Sync Nat) : IO Unit := do
|
||
let messages := List.range 1000
|
||
let sendTask1 ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
|
||
let sendTask2 ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
|
||
let recvTask1 ← IO.asTask (prio := .dedicated) (recvItSync ch)
|
||
let recvTask2 ← IO.asTask (prio := .dedicated) (recvItSync ch)
|
||
IO.ofExcept (← IO.wait sendTask1)
|
||
IO.ofExcept (← IO.wait sendTask2)
|
||
discard <| ch.close
|
||
let msg1 ← IO.ofExcept (← IO.wait recvTask1)
|
||
let msg2 ← IO.ofExcept (← IO.wait recvTask2)
|
||
assertBEq (msg1.sum + msg2.sum) (2 * messages.sum)
|
||
|
||
def testIt (capacity : Option Nat) : IO Unit := do
|
||
paired (← CloseableChannel.new capacity)
|
||
syncPaired (← CloseableChannel.new capacity).sync
|
||
|
||
closeClose (← CloseableChannel.new capacity)
|
||
trySend (← CloseableChannel.new capacity) capacity
|
||
tryRecv (← CloseableChannel.new capacity)
|
||
sendRecvClose (← CloseableChannel.new capacity)
|
||
|
||
sendLots (← CloseableChannel.new capacity)
|
||
sendLotsSync (← CloseableChannel.new capacity).sync
|
||
sendLotsMulti (← CloseableChannel.new capacity)
|
||
sendLotsMultiSync (← CloseableChannel.new capacity).sync
|
||
|
||
def suite : IO Unit := do
|
||
testIt none
|
||
testIt (some 0)
|
||
testIt (some 1)
|
||
testIt (some 8)
|
||
testIt (some 128)
|
||
|
||
#eval suite
|