Skip to content

Commit

Permalink
Add toIndexedChunk
Browse files Browse the repository at this point in the history
  • Loading branch information
mpilquist committed Oct 14, 2021
1 parent 6dcc2c8 commit c551fd3
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
29 changes: 28 additions & 1 deletion core/shared/src/main/scala/fs2/Chunk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ abstract class Chunk[+O] extends Serializable with ChunkPlatform[O] with ChunkRu
/** Copies the elements of this chunk in to the specified array at the specified start index. */
def copyToArray[O2 >: O](xs: Array[O2], start: Int = 0): Unit

/** Converts this chunk to a chunk backed by a single array. */
/** Converts this chunk to a chunk backed by a single array.
*
* Alternatively, call `toIndexedChunk` to get back a chunk with guaranteed O(1) indexed lookup
* while also minimizing copying.
*/
def compact[O2 >: O](implicit ct: ClassTag[O2]): Chunk.ArraySlice[O2] =
Chunk.ArraySlice(toArray[O2], 0, size)

Expand Down Expand Up @@ -309,6 +313,21 @@ abstract class Chunk[+O] extends Serializable with ChunkPlatform[O] with ChunkRu
if (isEmpty) Chain.empty
else Chain.fromSeq(toList)

/** Returns a chunk with guaranteed O(1) lookup by index.
*
* Unlike `compact`, this operation does not copy any elements unless this chunk
* does not provide O(1) lookup by index -- e.g., a chunk built via 1 or more usages
* of `++`.
*/
def toIndexedChunk: Chunk[O] = this match {
case _: Chunk.Queue[_] =>
val b = collection.mutable.Buffer.newBuilder[O]
b.sizeHint(size)
foreach(o => b += o)
Chunk.buffer(b.result())
case other => other
}

/** Converts this chunk to a list. */
def toList: List[O] =
if (isEmpty) Nil
Expand Down Expand Up @@ -1063,6 +1082,14 @@ object Chunk

check(chunks, 0)
}

override def traverse[F[_], O2](f: O => F[O2])(implicit F: Applicative[F]): F[Chunk[O2]] =
toIndexedChunk.traverse(f)

override def traverseFilter[F[_], O2](f: O => F[Option[O2]])(implicit
F: Applicative[F]
): F[Chunk[O2]] =
toIndexedChunk.traverseFilter(f)
}

object Queue {
Expand Down
6 changes: 0 additions & 6 deletions core/shared/src/test/scala/fs2/ChunkSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,4 @@ class ChunkSuite extends Fs2Suite {
test("compactUntagged - regression #2679") {
Chunk.Queue.singleton(Chunk.singleton(1)).traverse(x => Option(x))
}

test("compactBoxed soundness") {
assertEquals(Chunk(1, 2, 3).compactBoxed.compact.values.toList, List(1, 2, 3))
assertEquals(Chunk(1, 2, 3).compactBoxed.toList, List(1, 2, 3))
assertEquals(Chunk(1, 2, 3).compactBoxed.map((_: Int) + 1).toList, List(2, 3, 4))
}
}

0 comments on commit c551fd3

Please # to comment.