/* sbt -- Simple Build Tool
 * Copyright 2010 Mark Harrah
 */
package sbt

/** A mutable set interface that uses object identity to test for set membership.*/
trait IDSet[T]
{
	def apply(t: T): Boolean
	def contains(t: T): Boolean
	def += (t: T): Unit
	def ++=(t: Iterable[T]): Unit
	def -= (t: T): Boolean
	def all: collection.Iterable[T]
	def isEmpty: Boolean
	def foreach(f: T => Unit): Unit
	def process[S](t: T)(ifSeen: S)(ifNew: => S): S
}

object IDSet
{
	implicit def toTraversable[T]: IDSet[T] => Traversable[T] = _.all
	def apply[T](values: T*): IDSet[T] = apply(values)
	def apply[T](values: Iterable[T]): IDSet[T] =
	{
		val s = create[T]
		s ++= values
		s
	}
	def create[T]: IDSet[T] = new IDSet[T] {
		private[this] val backing = new java.util.IdentityHashMap[T, AnyRef]
		private[this] val Dummy: AnyRef = ""

		def apply(t: T) = contains(t)
		def contains(t: T) = backing.containsKey(t)
		def foreach(f: T => Unit) = all foreach f
		def += (t: T) = backing.put(t, Dummy)
		def ++=(t: Iterable[T]) = t foreach +=
		def -= (t:T) = if(backing.remove(t) eq null) false else true
		def all = collection.JavaConversions.collectionAsScalaIterable(backing.keySet)
		def isEmpty = backing.isEmpty
		def process[S](t: T)(ifSeen: S)(ifNew: => S) = if(contains(t)) ifSeen else { this += t ; ifNew }
		override def toString = backing.toString
	}
}
