001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.math;
005:
006: import java.io.*;
007:
008: /** A primitive Unit of measurement (such as a meter).
009: * @author Per Bothner
010: */
011:
012: public class BaseUnit extends NamedUnit implements Externalizable {
013: /** The name of the "dimension" this is a base unit for. */
014: String dimension;
015:
016: /** BaseUnits are numberd with globally unique indexes. */
017: static int base_count = 0;
018:
019: /** This is an index in the bases array.
020: * The index may change if there are insertions in bases. */
021: int index;
022:
023: /* Array of all existing BaseUnits.
024: * This array is kept sorted (according to the compareTo method).
025: * The reason is to make it easy to keep the BaseUnits in a Dimensions
026: * array to be sorted "lexicographically". One reason we want to
027: * do that is to have a stable serialization representtion. *
028: // static BaseUnit[] bases = null;
029:
030: /** A name for the dimension bing measured.
031: * A meter has the dimension "Length".
032: * BaseUnits are considered equal if their name <em>and</em>
033: * their dimension are equal. (In that case they are also identical.)
034: * We use dimension as a partial guard against accidental name clashes.
035: */
036: public String getDimension() {
037: return dimension;
038: }
039:
040: /** Name for Unit.Empty. */
041: private static final String unitName = "(name)";
042:
043: /** Should only be used for serialization, and Unit.Empty. */
044: public BaseUnit() {
045: name = unitName;
046: index = 0x7fffffff;
047: dims = Dimensions.Empty;
048: }
049:
050: protected void init() {
051: this .base = this ;
052: this .scale = 1.0;
053: this .dims = new Dimensions(this );
054: super .init();
055:
056: this .index = BaseUnit.base_count++;
057: /*
058: if (bases == null)
059: bases = new BaseUnit[10];
060: else if (index >= bases.length)
061: {
062: BaseUnit[] b = new BaseUnit[2 * index];
063: System.arraycopy(bases, 0, b, 0, bases.length);
064: bases = b;
065: }
066: bases[index] = this;
067: // Make sure bases array is sorted.
068: for (int i = index; --i >= 0; )
069: {
070: BaseUnit old = bases[i];
071: int code = compare(old, this);
072: if (code == 0)
073: throw new Error("internal invariant failure");
074: if (code > 0)
075: break;
076: // Swap old and this, and their index fields.
077: bases[i] = this;
078: bases[index] = old;
079: old.index = index;
080: index = i;
081: }
082: */
083: }
084:
085: public BaseUnit(String name) {
086: this .name = name;
087: init();
088: }
089:
090: public BaseUnit(String name, String dimension) {
091: this .name = name;
092: this .dimension = dimension;
093: init();
094: }
095:
096: public int hashCode() {
097: return name.hashCode();
098: }
099:
100: public Unit unit() {
101: return this ;
102: }
103:
104: /** Look for an existing matching BaseUnit.
105: * @param name name of desired BaseUnit, such as "m"
106: * @param dimension a name for what the unit measures, such as "Length".
107: */
108: public static BaseUnit lookup(String name, String dimension) {
109: name = name.intern();
110: if (name == unitName && dimension == null)
111: return Unit.Empty;
112: int hash = name.hashCode();
113: int index = (hash & 0x7FFFFFFF) % table.length;
114: for (NamedUnit unit = table[index]; unit != null; unit = unit.chain) {
115: if (unit.name == name && unit instanceof BaseUnit) {
116: BaseUnit bunit = (BaseUnit) unit;
117: if (bunit.dimension == dimension)
118: return bunit;
119: }
120: }
121: return null;
122: }
123:
124: public static BaseUnit make(String name, String dimension) {
125: BaseUnit old = lookup(name, dimension);
126: return old == null ? new BaseUnit(name, dimension) : old;
127: }
128:
129: public static int compare(BaseUnit unit1, BaseUnit unit2) {
130: int code = unit1.name.compareTo(unit2.name);
131: if (code != 0)
132: return code;
133: String dim1 = unit1.dimension;
134: String dim2 = unit2.dimension;
135: if (dim1 == dim2)
136: return 0;
137: if (dim1 == null)
138: return -1;
139: if (dim2 == null)
140: return 1;
141: return dim1.compareTo(dim2);
142: }
143:
144: /**
145: * @serialData Write the unit name (using writeUTF), followed.
146: * followed by the name of the dimension it is a unit for.
147: * The latter is either null or a String and is written with writeObject.
148: */
149:
150: public void writeExternal(ObjectOutput out) throws IOException {
151: out.writeUTF(name);
152: out.writeObject(dimension);
153: }
154:
155: public void readExternal(ObjectInput in) throws IOException,
156: ClassNotFoundException {
157: name = in.readUTF();
158: dimension = (String) in.readObject();
159: }
160:
161: public Object readResolve() throws ObjectStreamException {
162: BaseUnit unit = lookup(name, dimension);
163: if (unit != null)
164: return unit;
165: init();
166: return this;
167: }
168: }
|