Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core-tests/shared/src/test/scala/zio/ZQueueSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,16 @@ object ZQueueSpec extends ZIOBaseSpec {
getter = queue.takeBetween(5, 10)
res <- getter.race(updater)
} yield assert(res)(hasSize(isGreaterThanEqualTo(5)))
},
testM("returns elements in the correct order") {
checkM(Gen.listOf(Gen.int(-10, 10))) { as =>
for {
queue <- Queue.bounded[Int](100)
f <- ZIO.foreach(as)(queue.offer).fork
bs <- queue.takeBetween(as.length, as.length)
_ <- f.interrupt
} yield assert(as)(equalTo(bs))
}
}
),
testM("offerAll with takeAll") {
Expand Down
47 changes: 28 additions & 19 deletions core/shared/src/main/scala/zio/ZQueue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import zio.internal.MutableConcurrentQueue

import java.util.concurrent.atomic.AtomicBoolean
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer

/**
* A `ZQueue[RA, RB, EA, EB, A, B]` is a lightweight, asynchronous queue into which values of
Expand Down Expand Up @@ -102,27 +103,35 @@ sealed abstract class ZQueue[-RA, -RB, +EA, +EB, -A, +B] extends Serializable {
def takeUpTo(max: Int): ZIO[RB, EB, List[B]]

/**
* Takes between min and max number of values from the queue. If there
* is less than min items available, it'll block until the items are
* collected.
* Takes a number of elements from the queue between the specified minimum
* and maximum. If there are fewer than the minimum number of elements
* available, suspends until at least the minimum number of elements have
* been collected.
*/
final def takeBetween(min: Int, max: Int): ZIO[RB, EB, List[B]] =
if (max < min) UIO.succeedNow(Nil)
else
takeUpTo(max).flatMap { bs =>
val remaining = min - bs.length

if (remaining == 1)
take.map(bs :+ _)
else if (remaining > 1) {
def takeRemainder(n: Int): ZIO[RB, EB, List[B]] =
if (n <= 0) ZIO.succeed(Nil)
else take.flatMap(a => takeRemainder(n - 1).map(a :: _))

takeRemainder(remaining).map(list => bs ++ list.reverse)
} else
UIO.succeedNow(bs)
}
ZIO.effectSuspendTotal {
val buffer = ListBuffer[B]()

def takeRemainder(min: Int, max: Int): ZIO[RB, EB, Any] =
if (max < min) ZIO.unit
else
takeUpTo(max).flatMap { bs =>
val remaining = min - bs.length
if (remaining == 1)
take.flatMap(b => ZIO.effectTotal(buffer ++= bs += b))
else if (remaining > 1) {
take.flatMap { b =>
ZIO.effectSuspendTotal {
buffer ++= bs += b
takeRemainder(remaining - 1, max - bs.length - 1)
}
}
} else
ZIO.effectTotal(buffer ++= bs)
}

takeRemainder(min, max).as(buffer.toList)
}

/**
* Alias for `both`.
Expand Down