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

parsley.token.numeric.BitBounds.scala Maven / Gradle / Ivy

There is a newer version: 5.0.0-M6
Show newest version
/*
 * Copyright 2020 Parsley Contributors 
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package parsley.token.numeric

import scala.annotation.implicitNotFound

private [numeric] sealed abstract class Bits {
    private [numeric] type self <: Bits
    private [numeric] def upperSigned: BigInt
    private [numeric] def lowerSigned: BigInt
    private [numeric] def upperUnsigned: BigInt
    private [numeric] def bits: Int
}
private [numeric] object _8 extends Bits {
    private [numeric] type self = _8.type
    private [numeric] final val upperSigned = Byte.MaxValue
    private [numeric] final val lowerSigned = Byte.MinValue
    private [numeric] final val upperUnsigned = 0xff
    private [numeric] final val bits = 8
}
private [numeric] object _16 extends Bits {
    private [numeric] type self = _16.type
    private [numeric] final val upperSigned = Short.MaxValue
    private [numeric] final val lowerSigned = Short.MinValue
    private [numeric] final val upperUnsigned = 0xffff
    private [numeric] final val bits = 16
}
private [numeric] object _32 extends Bits {
    private [numeric] type self = _32.type
    private [numeric] final val upperSigned = Int.MaxValue
    private [numeric] final val lowerSigned = Int.MinValue
    private [numeric] final val upperUnsigned = 0xffffffffL
    private [numeric] final val bits = 32
}
private [numeric] object _64 extends Bits {
    private [numeric] type self = _64.type
    private [numeric] final val upperSigned = Long.MaxValue
    private [numeric] final val lowerSigned = Long.MinValue
    private [numeric] final val upperUnsigned = BigInt("ffffffffffffffff", 16)
    private [numeric] final val bits = 64
}

private [numeric] sealed abstract class CanHold[N <: Bits, T] {
    private [numeric] def fromBigInt(x: BigInt): T
}

/** This class is used to provide "low-priority" implicits
  * for the types defined within [[CanHold$ `CanHold`]].
  *
  * These implicits are not favoured equally to the implicits
  * defined within [[CanHold$ `CanHold`]] and this means
  * that Scala will not have any ambiguous implicit errors.
  *
  * @since 4.0.0
  */
sealed class LowPriorityImplicits private[numeric] {
    import CanHold.can_hold_64_bits // scalastyle:ignore import.grouping
    // this being here means that Scala will look for it last, which allows default to Long for 64-bit
    /** Evidence that `BigInt` can store (at least) 64 bits of data.
      *
      * @note [[CanHold$.long_64 `long_64`]] is prioritised for implicit selection over this.
      * @since 4.0.0
      */
    implicit val big_64: can_hold_64_bits[BigInt] = new CanHold[_64.type, BigInt] { // scalastyle:ignore field.name
        def fromBigInt(x: BigInt): BigInt = x
    }
}

/** This object contains the definitions of several types that help enforce that
  * parsers of bounded precision only return types that can losslessly accommodate
  * that precision.
  *
  * Note that, on the JVM, there is no such thing as an unsigned value ''natively''.
  * Instead, the JVM provides a guarantee that overflow is well-defined, and, as such
  * supports operations that work on numbers ''as if'' they were unsigned. For this
  * reason, `parsley` makes no distinction between unsigned and signed numbers.
  *
  * @since 4.0.0
  */
object CanHold extends LowPriorityImplicits {
    /** This type-constraint requires that the given type has enough bit-width
      * to store 8 bits of data.
      *
      * @tparam T the type that can accommodate 8 bits.
      * @since 4.0.0
      */
    @implicitNotFound("The type ${T} cannot hold an 8-bit number without loss")
    type can_hold_8_bits[T] = CanHold[_8.type, T] // scalastyle:ignore field.name
    /** This type-constraint requires that the given type has enough bit-width
      * to store 16 bits of data.
      *
      * @tparam T the type that can accommodate 16 bits.
      * @since 4.0.0
      */
    @implicitNotFound("The type ${T} cannot hold a 16-bit number without loss")
    type can_hold_16_bits[T] = CanHold[_16.type, T] // scalastyle:ignore field.name
    /** This type-constraint requires that the given type has enough bit-width
      * to store 32 bits of data.
      *
      * @tparam T the type that can accommodate 32 bits.
      * @since 4.0.0
      */
    @implicitNotFound("The type ${T} cannot hold a 32-bit number without loss")
    type can_hold_32_bits[T] = CanHold[_32.type, T] // scalastyle:ignore field.name
    /** This type-constraint requires that the given type has enough bit-width
      * to store 64 bits of data.
      *
      * @tparam T the type that can accommodate 64 bits.
      * @since 4.0.0
      */
    @implicitNotFound("The type ${T} cannot hold a 64-bit number without loss")
    type can_hold_64_bits[T] = CanHold[_64.type, T] // scalastyle:ignore field.name

    /** Provides evidence that a type that can store 16 bits can also store 8 bits.
      *
      * @since 4.0.0
      */
    implicit def fits_8_16[T: can_hold_16_bits]: can_hold_8_bits[T] = // scalastyle:ignore field.name
        implicitly[can_hold_16_bits[T]].asInstanceOf[can_hold_8_bits[T]]
    /** Provides evidence that a type that can store 32 bits can also store 16 bits.
      *
      * @since 4.0.0
      */
    implicit def fits_16_32[T: can_hold_32_bits]: can_hold_16_bits[T] = // scalastyle:ignore field.name
        implicitly[can_hold_32_bits[T]].asInstanceOf[can_hold_16_bits[T]]
    /** Provides evidence that a type that can store 64 bits can also store 32 bits.
      *
      * @since 4.0.0
      */
    implicit def fits_32_64[T: can_hold_64_bits]: can_hold_32_bits[T] = // scalastyle:ignore field.name
        implicitly[can_hold_64_bits[T]].asInstanceOf[can_hold_32_bits[T]]

    /** Evidence that `Byte` can store 8 bits of data.
      *
      * @since 4.0.0
      */
    implicit val byte_8: can_hold_8_bits[Byte] = new CanHold[_8.type, Byte] { // scalastyle:ignore field.name
        def fromBigInt(x: BigInt): Byte = x.toByte
    }
    /** Evidence that `Short` can store 16 bits of data.
      *
      * @since 4.0.0
      */
    implicit val short_16: can_hold_16_bits[Short] = new CanHold[_16.type, Short] { // scalastyle:ignore field.name
        def fromBigInt(x: BigInt): Short = x.toShort
    }
    /** Evidence that `Int` can store 32 bits of data.
      *
      * @since 4.0.0
      */
    implicit val int_32: can_hold_32_bits[Int] = new CanHold[_32.type, Int] { // scalastyle:ignore field.name
        def fromBigInt(x: BigInt): Int = x.toInt
    }
    /** Evidence that `Long` can store 64 bits of data.
      *
      * @since 4.0.0
      */
    implicit val long_64: can_hold_64_bits[Long] = new CanHold[_64.type, Long] { // scalastyle:ignore field.name
        def fromBigInt(x: BigInt): Long = x.toLong
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy