Search code examples
scaladictionarysoft-references

Is there a SoftHashMap in Scala?


I'm aware of this question for java, but none of those implementations seem to play well with scala.collection.JavaConversions.

I'm looking for something simple (e.g. single file, not a whole library) that implements SoftHashMap such that it plays well with Scala Map (i.e. supports getOrElseUpdate, unzip, and the remaining Scala Map methods).


Solution

  • Implementation inspired by this java WeakHashMap:

    import scala.collection.mutable.{Map, HashMap}
    import scala.ref._
    
    
    class SoftMap[K, V <: AnyRef] extends Map[K, V]
    {
      class SoftValue[K, +V <: AnyRef](val key:K, value:V, queue:ReferenceQueue[V]) extends SoftReference(value, queue)
    
      private val map = new HashMap[K, SoftValue[K, V]]
    
      private val queue = new ReferenceQueue[V]
    
      override def += (kv: (K, V)): this.type =
      {
        processQueue
        val sv = new SoftValue(kv._1, kv._2, queue)
        map(kv._1) = sv
        this
      }
    
      private def processQueue
      {
        while (true)
        {
          queue.poll match
          {   
            case Some(sv:SoftValue[K, _]) => map.remove(sv.key)
            case _ => return
          }
        }
      }
    
    
      override def get(key: K): Option[V] = map.get(key) match
      {
        case Some(sv) => sv.get match
          { case v:Some[_] => v
            case None => {map.remove(key); None} }
        case None => None
      }
    
    
    
      override def -=(key: K):this.type =
      {
        processQueue
        map.remove(key)
        this
      }
    
      override def iterator: Iterator[(K, V)] =
      {
        processQueue
        map.iterator.collect{ case (key, sv) if sv.get.isDefined => (key, sv.get.get) }
      }
    
      override def empty:SoftMap[K, V] = new SoftMap[K, V]
    
      override def size = {processQueue; map.size}
    }