enumeration.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 359 行
SCALA
359 行
/* __ *\** ________ ___ / / ___ Scala API **** / __/ __// _ | / / / _ | (c) 2002-2007, LAMP/EPFL **** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **** /____/\___/_/ |_/____/_/ | | **** |/ **\* */// $Id: Enumeration.scala 14398 2008-03-17 18:56:09Z odersky $package scalaimport scala.collection.mutable.{Map, HashMap}/** <p> * Defines a finite set of values specific to the enumeration. Typically * these values enumerate all possible forms something can take and provide a * lightweight alternative to case classes. * </p> * <p> * Each call to a <code>Value</code> method adds a new unique value to the * enumeration. To be accessible, these values are usually defined as * <code>val</code> members of the evaluation. * </p> * <p> * All values in an enumeration share a common, unique type defined as the * <code>Value</code> type member of the enumeration (<code>Value</code> * selected on the stable identifier path of the enumeration instance). * </p> * <p> * <b>Example use</b> * </p><pre> * <b>object</b> Main <b>extends</b> Application { * * <b>object</b> WeekDays <b>extends</b> Enumeration { * <b>val</b> Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value * } * * <b>def</b> isWorkingDay(d: WeekDays.Value) = * ! (d == WeekDays.Sat || d == WeekDays.Sun) * * WeekDays filter (isWorkingDay) foreach { d => Console.println(d) } * }</pre> * * @param initial The initial value from which to count the integers that * identifies values at run-time. * @param names The sequence of names to give to this enumeration's values. * * @author Matthias Zenger * @version 1.0, 10/02/04 */abstract class Enumeration(initial: Int, names: String*) { def this() = this(0, null) def this(names: String*) = this(0, names: _*) /** The name of this enumeration. */ def name = { val cname = this.getClass().getName() if (cname.endsWith("$")) cname.substring(0, cname.length() - 1) else if (cname.endsWith("$class")) cname.substring(0, cname.length() - 6) else cname } /** The mapping from the integer used to identifying values to the actual * values. */ private val values: Map[Int, Value] = new HashMap /** The cache listing all values of this enumeration. */ private var vcache: List[Value] = null private def updateCache: List[Value] = if (vcache eq null) { vcache = values.values.toList.sort((p1, p2) => p1.id < p2.id); vcache } else vcache; /** The integer to use to identify the next created value. */ protected var nextId = initial /** The string to use to name the next created value. */ protected var nextName = names.elements /** The highest integer amongst those used to identify values in this * enumeration. */ private var topId = initial /** The highest integer amongst those used to identify values in this * enumeration. */ final def maxId = topId /** The value in this enumeration identified by integer <code>x</code>. */ final def apply(x: Int): Value = values(x) /** A new iterator over all values of this enumeration. */ final def elements: Iterator[Value] = updateCache.elements /** Apply a function f to all values of this enumeration. */ def foreach(f: Value => Unit): Unit = elements foreach f /** Apply a predicate p to all values of this enumeration and return * true, iff the predicate yields true for all values. */ def forall(p: Value => Boolean): Boolean = elements forall p /** Apply a predicate p to all values of this enumeration and return * true, iff there is at least one value for which p yields true. */ def exists(p: Value => Boolean): Boolean = elements exists p /** Returns an iterator resulting from applying the given function f to each * value of this enumeration. */ def map[b](f: Value => b): Iterator[b] = elements map f /** Applies the given function f to each value of this enumeration, then * concatenates the results. */ def flatMap[b](f: Value => Iterator[b]): Iterator[b] = elements flatMap f /** Returns all values of this enumeration that satisfy the predicate p. * The order of values is preserved. */ def filter(p: Value => Boolean): Iterator[Value] = elements filter p override def toString(): String = updateCache.mkString("{", ", ", "}") /** Creates a fresh value, part of this enumeration. */ protected final def Value: Value = new Val(nextId, if (nextName.hasNext) nextName.next else null) /** Creates a fresh value, part of this enumeration, identified by the integer * <code>i</code>. * * @param i An integer that identifies this value at run-time. It must be * unique amongst all values of the enumeration. * @return .. */ protected final def Value(i: Int): Value = new Val(i, if (nextName.hasNext) nextName.next else null) /** Creates a fresh value, part of this enumeration, called <code>name</code>. * * @param name A human-readable name for that value. */ protected final def Value(name: String): Value = new Val(nextId, name) /** Creates a fresh value, part of this enumeration, called <code>name</code> * and identified by the integer <code>i</code>. * * @param i An integer that identifies this value at run-time. It must be * unique amongst all values of the enumeration. * @param name A human-readable name for that value. * @return .. */ protected final def Value(i: Int, name: String): Value = new Val(i, name) /** The type of the enumerated values. */ abstract class Value extends Ordered[Value] { /** the id and bit location of this enumeration value */ def id: Int override def compare(that: Value): Int = this.id - that.id override def equals(other : Any) : Boolean = other match { case that : Value => compare(that) == 0 case _ => false } override def hashCode : Int = id.hashCode /** this enumeration value as an <code>Int</code> bit mask. * @throws IllegalArgumentException if <code>id</code> is greater than 31 */ def mask32: Int = { if (id >= 32) throw new IllegalArgumentException 1 << id } /** this enumeration value as an <code>Long</code> bit mask. * @throws IllegalArgumentException if <code>id</code> is greater than 63 */ def mask64: Long = { if (id >= 64) throw new IllegalArgumentException 1L << id } } /** A class implementing the <a href="Enumeration.Value.html" * target="contentFrame"><code>Value</code></a> type. This class can be * overriden to change the enumeration's naming and integer identification * behaviour. */ protected class Val(i: Int, name: String) extends Value { def this(i: Int) = this(i, if (nextName.hasNext) nextName.next else i.toString()) def this(name: String) = this(nextId, name) def this() = this(nextId, if (nextName.hasNext) nextName.next else nextId.toString()) assert(!values.isDefinedAt(i)) values(i) = this nextId = i + 1 if (nextId > topId) topId = nextId def id = i override def toString() = if (name eq null) Enumeration.this.name + "(" + i + ")" else name } /** A set that efficiently stores enumeration values as bits. * * @author Sean McDirmid * * @ex * * <pre> * <b>object</b> flags <b>extends</b> Enumeration { * <b>val</b> Public = Value(5, "public"); * <b>val</b> Private = Value(4, "private"); * <b>val</b> Protected = Value(6, "protected"); * <b>val</b> Final = Value(7, "final"); * } * * <b>class</b> Entity { * <b>var</b> flags0 : Int = ...; * <b>def</b> flags = flags.Set32(flags0); * } * * <b>val</b> e : Entity = ...; * * <b>if</b> (e.flags.contains(flags.Private)) * e.flags0 = (e.flags | flags.Final).underlying; * </pre> */ abstract class SetXX extends collection.immutable.Set[Value] { /** either Int or Long */ type Underlying <: AnyVal type TSet <: SetXX /** The integer that bit-encodes a set of enumeration values. */ val underlying: Underlying /** returns the underlying integer representation of this set as a long. */ protected def underlyingAsLong: Long /** Equivalent to <code>++</code> for bit sets. Returns a set * that has all values in <code>this</code> and <code>set</code>. */ def |(set: TSet): TSet /** Equivalent to <code>+</code> for bit sets. Returns a set * that has all values in <code>this</code> with the addition of <code>value</code>. */ def |(value: Value): TSet /** Equivalent to <code>**</code> for bit sets. * Returns a bit set that has all values that are both in <code>this</code> and <code>set</code>. */ def &(set: TSet): TSet /** Equivalent to <code>-</code> for bit sets. * Returns a bit set that has all values in <code>this</code> except for <code>value</code>. */ def &~(value: Value): TSet def -(value: Value): TSet = this &~ value def +(value: Value): TSet = this | value def ++(set: TSet): TSet = this | set def **(set: TSet): TSet = this & set def size = { var x = underlyingAsLong var sz = 0 while (x != 0) { if ((x & 1) != 0) sz += 1 x = x >> 1 } sz } override def stringPrefix = Enumeration.this.name; def elements = new Iterator[Value] { var bit = 0 var underlying = underlyingAsLong def hasNext = underlying != 0 private def shift = { underlying = underlying >> 1 bit += 1 } def next = { if (underlying == 0) throw new NoSuchElementException while ((underlying & 1) == 0) shift val ret = values(bit) shift ret } } def empty[B]: scala.collection.immutable.Set[B] = new scala.collection.immutable.HashSet[B]; } /** An enumeration bit set that can handle enumeration values with ids up * to 31 in an <code>Int</code>. */ class Set32(val underlying : Int) extends SetXX { def this() = this(0) type Underlying = Int type TSet = Set32 def underlyingAsLong = { if (underlying >= 0) underlying.toLong else { val underlying0 = (~(1 << 31)) & underlying assert(underlying0 >= 0) underlying0.toLong | (1L << 31) } } def contains(value : Value) = (underlying & value.mask32) != 0 def |(set : Set32) = new Set32(underlying | set.underlying) def |(value : Value) = new Set32(underlying | value.mask32) def &~(value : Value) = new Set32(underlying & (~value.mask32)) def &(set : Set32) = new Set32(underlying & set.underlying) } /** create an empty 32 bit enumeration set */ def Set32 = new Set32 /** create a bit enumeration set according ot underlying */ def Set32(underlying : Int) = new Set32(underlying) /** An enumeration bit set that can handle enumeration values with ids up * to 63 in a <code>Long</code>. */ class Set64(val underlying : Long) extends SetXX { def this() = this(0) type Underlying = Long type TSet = Set64 def underlyingAsLong = underlying def contains(value : Value) = (underlying & value.mask64) != 0 def |( set : Set64) = new Set64(underlying | set.underlying) def |(value : Value) = new Set64(underlying | value.mask64) def &~(value : Value) = new Set64(underlying & (~value.mask64)) def &(set : Set64) = new Set64(underlying & set.underlying) } /** create an empty 64 bit enumeration set */ def Set64 = new Set64 /** create a bit enumeration set according ot underlying */ def Set64(underlying: Long) = new Set64(underlying) /** used to reverse engineer bit locations from pre-defined bit masks */ def maskToBit(n: Long) = { assert(n != 0) var bit = 0 var m = n while ((m & 1) != 1) { m = m >> 1 bit += 1 } assert(m == 1) bit }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?