From 806a524f9a3aedb850c604c7e2d0338b20459432 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 16 May 2011 21:08:41 +0000 Subject: Some largely self-contained utility classes int... Some largely self-contained utility classes into common.util, no review. --- src/compiler/scala/reflect/common/util/Chars.scala | 92 ++++++++++++++++++ .../scala/reflect/common/util/HashSet.scala | 106 +++++++++++++++++++++ src/compiler/scala/reflect/common/util/Set.scala | 28 ++++++ .../scala/reflect/common/util/StatBase.scala | 97 +++++++++++++++++++ .../scala/reflect/common/util/Statistics.scala | 34 +++++++ 5 files changed, 357 insertions(+) create mode 100644 src/compiler/scala/reflect/common/util/Chars.scala create mode 100644 src/compiler/scala/reflect/common/util/HashSet.scala create mode 100644 src/compiler/scala/reflect/common/util/Set.scala create mode 100644 src/compiler/scala/reflect/common/util/StatBase.scala create mode 100644 src/compiler/scala/reflect/common/util/Statistics.scala diff --git a/src/compiler/scala/reflect/common/util/Chars.scala b/src/compiler/scala/reflect/common/util/Chars.scala new file mode 100644 index 0000000000..4175455f1f --- /dev/null +++ b/src/compiler/scala/reflect/common/util/Chars.scala @@ -0,0 +1,92 @@ +/* NSC -- new Scala compiler + * Copyright 2006-2011 LAMP/EPFL + * @author Martin Odersky + */ +package scala.reflect.common.util + +import annotation.{ tailrec, switch } +import java.lang.{ Character => JCharacter } + +/** Contains constants and classifier methods for characters */ +trait Chars { + // Be very careful touching these. + // Apparently trivial changes to the way you write these constants + // will cause Scanners.scala to go from a nice efficient switch to + // a ghastly nested if statement which will bring the type checker + // to its knees. See ticket #1456 + // Martin: (this should be verified now that the pattern rules have been redesigned). + final val LF = '\u000A' + final val FF = '\u000C' + final val CR = '\u000D' + final val SU = '\u001A' + + /** Convert a character digit to an Int according to given base, + * -1 if no success */ + def digit2int(ch: Char, base: Int): Int = { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + ch - '0' + else if ('A' <= ch && ch < 'A' + base - 10) + ch - 'A' + 10 + else if ('a' <= ch && ch < 'a' + base - 10) + ch - 'a' + 10 + else + -1 + } + + /** Convert a character to a backslash-u escape */ + def char2uescape(c: Char): String = { + var rest = c.toInt + val buf = new StringBuilder + for (i <- 1 to 4) { + buf ++= (rest % 16).toHexString + rest = rest / 16 + } + "\\u" + buf.toString.reverse + } + + /** Is character a line break? */ + @inline def isLineBreakChar(c: Char) = (c: @switch) match { + case LF|FF|CR|SU => true + case _ => false + } + + /** Is character a whitespace character (but not a new line)? */ + def isWhitespace(c: Char) = + c == ' ' || c == '\t' || c == CR + + /** Can character form part of a doc comment variable $xxx? */ + def isVarPart(c: Char) = + '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' + + /** Can character start an alphanumeric Scala identifier? */ + def isIdentifierStart(c: Char): Boolean = + (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c) + + /** Can character form part of an alphanumeric Scala identifier? */ + def isIdentifierPart(c: Char) = + (c == '$') || Character.isUnicodeIdentifierPart(c) + + /** Is character a math or other symbol in Unicode? */ + def isSpecial(c: Char) = { + val chtp = Character.getType(c) + chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt + } + + private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_' + private final val letterGroups = { + import JCharacter._ + Set[Byte](LOWERCASE_LETTER, UPPERCASE_LETTER, OTHER_LETTER, TITLECASE_LETTER, LETTER_NUMBER) + } + def isScalaLetter(ch: Char) = letterGroups(JCharacter.getType(ch).toByte) || otherLetters(ch) + + /** Can character form part of a Scala operator name? */ + def isOperatorPart(c : Char) : Boolean = (c: @switch) match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '/' | '\\' => true + case c => isSpecial(c) + } +} + +object Chars extends Chars { } diff --git a/src/compiler/scala/reflect/common/util/HashSet.scala b/src/compiler/scala/reflect/common/util/HashSet.scala new file mode 100644 index 0000000000..53e7835418 --- /dev/null +++ b/src/compiler/scala/reflect/common/util/HashSet.scala @@ -0,0 +1,106 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect.common.util + +object HashSet { + def apply[T >: Null <: AnyRef](): HashSet[T] = this(16) + def apply[T >: Null <: AnyRef](label: String): HashSet[T] = this(label, 16) + def apply[T >: Null <: AnyRef](initialCapacity: Int): HashSet[T] = this("No Label", initialCapacity) + def apply[T >: Null <: AnyRef](label: String, initialCapacity: Int): HashSet[T] = + new HashSet[T](label, initialCapacity) +} + +class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) extends Set[T] { + private var used = 0 + private var table = new Array[AnyRef](initialCapacity) + private def index(x: Int): Int = math.abs(x % table.length) + + def size: Int = used + def clear() { + used = 0 + table = new Array[AnyRef](initialCapacity) + } + + def findEntryOrUpdate(x: T): T = { + var h = index(x.##) + var entry = table(h) + while (entry ne null) { + if (x == entry) + return entry.asInstanceOf[T] + + h = index(h + 1) + entry = table(h) + } + table(h) = x + used += 1 + if (used > (table.length >> 2)) growTable() + x + } + + def findEntry(x: T): T = { + var h = index(x.##) + var entry = table(h) + while ((entry ne null) && x != entry) { + h = index(h + 1) + entry = table(h) + } + entry.asInstanceOf[T] + } + + def addEntry(x: T) { + var h = index(x.##) + var entry = table(h) + while (entry ne null) { + if (x == entry) return + h = index(h + 1) + entry = table(h) + } + table(h) = x + used += 1 + if (used > (table.length >> 2)) growTable() + } + def addEntries(xs: TraversableOnce[T]) { + xs foreach addEntry + } + + def iterator = new Iterator[T] { + private var i = 0 + def hasNext: Boolean = { + while (i < table.length && (table(i) eq null)) i += 1 + i < table.length + } + def next: T = + if (hasNext) { i += 1; table(i - 1).asInstanceOf[T] } + else null + } + + private def addOldEntry(x: T) { + var h = index(x.##) + var entry = table(h) + while (entry ne null) { + h = index(h + 1) + entry = table(h) + } + table(h) = x + } + + private def growTable() { + val oldtable = table + val growthFactor = + if (table.length <= initialCapacity) 8 + else if (table.length <= (initialCapacity * 8)) 4 + else 2 + + table = new Array[AnyRef](table.length * growthFactor) + var i = 0 + while (i < oldtable.length) { + val entry = oldtable(i) + if (entry ne null) addOldEntry(entry.asInstanceOf[T]) + i += 1 + } + } + override def toString() = "HashSet %s(%d / %d)".format(label, used, table.length) +} diff --git a/src/compiler/scala/reflect/common/util/Set.scala b/src/compiler/scala/reflect/common/util/Set.scala new file mode 100644 index 0000000000..f4618e4432 --- /dev/null +++ b/src/compiler/scala/reflect/common/util/Set.scala @@ -0,0 +1,28 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ +package scala.reflect.common.util + +/** A common class for lightweight sets. + */ +abstract class Set[T <: AnyRef] { + + def findEntry(x: T): T + + def addEntry(x: T): Unit + + def iterator: Iterator[T] + + def foreach[U](f: T => U): Unit = iterator foreach f + + def apply(x: T): Boolean = contains(x) + + @deprecated("use `iterator' instead", "2.9.0") def elements = iterator + + def contains(x: T): Boolean = + findEntry(x) ne null + + def toList = iterator.toList + +} diff --git a/src/compiler/scala/reflect/common/util/StatBase.scala b/src/compiler/scala/reflect/common/util/StatBase.scala new file mode 100644 index 0000000000..12083938b7 --- /dev/null +++ b/src/compiler/scala/reflect/common/util/StatBase.scala @@ -0,0 +1,97 @@ +package scala.reflect.common.util + +class StatBase { + + private var _enabled = false + + def enabled = _enabled + def enabled_=(cond: Boolean) = { + if (cond && !_enabled) { + val test = new Timer() + val start = System.nanoTime() + var total = 0L + for (i <- 1 to 10000) { + val time = System.nanoTime() + total += System.nanoTime() - time + } + val total2 = System.nanoTime() - start + println("Enabling statistics, measuring overhead = "+ + total/10000.0+"ns to "+total2/10000.0+"ns per timer") + _enabled = true + } + } + + def currentTime() = + if (_enabled) System.nanoTime() else 0L + + def showPercent(x: Double, base: Double) = + if (base == 0) "" else " ("+"%2.1f".format(x / base * 100)+"%)" + + def incCounter(c: Counter) { + if (_enabled) c.value += 1 + } + + def incCounter(c: Counter, delta: Int) { + if (_enabled) c.value += delta + } + + def startCounter(sc: SubCounter): IntPair = + if (_enabled) sc.start() else null + + def stopCounter(sc: SubCounter, start: IntPair) { + if (_enabled) sc.stop(start) + } + + def startTimer(tm: Timer): LongPair = + if (_enabled) tm.start() else null + + def stopTimer(tm: Timer, start: LongPair) { + if (_enabled) tm.stop(start) + } + + case class IntPair(x: Int, y: Int) + case class LongPair(x: Long, y: Long) + + class Counter { + var value: Int = 0 + override def toString = value.toString + } + + class SubCounter(c: Counter) { + var value: Int = 0 + def start(): IntPair = + if (_enabled) IntPair(value, c.value) else null + def stop(prev: IntPair) { + if (_enabled) { + val IntPair(value0, cvalue0) = prev + value = value0 + c.value - cvalue0 + } + } + override def toString = + value+showPercent(value, c.value) + } + + class Timer { + var nanos: Long = 0 + var timings = 0 + def start(): LongPair = + if (_enabled) { + timings += 1 + LongPair(nanos, System.nanoTime()) + } else null + def stop(prev: LongPair) { + if (_enabled) { + val LongPair(nanos0, start) = prev + nanos = nanos0 + System.nanoTime() - start + timings += 1 + } + } + override def toString = (timings/2)+" spans, "+nanos.toString+"ns" + } + + import Predef.Class + + class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] { + override def default(key: Class[_]) = 0 + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/common/util/Statistics.scala b/src/compiler/scala/reflect/common/util/Statistics.scala new file mode 100644 index 0000000000..85a02c9f37 --- /dev/null +++ b/src/compiler/scala/reflect/common/util/Statistics.scala @@ -0,0 +1,34 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ +package scala.reflect.common.util + +class Statistics extends StatBase { + val singletonBaseTypeSeqCount = new Counter + val compoundBaseTypeSeqCount = new Counter + val typerefBaseTypeSeqCount = new Counter + val findMemberCount = new Counter + val noMemberCount = new Counter + val multMemberCount = new Counter + val findMemberNanos = new Timer + val asSeenFromCount = new Counter + val asSeenFromNanos = new Timer + val subtypeCount = new Counter + val subtypeNanos = new Timer + val sametypeCount = new Counter + val rawTypeCount = new Counter + val rawTypeFailed = new SubCounter(rawTypeCount) + val findMemberFailed = new SubCounter(findMemberCount) + val subtypeFailed = new SubCounter(subtypeCount) + val rawTypeImpl = new SubCounter(rawTypeCount) + val findMemberImpl = new SubCounter(findMemberCount) + val subtypeImpl = new SubCounter(subtypeCount) + val baseTypeSeqCount = new Counter + val baseTypeSeqLenTotal = new Counter + val typeSymbolCount = new Counter + val classSymbolCount = new Counter +} + +object Statistics extends Statistics + -- cgit v1.2.3