summaryrefslogtreecommitdiff
path: root/sources/scala/Enumeration.scala
blob: 90335ca4dbb1d5e659c5af9627000eef630b9440 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2002-2004, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
** $Id$
\*                                                                      */

package scala;

import scala.collection.mutable._;

/**
 * <p>The class <code>Enumeration</code> provides the same functionality as the
 * <code>enum</code> construct found in C-like languages like C++ or Java.
 * Here is an example:</p>
 * <pre>
 * <b>object</b> Main <b>with</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 =&gt; System.out.println(d) }
 * }
 * </pre>
 *
 * @param initial the initial integer value associated with the first element
 * @param names the sequence of element names of the enumeration
 *
 * @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: _*);

    def name = {
        val cname = scala.runtime.compat.Platform.getClassName(this);
        if (cname.endsWith("$"))
            cname.substring(0, cname.length() - 1);
        else if (cname.endsWith("$class"))
            cname.substring(0, cname.length() - 6);
        else
            cname;
    }

    /**
     * A mapping between the enumeration value id and the enumeration
     * object.
     */
    private var values: Map[Int, Value] = new HashMap;

    /**
     * A cache listing all values of this enumeration.
     */
    private var vcache: List[Value] = null;

    private def updateCache: List[Value] =
        if (vcache == null) {
            vcache = values.values.toList.sort((p1, p2) => p1.id < p2.id);
            vcache
        } else
            vcache;

    protected var nextId = initial;

    protected var nextName = names.elements;

    private var topId = initial;

    final def maxId = topId;

    /**
     * Returns the enumeration value for the given id.
     */
    final def apply(x: Int): Value = values(x);

    /**
     * Returns all values of this enumeration.
     */
    final def elements: Iterator[Value] = updateCache.elements;

    def foreach(f: Value => Unit): Unit = elements foreach f;

    def forall(p: Value => Boolean): Boolean = elements forall p;

    def exists(p: Value => Boolean): Boolean = elements exists p;

    def map[b](f: Value => b): Iterator[b] = elements map f;

    def flatMap[b](f: Value => Iterator[b]): Iterator[b] = elements flatMap f;

    def filter(p: Value => Boolean): Iterator[Value] = elements filter p;

    override def toString(): String = updateCache.mkString("{", ", ", "}");

    protected final def Value: Value =
        new Val(nextId, if (nextName.hasNext) nextName.next else null);

    protected final def Value(i: Int): Value =
        new Val(i, if (nextName.hasNext) nextName.next else null);

    protected final def Value(name: String): Value = new Val(nextId, name);

    protected final def Value(i: Int, name: String): Value = new Val(i, name);

    trait Value extends Ordered[Value] {
        def id: Int;
        def compareTo[S >: Value <% Ordered[S]](that: S): Int = that match {
          case that1: Value => id - that1.id
          case _            => -(that compareTo this)
        }
    }

    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 == null)
                                    Enumeration.this.name + "(" + i + ")";
                                  else
                                    name;
    }
}