diff options
author | Stefan Zeiger <szeiger@novocode.com> | 2011-12-02 15:26:03 +0100 |
---|---|---|
committer | Stefan Zeiger <szeiger@novocode.com> | 2011-12-02 15:26:03 +0100 |
commit | 0f87b7b5780267d05d467a2f0075ee746f2cef2f (patch) | |
tree | 49d689fc1fe53946d4015f082a7342982ddef405 | |
parent | 947797ea23d711e501605c0cc218fec88e3b97ef (diff) | |
download | scala-0f87b7b5780267d05d467a2f0075ee746f2cef2f.tar.gz scala-0f87b7b5780267d05d467a2f0075ee746f2cef2f.tar.bz2 scala-0f87b7b5780267d05d467a2f0075ee746f2cef2f.zip |
Enumeration and Enumeration.ValueSet improvements
- Make Enumeration.ValueSet a SortedSet and back it by a BitSet
- Add toBitMask and fromBitMask methods for value sets
- Add an Ordering for the values
- Deprecate names seq in the Enumeration constructor
- Add + method to Value for easy ValueSet creation
-rw-r--r-- | src/library/scala/Enumeration.scala | 63 | ||||
-rw-r--r-- | test/files/run/enums.check | 10 | ||||
-rw-r--r-- | test/files/run/enums.scala | 31 |
3 files changed, 89 insertions, 15 deletions
diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index 07e758013c..5889bea0e9 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -8,7 +8,7 @@ package scala -import scala.collection.{ mutable, immutable, generic, SetLike, AbstractSet } +import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet } import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField } import scala.reflect.NameTransformer._ import java.util.regex.Pattern @@ -53,10 +53,14 @@ import java.util.regex.Pattern * @author Matthias Zenger */ @SerialVersionUID(8476000850333817230L) -abstract class Enumeration(initial: Int, names: String*) extends Serializable { +abstract class Enumeration(initial: Int, + @deprecated("Names should be specified individually or discovered via reflection", "2.10") + names: String*) extends Serializable { thisenum => def this() = this(0) + + @deprecated("Names should be specified individually or discovered via reflection", "2.10") def this(names: String*) = this(0, names: _*) /* Note that `readResolve` cannot be private, since otherwise @@ -86,7 +90,7 @@ abstract class Enumeration(initial: Int, names: String*) extends Serializable { */ def values: ValueSet = { if (!vsetDefined) { - vset = new ValueSet(immutable.SortedSet.empty[Int] ++ (vmap.values map (_.id))) + vset = (ValueSet.newBuilder ++= vmap.values).result() vsetDefined = true } vset @@ -104,6 +108,10 @@ abstract class Enumeration(initial: Int, names: String*) extends Serializable { * enumeration. */ private var topId = initial + /** The lowest integer amongst those used to identify values in this + * enumeration, but no higher than 0. */ + private var bottomId = if(initial < 0) initial else 0 + /** The highest integer amongst those used to identify values in this * enumeration. */ final def maxId = topId @@ -200,6 +208,9 @@ abstract class Enumeration(initial: Int, names: String*) extends Serializable { case _ => false } override def hashCode: Int = id.## + + /** Create a ValueSet which contains this value and another one */ + def + (v: Value) = ValueSet(this, v) } /** A class implementing the [[scala.Enumeration.Value]] type. This class @@ -217,6 +228,7 @@ abstract class Enumeration(initial: Int, names: String*) extends Serializable { vsetDefined = false nextId = i + 1 if (nextId > topId) topId = nextId + if (i < bottomId) bottomId = i def id = i override def toString() = if (name != null) name @@ -230,34 +242,55 @@ abstract class Enumeration(initial: Int, names: String*) extends Serializable { } } + /** An ordering by id for values of this set */ + object ValueOrdering extends Ordering[Value] { + def compare(x: Value, y: Value): Int = x.id - y.id + } + /** A class for sets of values. * Iterating through this set will yield values in increasing order of their ids. * - * @param ids The set of ids of values, organized as a `SortedSet`. + * @param nnIds The set of ids of values (adjusted so that the lowest value does + * not fall below zero), organized as a `BitSet`. */ - class ValueSet private[Enumeration] (val ids: immutable.SortedSet[Int]) + class ValueSet private[ValueSet] (val nnIds: immutable.BitSet) extends AbstractSet[Value] - with Set[Value] - with SetLike[Value, ValueSet] { + with immutable.SortedSet[Value] + with SortedSetLike[Value, ValueSet] { + + implicit def ordering: Ordering[Value] = ValueOrdering + def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet = + new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId))) override def empty = ValueSet.empty - def contains(v: Value) = ids contains (v.id) - def + (value: Value) = new ValueSet(ids + value.id) - def - (value: Value) = new ValueSet(ids - value.id) - def iterator = ids.iterator map thisenum.apply + def contains(v: Value) = nnIds contains (v.id - bottomId) + def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId)) + def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId)) + def iterator = nnIds.iterator map (id => thisenum.apply(id + bottomId)) override def stringPrefix = thisenum + ".ValueSet" + /** Creates a bit mask for the zero-adjusted ids in this set as a + * new array of longs */ + def toBitMask: Array[Long] = nnIds.toBitMask } - + /** A factory object for value sets */ object ValueSet { import generic.CanBuildFrom /** The empty value set */ - val empty = new ValueSet(immutable.SortedSet.empty) + val empty = new ValueSet(immutable.BitSet.empty) /** A value set consisting of given elements */ - def apply(elems: Value*): ValueSet = empty ++ elems + def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result() + /** A value set containing all the values for the zero-adjusted ids + * corresponding to the bits in an array */ + def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems)) /** A builder object for value sets */ - def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.SetBuilder(empty) + def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] { + private[this] val b = new mutable.BitSet + def += (x: Value) = { b += (x.id - bottomId); this } + def clear() = b.clear + def result() = new ValueSet(b.toImmutable) + } /** The implicit builder for value sets */ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] = new CanBuildFrom[ValueSet, Value, ValueSet] { diff --git a/test/files/run/enums.check b/test/files/run/enums.check index f53aba8794..93eadae6e3 100644 --- a/test/files/run/enums.check +++ b/test/files/run/enums.check @@ -3,3 +3,13 @@ test Test2 was successful test Test3 was successful test Test4 was successful +D1.ValueSet(North, East) +D2.ValueSet(North, East) +D1.ValueSet(North, East, West) +D2.ValueSet(North, East, West) +List(101) +List(101) +D1.ValueSet(North, East) +D2.ValueSet(North, East) +WeekDays.ValueSet(Tue, Wed, Thu, Fri) + diff --git a/test/files/run/enums.scala b/test/files/run/enums.scala index 6dda8cbc6e..8c6c88ea07 100644 --- a/test/files/run/enums.scala +++ b/test/files/run/enums.scala @@ -65,6 +65,35 @@ object Test4 { } } +object Test5 { + + object D1 extends Enumeration(0) { + val North, South, East, West = Value; + } + + object D2 extends Enumeration(-2) { + val North, South, East, West = Value; + } + + object WeekDays extends Enumeration { + val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value + } + + def run { + val s1 = D1.ValueSet(D1.North, D1.East) + val s2 = D2.North + D2.East + println(s1) + println(s2) + println(s1 + D1.West) + println(s2 + D2.West) + println(s1.toBitMask.map(_.toBinaryString).toList) + println(s2.toBitMask.map(_.toBinaryString).toList) + println(D1.ValueSet.fromBitMask(s1.toBitMask)) + println(D2.ValueSet.fromBitMask(s2.toBitMask)) + println(WeekDays.values.range(WeekDays.Tue, WeekDays.Sat)) + } +} + //############################################################################ // Test code @@ -94,6 +123,8 @@ object Test { check_success("Test3", Test3.run, 1); check_success("Test4", Test4.run, 0); Console.println; + Test5.run; + Console.println; } } |