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

cgta.oscala.legacy.NumberSystem.scala Maven / Gradle / Ivy

The newest version!
package cgta.oscala
package legacy

import scala.annotation.tailrec

/**
 * This trait will allow users to create their own number systems with a configurable "base"
 * But these should be used for counting up from > 0L
 * Negative numbers and fractions / decimal points not supported
 */
//move to cdk.math
trait NumberSystem {
  /**
   * Base of the number system, ie Decimal is base = 10, binary 2, and so forth
   */
  private def base = digitArray.length

  /**
   * Alphabet of digits("chars") that will represent digits in the number system
   * This Array MUST have a length == base
   */
  protected def digitArray: Array[Char]

  /**
   * A map from the digit to the Integer that digit represents in the number system
   */
  private lazy val digitMap: IMap[Char, Int] = IMap() ++ digitArray.zipWithIndex

  private def digitToInt(digit: Char): Option[Int] = digitMap.get(digit)

  //DREAM: - test this version against one which calculates it on the fly with ascii / char values and use fastest
  private def intToDigit(i: Int): Option[Char] = {
    try {
      Some(digitArray(i))
    } catch {
      case e: Throwable => None
    }
  }

  private def stopIt = {
    throw new Exception("Exception in Number System") {
      override def fillInStackTrace() =  this
    }
  }

  /**
   * Converts a based number (represented as a string) into a long if possible
   * Will return None if unable to convert the string into a long
   */
  def baseXToLong(number: String): Option[Long] = {
    if (number.isEmpty) {
      None
    } else {
      try {
        Some(number.map(digitToInt(_).getOrElse {stopIt}).foldLeft(0L)((acc, digit) => acc * base + digit))
      } catch {
        case e: Throwable => None
      }
    }
  }

  /**
   * Converts a decimal long value into a based number (represented as a string)
   * Will return None if try to convert a negative number...
   */
  def longToBaseX(value: Long): Option[String] = {
    @tailrec
    def record(acc: StringBuilder, value: Long): String = {
      value match {
        case x if (x == 0L) => acc.reverse.toString
        case x => {
          acc.append(intToDigit((x % base).toInt).get)
          record(acc, x / base)
        }
      }
    }

    if (value < 0L) {
      None
    } else if (value == 0) {
      intToDigit(0).map(_.toString)
    } else {
      Some(record(new StringBuilder, value))
    }
  }
}

/**
 * Base 36 numbers represented with numbers and uppercase letters
 * Used to create ClOrdIds for the CME (they use those characters)
 */
object Base36 extends NumberSystem {
  override protected val digitArray: Array[Char] = {
    val alphabet = ('0' to '9') ++ ('A' to 'Z')
    alphabet.toArray[Char]
  }
}

/**
 * Base 62 numbers represented with numbers and uppercase + lowercase letters
 * Used for creating forever unique RunIds within the company
 */
object Base62 extends NumberSystem {
  override protected val digitArray: Array[Char] = {
    val alphabet = ('0' to '9') ++ ('a' to 'z') ++ ('A' to 'Z')
    //val WHAT THIS SHOULD BE  = ('0' to '9') ++ ('A' to 'Z') ++ ('a' to 'z')
    alphabet.toArray[Char]
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy