All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zio.ChunkBuilder.scala Maven / Gradle / Ivy

There is a newer version: 2.1.11
Show newest version
/*
 * Copyright 2020-2024 John A. De Goes and the ZIO Contributors
 *
 * 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 zio

import zio.Chunk.BitChunkByte
import zio.stacktracer.TracingImplicits.disableAutoTrace

import scala.collection.mutable.{ArrayBuilder, Builder}
import scala.{
  Boolean => SBoolean,
  Byte => SByte,
  Char => SChar,
  Double => SDouble,
  Float => SFloat,
  Int => SInt,
  Long => SLong,
  Short => SShort
}

/**
 * A `ChunkBuilder[A]` can build a `Chunk[A]` given elements of type `A`.
 * `ChunkBuilder` is a mutable data structure that is implemented to efficiently
 * build chunks of unboxed primitives and for compatibility with the Scala
 * collection library.
 */
sealed abstract class ChunkBuilder[A] extends Builder[A, Chunk[A]]

object ChunkBuilder {

  /**
   * Constructs a generic `ChunkBuilder`.
   */
  def make[A](): ChunkBuilder[A] =
    new ChunkBuilder[A] {
      var arrayBuilder: ArrayBuilder[A] = null
      var size: SInt                    = -1
      def addOne(a: A): this.type = {
        if (arrayBuilder eq null) {
          implicit val tag = Chunk.Tags.fromValue(a)
          arrayBuilder = ArrayBuilder.make
          if (size != -1) {
            arrayBuilder.sizeHint(size)
          }
        }
        try {
          arrayBuilder.addOne(a)
        } catch {
          case _: ClassCastException =>
            val as = arrayBuilder.result()
            arrayBuilder = ArrayBuilder.make[AnyRef].asInstanceOf[ArrayBuilder[A]]
            if (size != -1) {
              arrayBuilder.sizeHint(size)
            }
            arrayBuilder.addAll(as)
            arrayBuilder.addOne(a)
        }
        this
      }
      def clear(): Unit =
        if (arrayBuilder ne null) {
          arrayBuilder.clear()
        }
      def result(): Chunk[A] =
        if (arrayBuilder eq null) {
          Chunk.empty
        } else {
          Chunk.fromArray(arrayBuilder.result())
        }
      override def sizeHint(n: SInt): Unit =
        if (arrayBuilder eq null) {
          size = n
        } else {
          arrayBuilder.sizeHint(n)
        }
      override def knownSize: SInt =
        if (arrayBuilder eq null) {
          -1
        } else {
          arrayBuilder.knownSize
        }
    }

