summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2010-06-28 15:21:47 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2010-06-28 15:21:47 +0000
commit44ca9e1e608e07042b9536dcfd986f2a6a128482 (patch)
treee44714f55442b7343f9a604f23bb9045d92234d0 /src/library
parent6c7d1d8902c0fe4b425dc1a789d366dad7dad251 (diff)
downloadscala-44ca9e1e608e07042b9536dcfd986f2a6a128482.tar.gz
scala-44ca9e1e608e07042b9536dcfd986f2a6a128482.tar.bz2
scala-44ca9e1e608e07042b9536dcfd986f2a6a128482.zip
Merged revisions 22399-22400 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r22399 | extempore | 2010-06-27 03:34:40 +0200 (Sun, 27 Jun 2010) | 2 lines Disposed of a gordian knot by transforming stringbuilder into a straight wrapper of java's. No review. ........ r22400 | extempore | 2010-06-27 03:35:11 +0200 (Sun, 27 Jun 2010) | 1 line Removed unfinished Jenkins hashcode for final. No review. ........
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/Predef.scala1
-rw-r--r--src/library/scala/collection/mutable/StringBuilder.scala258
-rw-r--r--src/library/scala/package.scala1
-rw-r--r--src/library/scala/runtime/ScalaRunTime.scala4
-rw-r--r--src/library/scala/util/JenkinsHash.scala191
5 files changed, 74 insertions, 381 deletions
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 502fe4a935..1e926ea07a 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -32,7 +32,6 @@ object Predef extends LowPriorityImplicits {
// miscelleaneous -----------------------------------------------------
scala.`package` // to force scala package object to be seen.
scala.collection.immutable.List // to force Nil, :: to be seen.
- scala.collection.mutable.StringBuilder // to force StringBuilder to be seen.
type Function[-A, +B] = Function1[A, B]
diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala
index 8bf1aca6b4..e9258c9730 100644
--- a/src/library/scala/collection/mutable/StringBuilder.scala
+++ b/src/library/scala/collection/mutable/StringBuilder.scala
@@ -6,16 +6,11 @@
** |/ **
\* */
-
-
package scala.collection
package mutable
-import generic._
-import compat.Platform.arraycopy
-import scala.reflect.Manifest
+import java.lang.{ StringBuilder => JavaStringBuilder }
import annotation.migration
-import StringBuilder._
/** A builder for mutable sequence of characters. This class provides an API
* mostly compatible with java.lang.StringBuilder, except where there are conflicts
@@ -28,20 +23,17 @@ import StringBuilder._
*/
@serializable
@SerialVersionUID(0 - 8525408645367278351L)
-final class StringBuilder(initCapacity: Int, private val initValue: String)
+final class StringBuilder(private val underlying: JavaStringBuilder)
extends Builder[Char, String]
+ with java.lang.CharSequence
with IndexedSeq[Char]
with IndexedSeqOptimized[Char, IndexedSeq[Char]] {
- require(initCapacity >= 0)
-
- import scala.collection.Seq
-
- /** The value is used for character storage. */
- private var array = new Array[Char](initCapacity + initValue.length)
-
- /** The count is the number of characters used. */
- private var count: Int = 0
+ /** Constructs a string builder initialized with String initValue
+ * and with additional Char capacity initCapacity.
+ */
+ def this(initCapacity: Int, initValue: String) =
+ this(new JavaStringBuilder(initValue.length + initCapacity) append initValue)
/** Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
@@ -49,11 +41,10 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
def this() = this(16, "")
/** Constructs a string builder with no characters in it and an
- * initial capacity specified by the <code>capacity</code> argument.
+ * initial capacity specified by the capacity argument.
*
* @param capacity the initial capacity.
- * @throws NegativeArraySizeException if the <code>capacity</code>
- * argument is less than <code>0</code>.
+ * @throws NegativeArraySizeException if capacity < 0.
*/
def this(capacity: Int) = this(capacity, "")
@@ -62,12 +53,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
*/
def this(str: String) = this(16, str)
- append(initValue)
-
- def toArray: Array[Char] = array
+ def toArray: Array[Char] = {
+ val arr = new Array[Char](length)
+ underlying.getChars(0, length, arr, 0)
+ arr
+ }
- def length: Int = count
- def length_=(n: Int) { setLength(n) }
+ def length: Int = underlying.length()
+ def length_=(n: Int) { underlying.setLength(n) }
/** Clears the builder contents.
*/
@@ -80,18 +73,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param len the new length
* @throws IndexOutOfBoundsException if the argument is negative.
*/
- def setLength(len: Int) {
- require(len >= 0, len)
- while (count < len) append('\0')
- count = len
- }
+ def setLength(len: Int) { underlying setLength len }
/** Returns the current capacity, which is the size of the underlying array.
* A new array will be allocated if the current capacity is exceeded.
*
* @return the capacity
*/
- def capacity: Int = array.length
+ def capacity: Int = underlying.capacity()
@deprecated("Use `ensureCapacity' instead. An assignment is misleading because\n"+
"it can never decrease the capacity.")
@@ -104,13 +93,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
*
* @param newCapacity the minimum desired capacity.
*/
- def ensureCapacity(newCapacity: Int): Unit =
- if (newCapacity > array.length) {
- val newSize = (array.length * 2 + 2) max newCapacity
- val newArray = new Array[Char](newSize)
- arraycopy(array, 0, newArray, 0, count)
- array = newArray
- }
+ def ensureCapacity(newCapacity: Int): Unit = underlying ensureCapacity newCapacity
/** Returns the Char at the specified index, counting from 0 as in Arrays.
*
@@ -118,15 +101,11 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return the Char at the given index.
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
- def charAt(index: Int): Char = {
- if (index < 0 || index >= count)
- throw new StringIndexOutOfBoundsException(index)
- array(index)
- }
+ def charAt(index: Int): Char = underlying charAt index
/** Equivalent to charAt.
*/
- def apply(i: Int): Char = charAt(i)
+ def apply(index: Int): Char = underlying charAt index
/** Removes the Char at the specified index. The sequence is
* shortened by one.
@@ -136,10 +115,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
def deleteCharAt(index: Int): StringBuilder = {
- if (index < 0 || index >= count)
- throw new StringIndexOutOfBoundsException(index)
- arraycopy(array, index + 1, array, index, count - index - 1)
- count -= 1
+ underlying deleteCharAt index
this
}
@@ -149,15 +125,11 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param ch the new Char.
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
- def setCharAt(index: Int, ch: Char) {
- if (index < 0 || index >= count)
- throw new StringIndexOutOfBoundsException(index)
- array(index) = ch
- }
+ def setCharAt(index: Int, ch: Char): Unit = underlying.setCharAt(index, ch)
/** Equivalent to setCharAt.
*/
- def update(i: Int, c: Char) { setCharAt(i, c) }
+ def update(i: Int, c: Char): Unit = setCharAt(i, c)
/** Returns a new String made up of a subsequence of this sequence,
* beginning at the given index and extending to the end of the sequence.
@@ -182,16 +154,10 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @throws StringIndexOutOfBoundsException If either index is out of bounds,
* or if start > end.
*/
- def substring(start: Int, end: Int): String = {
- if (start < 0)
- throw new StringIndexOutOfBoundsException(start)
- if (end > count)
- throw new StringIndexOutOfBoundsException(end)
- if (start > end)
- throw new StringIndexOutOfBoundsException(end - start)
- new String(array, start, end - start)
- }
+ def substring(start: Int, end: Int): String = underlying.substring(start, end)
+ /** For implementing CharSequence.
+ */
def subSequence(start: Int, end: Int): java.lang.CharSequence = substring(start, end)
/** Appends the given Char to the end of the sequence.
@@ -208,7 +174,10 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param x an <code>Any</code> object.
* @return this StringBuilder.
*/
- def append(x: Any): StringBuilder = append(String.valueOf(x))
+ def append(x: Any): StringBuilder = {
+ underlying append String.valueOf(x)
+ this
+ }
/** Appends the given String to this sequence.
*
@@ -216,11 +185,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return this StringBuilder.
*/
def append(s: String): StringBuilder = {
- val str = onull(s)
- val len = str.length
- ensureCapacity(count + len)
- str.getChars(0, len, array, count)
- count += len
+ underlying append s
this
}
@@ -229,30 +194,27 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param sb
* @return
*/
- def append(sb: StringBuilder): StringBuilder =
- if (sb == null)
- append("null")
- else {
- val len = sb.length
- ensureCapacity(count + len)
- arraycopy(sb.toArray, 0, array, count, len)
- count += len
- this
- }
+ def append(sb: StringBuilder): StringBuilder = {
+ underlying append sb
+ this
+ }
/** Appends all the Chars in the given Seq[Char] to this sequence.
*
* @param xs the characters to be appended.
* @return this StringBuilder.
*/
- def appendAll(xs: Seq[Char]): StringBuilder = appendAll(xs.toArray, 0, xs.length)
+ def appendAll(xs: TraversableOnce[Char]): StringBuilder = appendAll(xs.toArray)
/** Appends all the Chars in the given Array[Char] to this sequence.
*
* @param xs the characters to be appended.
* @return a reference to this object.
*/
- def appendAll(xs: Array[Char]): StringBuilder = appendAll(xs, 0, xs.length)
+ def appendAll(xs: Array[Char]): StringBuilder = {
+ underlying append xs
+ this
+ }
/** Appends a portion of the given Array[Char] to this sequence.
*
@@ -262,9 +224,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return this StringBuilder.
*/
def appendAll(xs: Array[Char], offset: Int, len: Int): StringBuilder = {
- ensureCapacity(count + len)
- arraycopy(xs, offset, array, count, len)
- count += len
+ underlying.append(xs, offset, len)
this
}
@@ -275,19 +235,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param x a primitive value
* @return This StringBuilder.
*/
- def append(x: Boolean): StringBuilder = append(String.valueOf(x))
- def append(x: Byte): StringBuilder = append(String.valueOf(x))
- def append(x: Short): StringBuilder = append(String.valueOf(x))
- def append(x: Int): StringBuilder = append(String.valueOf(x))
- def append(x: Long): StringBuilder = append(String.valueOf(x))
- def append(x: Float): StringBuilder = append(String.valueOf(x))
- def append(x: Double): StringBuilder = append(String.valueOf(x))
- def append(x: Char): StringBuilder = {
- ensureCapacity(count + 1)
- array(count) = x
- count += 1
- this
- }
+ def append(x: Boolean): StringBuilder = { underlying append x ; this }
+ def append(x: Byte): StringBuilder = { underlying append x ; this }
+ def append(x: Short): StringBuilder = { underlying append x ; this }
+ def append(x: Int): StringBuilder = { underlying append x ; this }
+ def append(x: Long): StringBuilder = { underlying append x ; this }
+ def append(x: Float): StringBuilder = { underlying append x ; this }
+ def append(x: Double): StringBuilder = { underlying append x ; this }
+ def append(x: Char): StringBuilder = { underlying append x ; this }
/** Remove a subsequence of Chars from this sequence, starting at the
* given start index (inclusive) and extending to the end index (exclusive)
@@ -299,14 +254,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @throws StringIndexOutOfBoundsException if start < 0 || start > end
*/
def delete(start: Int, end: Int): StringBuilder = {
- if (start < 0 || start > end)
- throw new StringIndexOutOfBoundsException(start)
- val end0 = if (end > count) count else end
- val len = end0 - start
- if (len > 0) {
- arraycopy(array, start + len, array, start, count - end0)
- count -= len
- }
+ underlying.delete(start, end)
this
}
@@ -319,18 +267,8 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return This StringBuilder.
* @throws StringIndexOutOfBoundsException if start < 0, start > length, or start > end
*/
- def replace(start: Int, end: Int, str: String) {
- if (start < 0 || start > count || start > end)
- throw new StringIndexOutOfBoundsException(start)
-
- val end0 = if (end > count) count else end
- val len = str.length()
- val newCount = count + len - (end0 - start)
- ensureCapacity(newCount)
-
- arraycopy(array, end, array, start + len, count - end)
- str.getChars(0, len, array, start)
- count = newCount
+ def replace(start: Int, end: Int, str: String): StringBuilder = {
+ underlying.replace(start, end, str)
this
}
@@ -347,16 +285,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* offset < 0, len < 0, or (offset + len) > str.length.
*/
def insertAll(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = {
- if (index < 0 || index > count)
- throw new StringIndexOutOfBoundsException(index)
- if (offset < 0 || len < 0 || offset > str.length - len)
- throw new StringIndexOutOfBoundsException(
- "offset " + offset + ", len " + len +
- ", str.length " + str.length)
- ensureCapacity(count + len)
- arraycopy(array, index, array, index + len, count - index)
- arraycopy(str, offset, array, index, len)
- count += len
+ underlying.insert(index, str, offset, len)
this
}
@@ -377,7 +306,10 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return this StringBuilder.
* @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
- def insert(index: Int, x: String): StringBuilder = insertAll(index, x.toArray)
+ def insert(index: Int, x: String): StringBuilder = {
+ underlying.insert(index, x)
+ this
+ }
/** Inserts the given Seq[Char] into this sequence at the given index.
*
@@ -386,7 +318,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return this StringBuilder.
* @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
- def insertAll(index: Int, xs: Seq[Char]): StringBuilder = insertAll(index, xs.toArray)
+ def insertAll(index: Int, xs: TraversableOnce[Char]): StringBuilder = insertAll(index, xs.toArray)
/** Inserts the given Array[Char] into this sequence at the given index.
*
@@ -396,13 +328,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @throws StringIndexOutOfBoundsException if the index is out of bounds.
*/
def insertAll(index: Int, xs: Array[Char]): StringBuilder = {
- if (index < 0 || index > count)
- throw new StringIndexOutOfBoundsException(index)
- val len = xs.length
- ensureCapacity(count + len)
- arraycopy(array, index, array, index + len, count - index)
- arraycopy(xs, 0, array, index, len)
- count += len
+ underlying.insert(index, xs)
this
}
@@ -420,15 +346,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
def insert(index: Int, x: Long): StringBuilder = insert(index, String.valueOf(x))
def insert(index: Int, x: Float): StringBuilder = insert(index, String.valueOf(x))
def insert(index: Int, x: Double): StringBuilder = insert(index, String.valueOf(x))
- def insert(index: Int, x: Char): StringBuilder = {
- if (index < 0 || index > count)
- throw new StringIndexOutOfBoundsException(index)
- ensureCapacity(count + 1)
- arraycopy(array, index, array, index + 1, count - index)
- array(index) = x
- count += 1
- this
- }
+ def insert(index: Int, x: Char): StringBuilder = insert(index, String.valueOf(x))
@deprecated("Use appendAll instead. This method is deprecated because of the\n"+
"possible confusion with `append(Any)'.")
@@ -453,15 +371,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
@deprecated("use insertAll instead. This method is deprecated because of\n"+
"the possible confusion with `insert(Int, Any)'.")
- def insert(at: Int, x: Array[Char]): StringBuilder =
- insertAll(at, x)
+ def insert(at: Int, x: Array[Char]): StringBuilder = insertAll(at, x)
/** Finds the index of the first occurrence of the specified substring.
*
* @param str the target string to search for
* @return the first applicable index where target occurs, or -1 if not found.
*/
- def indexOf(str: String): Int = indexOf(str, 0)
+ def indexOf(str: String): Int = underlying.indexOf(str)
/** Finds the index of the first occurrence of the specified substring.
*
@@ -469,14 +386,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param fromIndex the smallest index in the source string to consider
* @return the first applicable index where target occurs, or -1 if not found.
*/
- def indexOf(str: String, fromIndex: Int): Int = indexOfSlice(str.toIndexedSeq, fromIndex)
+ def indexOf(str: String, fromIndex: Int): Int = underlying.indexOf(str, fromIndex)
/** Finds the index of the last occurrence of the specified substring.
*
* @param str the target string to search for
* @return the last applicable index where target occurs, or -1 if not found.
*/
- def lastIndexOf(str: String): Int = lastIndexOf(str, count)
+ def lastIndexOf(str: String): Int = underlying.lastIndexOf(str)
/** Finds the index of the last occurrence of the specified substring.
*
@@ -484,7 +401,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @param fromIndex the smallest index in the source string to consider
* @return the last applicable index where target occurs, or -1 if not found.
*/
- def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSlice(str.toIndexedSeq, fromIndex)
+ def lastIndexOf(str: String, fromIndex: Int): Int = underlying.lastIndexOf(str, fromIndex)
/** Creates a new StringBuilder with the reversed contents of this one.
* If surrogate pairs are present, they are treated as indivisible units: each
@@ -493,33 +410,16 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
* @return the reversed StringBuilder
*/
@migration(2, 8, "Since 2.8 reverse returns a new instance. Use 'reverseContents' to update in place.")
- override def reverse: StringBuilder = new StringBuilder(this.toString).reverseContents()
+ override def reverse: StringBuilder = new StringBuilder(new JavaStringBuilder(underlying) reverse)
+
+ override def clone(): StringBuilder = new StringBuilder(new JavaStringBuilder(underlying))
/** Like reverse, but destructively updates the target StringBuilder.
*
* @return the reversed StringBuilder (same as the target StringBuilder)
*/
def reverseContents(): StringBuilder = {
- // record of indices of pairs which need to be swapped
- val surrogates = new ListBuffer[(Int, Int)]
- val half = count / 2
-
- def mirror(x: Int) = count - 1 - x
- def swap(i1: Int, i2: Int) {
- val tmp = array(i2)
- array(i2) = array(i1)
- array(i1) = tmp
- }
-
- for ((i, j) <- 0 until half zip (count - 1 to half by -1)) {
- if (array(i).isSurrogate && array(i + 1).isSurrogate)
- surrogates += ((j - 1, j))
- if (array(j).isSurrogate && array(j - 1).isSurrogate)
- surrogates += ((i, i + 1))
-
- swap(i, j)
- }
- surrogates foreach (swap _).tupled
+ underlying.reverse()
this
}
@@ -527,21 +427,7 @@ final class StringBuilder(initCapacity: Int, private val initValue: String)
*
* @return the current contents of this sequence as a String
*/
- override def toString: String = new String(array, 0, count)
+ override def toString = underlying.toString
def result(): String = toString
}
-
-
-object StringBuilder
-{
- // method <code>java.util.Arrays.copyOf</code> exists since 1.6
- private def copyOf(src: Array[Char], newLength: Int): Array[Char] = {
- val dest = new Array[Char](newLength)
- arraycopy(src, 0, dest, 0, src.length min newLength)
- dest
- }
-
- // for mimicking java's propensity to make null into "null"
- private def onull(s: String): String = if (s == null) "null" else s
-}
diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala
index b92d420391..50eccc8ec2 100644
--- a/src/library/scala/package.scala
+++ b/src/library/scala/package.scala
@@ -60,7 +60,6 @@ package object scala {
val Vector = scala.collection.immutable.Vector
type StringBuilder = scala.collection.mutable.StringBuilder
- val StringBuilder = scala.collection.mutable.StringBuilder
type Range = scala.collection.immutable.Range
val Range = scala.collection.immutable.Range
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala
index 26dc0830e5..a1d15c4b7d 100644
--- a/src/library/scala/runtime/ScalaRunTime.scala
+++ b/src/library/scala/runtime/ScalaRunTime.scala
@@ -145,8 +145,8 @@ object ScalaRunTime {
def _toString(x: Product): String =
x.productIterator.mkString(x.productPrefix + "(", ",", ")")
- def _hashCodeJenkins(x: Product): Int =
- scala.util.JenkinsHash.hashSeq(x.productPrefix.toSeq ++ x.productIterator.toSeq)
+ // def _hashCodeJenkins(x: Product): Int =
+ // scala.util.JenkinsHash.hashSeq(x.productPrefix.toSeq ++ x.productIterator.toSeq)
def _hashCode(x: Product): Int = {
val arr = x.productArity
diff --git a/src/library/scala/util/JenkinsHash.scala b/src/library/scala/util/JenkinsHash.scala
deleted file mode 100644
index 83df5ad834..0000000000
--- a/src/library/scala/util/JenkinsHash.scala
+++ /dev/null
@@ -1,191 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.util
-
-import java.nio.ByteBuffer
-
-/**
- * Original algorithm due to Bob Jenkins.
- * http://burtleburtle.net/bob/c/lookup3.c
- * Scala version partially adapted from java version by Gray Watson.
- * http://256.com/sources/jenkins_hash_java/JenkinsHash.java
- *
- * This is based on the 1996 version, not the 2006 version, and
- * could most likely stand some improvement; the collision rate is
- * negligible in my tests, but performance merits investigation.
- *
- * @author Paul Phillips
- */
-
-object JenkinsHash {
- final val MAX_VALUE = 0xFFFFFFFFL
-
- private def bytesProvided(v: Any) = v match {
- case x: Byte => 1
- case x: Short => 2
- case x: Int => 4
- case x: Long => 8
- case x: Float => 4
- case x: Double => 8
- case x: Boolean => 1
- case x: Char => 2
- case x: Unit => 0
- case _ => 4
- }
-
- private def putAnyVal(bb: ByteBuffer, v: AnyVal) = v match {
- case x: Byte => bb put x
- case x: Short => bb putShort x
- case x: Int => bb putInt x
- case x: Long => bb putLong x
- case x: Float => bb putFloat x
- case x: Double => bb putDouble x
- case x: Boolean => bb.put(if (x) Byte.MaxValue else Byte.MinValue)
- case x: Char => bb putChar x
- case x: Unit =>
- }
-
- /** Not entirely sure how else one might do this these days, since
- * matching on x: AnyVal is a compile time error.
- */
- private def classifyAny(x: Any): (Option[AnyVal], Option[AnyRef]) = x match {
- case x: Byte => (Some(x), None)
- case x: Short => (Some(x), None)
- case x: Int => (Some(x), None)
- case x: Long => (Some(x), None)
- case x: Float => (Some(x), None)
- case x: Double => (Some(x), None)
- case x: Boolean => (Some(x), None)
- case x: Char => (Some(x), None)
- case x: Unit => (Some(x), None)
- case x: AnyRef => (None, Some(x))
- }
-
- private def partitionValuesAndRefs(xs: Seq[Any]): (Seq[AnyVal], Seq[AnyRef]) = {
- val (avs, ars) = xs map classifyAny unzip
-
- (avs.flatten, ars.flatten)
- }
-
- private def hashAnyValSeq(xs: Seq[AnyVal]): Int = {
- val arr = new Array[Byte](xs map bytesProvided sum)
- val bb = ByteBuffer wrap arr
- xs foreach (x => putAnyVal(bb, x))
-
- hash(bb.array()).toInt
- }
-
- /**
- * Convert a byte into a long value without making it negative.
- */
- private def byteToLong(b: Byte): Long = {
- val res = b & 0x7F
- if ((b & 0x80) != 0L) res + 128
- else res
- }
-
- /**
- * Do addition and turn into 4 bytes.
- */
- private def add(x1: Long, x2: Long) = (x1 + x2) & MAX_VALUE
-
- /**
- * Do subtraction and turn into 4 bytes.
- */
- private def subtract(x1: Long, x2: Long) = (x1 - x2) & MAX_VALUE
-
- /**
- * Left shift val by shift bits and turn in 4 bytes.
- */
- private def xor(x1: Long, x2: Long) = (x1 ^ x2) & MAX_VALUE
-
- /**
- * Left shift val by shift bits. Cut down to 4 bytes.
- */
- private def leftShift(x: Long, shift: Int) = (x << shift) & MAX_VALUE
-
- /**
- * Convert 4 bytes from the buffer at offset into a long value.
- */
- private def fourByteToLong(bytes: Array[Byte], offset: Int) =
- 0 to 3 map (i => byteToLong(bytes(offset + i)) << (i * 8)) sum
-
- /**
- * Hash a sequence of anything into a 32-bit value. Descendants
- * of AnyVal are broken down into individual bytes and mixed with
- * some vigor, and this is summed with the hashCodes provided by
- * the descendants of AnyRef.
- */
- def hashSeq(xs: Seq[Any]): Int = {
- val (values, refs) = partitionValuesAndRefs(xs)
- val refsSum = refs map (x => if (x == null) 0 else x.##) sum
-
- hashAnyValSeq(values) + refsSum
- }
-
- /**
- * Hash a variable-length key into a 32-bit value. Every bit of the
- * key affects every bit of the return value. Every 1-bit and 2-bit
- * delta achieves avalanche. The best hash table sizes are powers of 2.
- *
- * @param buffer Byte array that we are hashing on.
- * @param initialValue Initial value of the hash if we are continuing from
- * a previous run. 0 if none.
- * @return Hash value for the buffer.
- */
- def hash(buffer: Array[Byte], initialValue: Long = 0L): Long = {
- var a, b = 0x09e3779b9L
- var c = initialValue
-
- def hashMix(): Long = {
- a = subtract(a, b); a = subtract(a, c); a = xor(a, c >> 13);
- b = subtract(b, c); b = subtract(b, a); b = xor(b, leftShift(a, 8));
- c = subtract(c, a); c = subtract(c, b); c = xor(c, (b >> 13));
- a = subtract(a, b); a = subtract(a, c); a = xor(a, (c >> 12));
- b = subtract(b, c); b = subtract(b, a); b = xor(b, leftShift(a, 16));
- c = subtract(c, a); c = subtract(c, b); c = xor(c, (b >> 5));
- a = subtract(a, b); a = subtract(a, c); a = xor(a, (c >> 3));
- b = subtract(b, c); b = subtract(b, a); b = xor(b, leftShift(a, 10));
- c = subtract(c, a); c = subtract(c, b); c = xor(c, (b >> 15));
-
- c
- }
-
- def mixTwelve(pos: Int) = {
- a = add(a, fourByteToLong(buffer, pos));
- b = add(b, fourByteToLong(buffer, pos + 4));
- c = add(c, fourByteToLong(buffer, pos + 8));
- hashMix()
- }
-
- // mix in blocks of 12
- var pos: Int = buffer.length
- while (pos >= 12) {
- pos -= 12
- mixTwelve(pos)
- }
- c += buffer.length
-
- // mix any leftover bytes (0-11 remaining)
- if (pos > 10) c = add(c, leftShift(byteToLong(buffer(10)), 24))
- if (pos > 9) c = add(c, leftShift(byteToLong(buffer(9)), 16))
- if (pos > 8) c = add(c, leftShift(byteToLong(buffer(8)), 8))
- if (pos > 7) b = add(b, leftShift(byteToLong(buffer(7)), 24))
- if (pos > 6) b = add(b, leftShift(byteToLong(buffer(6)), 16))
- if (pos > 5) b = add(b, leftShift(byteToLong(buffer(5)), 8))
- if (pos > 4) b = add(b, byteToLong(buffer(4)))
- if (pos > 3) a = add(a, leftShift(byteToLong(buffer(3)), 24))
- if (pos > 2) a = add(a, leftShift(byteToLong(buffer(2)), 16))
- if (pos > 1) a = add(a, leftShift(byteToLong(buffer(1)), 8))
- if (pos > 0) a = add(a, byteToLong(buffer(0)))
-
- // final mix and result
- hashMix()
- }
-}