diff options
author | Paul Phillips <paulp@improving.org> | 2009-05-08 22:02:14 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-05-08 22:02:14 +0000 |
commit | 974735b01f3c08d9fef02b8ab5f086d2d689a590 (patch) | |
tree | a245e72d2e006a43d102f1d1b57e95e02ff69621 | |
parent | 8b030ca4844d6a0ad67f4b47f416a7af59bddea2 (diff) | |
download | scala-974735b01f3c08d9fef02b8ab5f086d2d689a590.tar.gz scala-974735b01f3c08d9fef02b8ab5f086d2d689a590.tar.bz2 scala-974735b01f3c08d9fef02b8ab5f086d2d689a590.zip |
Explicit locking on Symbol creation so multiple...
Explicit locking on Symbol creation so multiple readers don't have to
block up on synchronize. Closes bug #1307.
-rw-r--r-- | src/library/scala/Symbol.scala | 84 |
1 files changed, 49 insertions, 35 deletions
diff --git a/src/library/scala/Symbol.scala b/src/library/scala/Symbol.scala index becb37bc96..610cc839c3 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -11,13 +11,6 @@ package scala -// jcl disabled for now; go directly to java collections. -//import scala.collection.jcl - -//private[scala] object internedSymbols extends jcl.WeakHashMap[String, ref.WeakReference[Symbol]] -private[scala] object internedSymbols - extends java.util.WeakHashMap[String, java.lang.ref.WeakReference[Symbol]] - /** <p> * This class provides a simple way to get unique objects for * equal strings. Since symbols are interned, they can be compared using @@ -37,7 +30,6 @@ private[scala] object internedSymbols */ @serializable final class Symbol private (val name: String) { - /** Converts this symbol to a string. */ override def toString(): String = "'" + name @@ -46,34 +38,56 @@ final class Symbol private (val name: String) { private def readResolve(): Any = Symbol.apply(name) } -object Symbol { +object Symbol extends UniquenessCache[String, Symbol] +{ + protected def valueFromKey(name: String): Symbol = new Symbol(name) + protected def keyFromValue(sym: Symbol): Option[String] = Some(sym.name) +} - /** <p> - * Makes this symbol into a unique reference. - * </p> - * <p> - * If two interened symbols are equal (i.e. they have the same name) - * then they must be identical (wrt reference equality). - * </p> - * - * @return the unique reference to this string. - */ - def apply(name: String): Symbol = internedSymbols.synchronized { -// internedSymbols.get(name).flatMap(_.get) match { -// case Some(sym) => sym -// case _ => -// val sym = new Symbol(name) -// internedSymbols(name) = new ref.WeakReference(sym) -// sym - var sym: Symbol = null - val ref = internedSymbols.get(name) - if (ref != null) sym = ref.get - if (sym == null) { - sym = new Symbol(name) - internedSymbols.put(name, new java.lang.ref.WeakReference(sym)) +/** This is private so it won't appear in the library API, but + * abstracted to offer some hope of reusability. */ +private[scala] abstract class UniquenessCache[K, V >: Null] +{ + import java.lang.ref.{ ReferenceQueue, WeakReference } + import java.util.WeakHashMap + import java.util.concurrent.locks.ReentrantReadWriteLock + + private val queue = new ReferenceQueue[V] + private val rwl = new ReentrantReadWriteLock() + private val rlock = rwl.readLock + private val wlock = rwl.writeLock + private val map = new WeakHashMap[K, WeakReference[V]] + + protected def valueFromKey(k: K): V + protected def keyFromValue(v: V): Option[K] + + def apply(name: K): V = { + def cached(): V = { + rlock.lock + try { + val reference = map get name + if (reference == null) null + else reference.get // will be null if we were gc-ed + } + finally rlock.unlock + } + def updateCache(): V = { + wlock.lock + try { + val res = cached() + if (res != null) res + else { + val sym = valueFromKey(name) + map.put(name, new WeakReference(sym, queue)) + sym + } + } + finally wlock.unlock } - sym - } - def unapply(other: Symbol): Option[String] = Some(other.name) + val res = cached() + if (res == null) updateCache() + else res + } + def unapply(other: V): Option[K] = keyFromValue(other) } |