  /**
   * Constructs a generic `ChunkBuilder` with size hint.
   */
  def make[A](sizeHint: SInt): ChunkBuilder[A] = {
    val builder = make[A]()
    builder.sizeHint(sizeHint)
    builder
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Boolean`
   * values.
   */
  final class Boolean extends ChunkBuilder[SBoolean] { self =>

    private val arrayBuilder: ArrayBuilder.ofByte = {
      new ArrayBuilder.ofByte
    }
    private var lastByte: SByte   = 0.toByte
    private var maxBitIndex: SInt = 0

    override def addAll(as: IterableOnce[SBoolean]): this.type = {
      as.iterator.foreach(addOne _)
      this
    }
    def addOne(b: SBoolean): this.type = {
      if (b) {
        if (maxBitIndex == 8) {
          arrayBuilder.addOne(lastByte)
          lastByte = (1 << 7).toByte
          maxBitIndex = 1
        } else {
          val bitIndex = 7 - maxBitIndex
          lastByte = (lastByte | (1 << bitIndex)).toByte
          maxBitIndex = maxBitIndex + 1
        }
      } else {
        if (maxBitIndex == 8) {
          arrayBuilder.addOne(lastByte)
          lastByte = 0.toByte
          maxBitIndex = 1
        } else {
          maxBitIndex = maxBitIndex + 1
        }
      }
      this
    }
    def clear(): Unit = {
      arrayBuilder.clear()
      maxBitIndex = 0
      lastByte = 0.toByte
    }
    override def equals(that: Any): SBoolean =
      that match {
        case that: Boolean =>
          self.arrayBuilder.equals(that.arrayBuilder) &&
            self.maxBitIndex == that.maxBitIndex &&
            self.lastByte == that.lastByte
        case _ => false
      }
    def result(): Chunk[SBoolean] = {
      val bytes: Chunk[SByte] = Chunk.fromArray(arrayBuilder.result() :+ lastByte)
      BitChunkByte(bytes, 0, 8 * (bytes.length - 1) + maxBitIndex)
    }
    override def sizeHint(n: SInt): Unit = {
      val hint = if (n == 0) 0 else n / 8 + 1
      arrayBuilder.sizeHint(hint)
    }
    override def toString: String =
      "ChunkBuilder.Boolean"
    override def knownSize: SInt = arrayBuilder.knownSize * 8 + maxBitIndex
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Byte` values.
   */
  final class Byte extends ChunkBuilder[SByte] { self =>
    private val arrayBuilder: ArrayBuilder.ofByte = {
      new ArrayBuilder.ofByte
    }
    override def addAll(as: IterableOnce[SByte]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SByte): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Byte => self.arrayBuilder == that.arrayBuilder
        case _          => false
      }
    def result(): Chunk[SByte] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Byte"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Char` values.
   */
  final class Char extends ChunkBuilder[SChar] { self =>
    private val arrayBuilder: ArrayBuilder.ofChar = {
      new ArrayBuilder.ofChar
    }
    override def addAll(as: IterableOnce[SChar]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SChar): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Char => self.arrayBuilder == that.arrayBuilder
        case _          => false
      }
    def result(): Chunk[SChar] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Char"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Double`
   * values.
   */
  final class Double extends ChunkBuilder[SDouble] { self =>
    private val arrayBuilder: ArrayBuilder.ofDouble = {
      new ArrayBuilder.ofDouble
    }
    override def addAll(as: IterableOnce[SDouble]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SDouble): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Double => self.arrayBuilder == that.arrayBuilder
        case _            => false
      }
    def result(): Chunk[SDouble] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Double"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Float` values.
   */
  final class Float extends ChunkBuilder[SFloat] { self =>
    private val arrayBuilder: ArrayBuilder.ofFloat = {
      new ArrayBuilder.ofFloat
    }
    override def addAll(as: IterableOnce[SFloat]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SFloat): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Float => self.arrayBuilder == that.arrayBuilder
        case _           => false
      }
    def result(): Chunk[SFloat] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Float"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Int` values.
   */
  final class Int extends ChunkBuilder[SInt] { self =>
    private val arrayBuilder: ArrayBuilder.ofInt = {
      new ArrayBuilder.ofInt
    }
    override def addAll(as: IterableOnce[SInt]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SInt): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Int => self.arrayBuilder == that.arrayBuilder
        case _         => false
      }
    def result(): Chunk[SInt] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Int"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Long` values.
   */
  final class Long extends ChunkBuilder[SLong] { self =>
    private val arrayBuilder: ArrayBuilder.ofLong = {
      new ArrayBuilder.ofLong
    }
    override def addAll(as: IterableOnce[SLong]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SLong): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Long => self.arrayBuilder == that.arrayBuilder
        case _          => false
      }
    def result(): Chunk[SLong] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Long"
    override def knownSize: SInt = arrayBuilder.knownSize
  }

  /**
   * A `ChunkBuilder` specialized for building chunks of unboxed `Short` values.
   */
  final class Short extends ChunkBuilder[SShort] { self =>
    private val arrayBuilder: ArrayBuilder.ofShort = {
      new ArrayBuilder.ofShort
    }
    override def addAll(as: IterableOnce[SShort]): this.type = {
      arrayBuilder.addAll(as)
      this
    }
    def addOne(a: SShort): this.type = {
      arrayBuilder.addOne(a)
      this
    }
    def clear(): Unit =
      arrayBuilder.clear()
    override def equals(that: Any): SBoolean =
      that match {
        case that: Short => self.arrayBuilder == that.arrayBuilder
        case _           => false
      }
    def result(): Chunk[SShort] =
      Chunk.fromArray(arrayBuilder.result())
    override def sizeHint(n: SInt): Unit =
      arrayBuilder.sizeHint(n)
    override def toString: String =
      "ChunkBuilder.Short"
    override def knownSize: SInt = arrayBuilder.knownSize
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy