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

perfolation.numeric.FastNumber.scala Maven / Gradle / Ivy

The newest version!
package perfolation.numeric

object FastNumber {
  private val ExtraZeroesRegex = """(\d+)[.]([0-9]+?)0+""".r
  private val threadLocal = new ThreadLocal[FastNumber] {
    override def initialValue(): FastNumber = new FastNumber
  }

  def apply[Return](value: BigDecimal)(f: FastNumber => Return): Return = {
    val fn = threadLocal.get()
    fn.set(value)
    f(fn)
  }
}

/**
  * FastNumber is a mutable, thread-local instance used for quick operations on numeric values
  */
class FastNumber {
  /**
    * Values are set right-aligned in the array with spaces representing non-values
    */
  val integer: Array[Char] = new Array[Char](255)
  /**
    * Values are set left-aligned in the array with spaces representing non-values
    */
  val fraction: Array[Char] = new Array[Char](255)

  def set(value: BigDecimal): Unit = {
    clear()
    val s = value.toString match {
      case FastNumber.ExtraZeroesRegex(i, d) => s"$i.$d"
      case v => v
    }
    val decimal = s.indexOf('.')

    if (decimal != -1) {
      s.substring(0, decimal).reverse.zipWithIndex.foreach {
        case (char, index) => integer(integer.length - (index + 1)) = char
      }
      s.substring(decimal + 1).zipWithIndex.foreach {
        case (char, index) => fraction(index) = char
      }
    } else {
      s.reverse.zipWithIndex.foreach {
        case (char, index) => integer(integer.length - (index + 1)) = char
      }
    }
  }

  def setMinimumIntegerDigits(min: Int): Unit = {
    (0 until min).foreach { i =>
      val index = integer.length - (i + 1)
      val char = integer(index)
      if (char == ' ') {
        integer(index) = '0'
      }
    }
  }

  def setMaximumIntegerDigits(max: Int): Unit = {
    (0 until integer.length - max).foreach { index =>
      val char = integer(index)
      if (char != ' ') {
        integer(index) = ' '
      }
    }
  }

  def setMinimumFractionDigits(min: Int): Unit = {
    (0 until min).foreach { index =>
      val char = fraction(index)
      if (char == ' ') {
        fraction(index) = '0'
      }
    }
  }

  def setMaximumFractionDigits(max: Int, roundingMode: RoundingMode): Unit = {
    if (fraction(max) != ' ') {   // Exceeded max
      val last = fraction(max).asDigit
      if (roundingMode.roundUp(last)) {
        incrementFraction(max - 1)
      }
      (max until fraction.length).takeWhile(fraction(_) != ' ').foreach { index =>
        fraction(index) = ' '
      }
    }
  }

  def group(grouping: Grouping, offset: Int = 0): Unit = if (grouping.every > 0) {
    val position = integer.length - (offset + grouping.every + 1)
    if (integer(position) != ' ' && integer(position) != '-') {
      insertInteger(grouping.char, position)
      group(grouping, offset + grouping.every + 1)
    }
  }

  def insertInteger(char: Char, position: Int): Unit = {
    (0 to position).foreach { index =>
      integer(index) = integer(index + 1)
    }
    integer(position) = char
  }

  private def incrementFraction(index: Int): Unit = if (index == -1) {    // Increment integer
    incrementInteger(integer.length - 1)
  } else {
    val v = fraction(index).asDigit
    if (v < 9) {
      val char: Char = Character.forDigit(v + 1, 10)
      fraction(index) = char
    } else {
      fraction(index) = '0'
      incrementFraction(index - 1)
    }
  }

  private def incrementInteger(index: Int): Unit = {
    val v = integer(index).asDigit
    if (integer(index) == ' ') {
      integer(index) = '1'
    } else if (v < 9) {
      val char: Char = Character.forDigit(v + 1, 10)
      integer(index) = char
    } else {
      integer(index) = '0'
      incrementInteger(index - 1)
    }
  }

  def clear(): Unit = integer.indices.foreach { index =>
    integer(index) = ' '
    fraction(index) = ' '
  }

  override def toString: String = {
    val b = new StringBuilder
    var write = false
    integer.indices.foreach { index =>
      val char = integer(index)
      if (write || char != ' ') {
        write = true

        b.append(char)
      }
    }
    write = false
    fraction.takeWhile(_ != ' ').foreach { char =>
      if (!write) {
        write = true
        b.append('.')
      }
      b.append(char)
    }
    b.toString()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy