Skip to content

Commit

Permalink
Avoid int boxing in the contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
satabin committed Oct 21, 2024
1 parent 0c878d8 commit 336ccc3
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 fs2-data Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package fs2.data.text.render.internal

private sealed trait NonEmptyIntList {
def head: Int
def ::(i: Int): NonEmptyIntList =
More(i, this)
def incHead: NonEmptyIntList
def decHead: NonEmptyIntList
def pop: NonEmptyIntList
}
private final case class One(head: Int) extends NonEmptyIntList {
override def incHead: NonEmptyIntList = One(head + 1)
override def decHead: NonEmptyIntList = One(head - 1)
override lazy val pop: NonEmptyIntList = One(0)
}
private final case class More(head: Int, tail: NonEmptyIntList) extends NonEmptyIntList {
override def incHead: NonEmptyIntList = More(head + 1, tail)
override def decHead: NonEmptyIntList = More(head - 1, tail)
override def pop: NonEmptyIntList = tail
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,31 @@ import cats.collections.Dequeue
import cats.data.{Chain, NonEmptyList}
import fs2.{Chunk, Pipe, Pull, Stream}

private case class OpenGroup(hpl: Int, indent: Int, group: Chain[Annotated])
private class AnnotationContext(var pos: Int,
var aligns: NonEmptyList[Int],
var aligns: NonEmptyIntList,
var hpl: Int,
var indent: Int,
var groups: Dequeue[(Int, Int, Chain[Annotated])])
var groups: Dequeue[OpenGroup])
private class RenderingContext(var fit: Int, var hpl: Int, var lines: NonEmptyList[String], var col: Int)

private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(implicit render: Renderable[Event])
extends Pipe[F, Event, String] {

private def push(annctx: AnnotationContext, evt: Annotated): Unit =
annctx.groups.unsnoc match {
case Some(((ghpl, gindent, group), groups)) => annctx.groups = groups.snoc((ghpl, gindent, group.append(evt)))
case None => // should never happen
case Some((OpenGroup(ghpl, gindent, group), groups)) =>
annctx.groups = groups.snoc(OpenGroup(ghpl, gindent, group.append(evt)))
case None => // should never happen
}

private def pop(buffer: Chain[Annotated],
annctx: AnnotationContext,
rctx: RenderingContext,
chunkAcc: StringBuilder): Unit =
annctx.groups.unsnoc match {
case Some(((ghpl, gindent, group), groups)) =>
annctx.groups = groups.snoc((ghpl, gindent, group.concat(buffer)))
case Some((OpenGroup(ghpl, gindent, group), groups)) =>
annctx.groups = groups.snoc(OpenGroup(ghpl, gindent, group.concat(buffer)))
case None =>
annctx.groups = Dequeue.empty
buffer.iterator.foreach(renderAnnotated(_, rctx, chunkAcc))
Expand All @@ -55,11 +57,11 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im
} else {
// group does not fit, uncons first buffer
annctx.groups.uncons match {
case Some(((_, _, buffer), groups)) =>
case Some((OpenGroup(_, _, buffer), groups)) =>
renderGroupBegin(Position.TooFar, rctx)
buffer.iterator.foreach(renderAnnotated(_, rctx, chunkAcc))
groups.uncons match {
case Some(((newhpl, newindent, _), _)) =>
case Some((OpenGroup(newhpl, newindent, _), _)) =>
annctx.hpl = newhpl
annctx.indent = newindent
annctx.groups = groups
Expand Down Expand Up @@ -131,10 +133,10 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im
// this is the top-level group, turn on the buffer mechanism
annctx.hpl = hpl1
annctx.indent = annctx.aligns.head
annctx.groups = annctx.groups.snoc((hpl1, annctx.indent, Chain.empty))
annctx.groups = annctx.groups.snoc(OpenGroup(hpl1, annctx.indent, Chain.empty))
} else {
// starting a new group, puts a new empty buffer in the group dequeue, and check for overflow
annctx.groups = annctx.groups.snoc((hpl1, annctx.aligns.head, Chain.empty))
annctx.groups = annctx.groups.snoc(OpenGroup(hpl1, annctx.aligns.head, Chain.empty))
check(annctx, rctx, chunkAcc)
}

Expand All @@ -143,7 +145,7 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im
case None =>
// closing unknown group, just ignore it

case Some(((newhpl, newindent, group), groups)) =>
case Some((OpenGroup(newhpl, newindent, group), groups)) =>
// closing a group, pop it from the buffer dequeue, and continue
annctx.groups = groups
pop(group.prepend(Annotated.GroupBegin(Position.Small(annctx.pos))).append(Annotated.GroupEnd),
Expand All @@ -157,7 +159,7 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im

case DocEvent.IndentBegin =>
// increment the current indentation level
annctx.aligns = NonEmptyList(annctx.aligns.head + 1, annctx.aligns.tail)
annctx.aligns = annctx.aligns.incHead
if (annctx.groups.isEmpty) {
// no open group we can emit immediately a new line
renderIndentBegin(rctx)
Expand All @@ -170,7 +172,7 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im

case DocEvent.IndentEnd =>
// decrement the current indentation level
annctx.aligns = NonEmptyList(annctx.aligns.head - 1, annctx.aligns.tail)
annctx.aligns = annctx.aligns.decHead
if (annctx.groups.isEmpty) {
// no open group we can emit immediately a new line
renderIndentEnd(rctx)
Expand All @@ -195,10 +197,7 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im

case DocEvent.AlignEnd =>
// restore to previous indentation level
annctx.aligns = annctx.aligns match {
case NonEmptyList(_, i :: is) => NonEmptyList(i, is)
case NonEmptyList(_, Nil) => NonEmptyList.one(0)
}
annctx.aligns = annctx.aligns.pop
if (annctx.groups.isEmpty) {
// no open group we can emit immediately a new line
renderAlignEnd(rctx)
Expand Down Expand Up @@ -287,7 +286,7 @@ private[render] class StreamPrinter[F[_], Event](width: Int, indentSize: Int)(im
0,
0,
events.flatMap(renderer.doc(_)),
new AnnotationContext(0, NonEmptyList.one(0), 0, 0, Dequeue.empty),
new AnnotationContext(0, One(0), 0, 0, Dequeue.empty),
new RenderingContext(0, width, NonEmptyList.one(""), 0),
new StringBuilder
).stream
Expand Down

0 comments on commit 336ccc3

Please sign in to comment.