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

org.gerweck.scala.util.package.scala Maven / Gradle / Ivy

The newest version!
package org.gerweck.scala

import scala.collection.mutable

/** Miscellaneous utility code for manipulating standard objects.
  *
  * This package is designed to be maximally convenient if you `import org.gerweck.scala.util._`.
  *
  * @author Sarah Gerweck 
  */
package object util {
  private[this] final val HashBase = 0x53474073
  private[this] final val HashOffsetStep = 7

  @inline final def rotateHash(v1: Any): Int = {
    HashBase ^ Integer.rotateRight(v1.hashCode, HashOffsetStep)
  }

  @inline final def rotateHash(v1: Any, v2: Any): Int = {
    HashBase ^ Integer.rotateRight(v1.hashCode, HashOffsetStep) ^ Integer.rotateRight(v2.hashCode, 2 * HashOffsetStep)
  }

  /** Compute a very fast hash functional of all the inputs' hashes.
    *
    * There is no guarantee that this value will be stable between releases.
    * It's suitable for an ephemeral hashCode if all the versions of the code
    * are on the same versions of GerweckUtil.
    */
  def rotateHash(v1: Any, v2: Any, inputs: Any*): Int = {
    // This uses a bit of group theory. As long as HashOffset is coprime with 32, we won't
    // repeat our offset until we've added in 32 values, which will take a while.
    @scala.annotation.tailrec @inline def helper(inputs: Seq[Any], offset: Int, current: Int): Int = {
      if (inputs.isEmpty) {
        current
      } else {
        val soak = Integer.rotateRight(inputs.head.hashCode, offset)
        helper(inputs.tail, offset + HashOffsetStep, current ^ soak)
      }
    }
    helper(inputs, HashOffsetStep * 3, rotateHash(v1, v2))
  }

  @inline final def hashProduct(p: Product) = {
    scala.util.hashing.MurmurHash3.seqHash(p.productPrefix +: p.productIterator.toSeq)
  }

  /** Utility functionality for working with characters.
   *
   * @author Sarah Gerweck 
   */
  implicit final class CharUtils(val self: Char) extends AnyVal {

    /** Convert a character to a random case.  It will have a 50% probability of
      * being uppercase and a 50% probability of being lowercase.
      */
    def toRandomCase: Char = if (scala.util.Random.nextBoolean) self.toUpper else self.toLower

    /** Case-insensitive equals.
      *
      * @note `~` is the command-mode vim keystroke to flip the case of a
      * character, and the defined operator looks similar to the mathematical
      * congruence operator (≅). These offer useful mnemonics.
      */
    def =~= (that: Char): Boolean = {
      /*
       * String's `equalsIgnoreCase` is safer than something like `toLower`. The
       * latter is not always safe when dealing with international characters.
       * (Passing in a specific locale is even better, but String provides good
       * generalized behavior.)
       */
      String.valueOf(self) =~= String.valueOf(that)
    }
  }

  /** Utility functionality for working with strings.
    *
    * @author Sarah Gerweck 
    */
  implicit final class StringUtils(val self: String) extends AnyVal {

    /** Convert a string to random case.  Each character will have a 50%
      * probability of being uppercase and a 50% probability of being lowercase.
      */
    def toRandomCase: String = self map { _.toRandomCase }

    /** Case-insensitive equals.
      *
      * @note `~` is the command-mode vim keystroke to flip the case of a
      * character, and the defined operator looks similar to the mathematical
      * congruence operator (≅). These offer useful mnemonics.
      */
    def =~= (that: String): Boolean =
      if (self eq that) true
      else self equalsIgnoreCase that
  }

  /** Enhancements to Java's `MessageFormat` API. */
  implicit final class RichMessageFormat(val mf: java.text.MessageFormat) extends AnyVal {
    final def apply(str: String) = mf.format(Array(str))
    final def apply(str: String, others: String*) = mf.format((str +: others).toArray)
  }

  /** Enhancements to Scala's `Regex` class. */
  implicit final class RichRegex(val inner: scala.util.matching.Regex) extends AnyVal {
    /** Check whether the given regex matches a provided string.
      *
      * Whether the entire string must match is governed by whether this is an anchored regex.
      *
      * @param s the string to test
     */
    def matches(s: String): Boolean = inner.unapplySeq(s).isDefined
  }

  implicit final class RichByteArray(val inner: Array[Byte]) extends AnyVal {
    def toHexString = {
      def hexLow(b: Int): Char = {
        val n = b & 0xf
        val baseChar = if (n > 9) 'W' else '0'
        (baseChar + n).toChar
      }
      val sb = new mutable.StringBuilder(inner.length * 2)
      for (b <- inner) {
        sb += hexLow(b >> 4)
        sb += hexLow(b)
      }
      sb.mkString
    }
    def toUriBase64 = {
      java.util.Base64.getUrlEncoder().encodeToString(inner)
    }
    def toBasicBase64 = {
      java.util.Base64.getEncoder().encodeToString(inner)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy