001: package gnu.mapping;
002:
003: import java.io.*;
004: import gnu.lists.*;
005:
006: /** Encapsulate multiple values in a single object.
007: * In Scheme and Lisp mainly used to return multiple values from a function.
008: */
009:
010: public class Values extends TreeList implements Printable,
011: Externalizable {
012: public static final Object[] noArgs = new Object[0];
013:
014: public static final Values empty = new Values(noArgs);
015:
016: public Values() {
017: }
018:
019: /** Constructor.
020: * @param values the values to encapulate
021: */
022: public Values(Object[] values) {
023: for (int i = 0; i < values.length; i++)
024: writeObject(values[i]);
025: }
026:
027: /** Get the values encapsulated. */
028: // Used by CallContext.writeValue, call_with_values.apply(CallContext) FIXME
029: public Object[] getValues() {
030: return isEmpty() ? noArgs : toArray();
031: }
032:
033: public static Object values$V(Object[] vals) {
034: return make(vals);
035: }
036:
037: public static Object make() {
038: return new Values();
039: }
040:
041: public static Object make(Object[] vals) {
042: if (vals.length == 1)
043: return vals[0];
044: else if (vals.length == 0)
045: return empty;
046: else
047: return new Values(vals);
048: }
049:
050: public static Object make(Sequence seq) {
051: int count = seq.size();
052: if (count == 0)
053: return empty;
054: if (count == 1)
055: return seq.get(0);
056: Values vals = new Values();
057: java.util.Enumeration it = seq.elements();
058: while (it.hasMoreElements())
059: vals.writeObject(it.nextElement());
060: return vals;
061: }
062:
063: public static Object make(TreeList list) {
064: return make(list, 0, list.data.length);
065: }
066:
067: public static Object make(TreeList list, int startPosition,
068: int endPosition) {
069: int next;
070: if (startPosition == endPosition
071: || (next = list.nextDataIndex(startPosition)) <= 0)
072: return empty;
073: if (next == endPosition || list.nextDataIndex(next) < 0)
074: return list.getNext(startPosition, null); // Singleton value
075: Values vals = new Values();
076: list.consumeRange(startPosition, endPosition, vals);
077: return vals;
078: }
079:
080: /** Apply a Procedure with these values as the arguments. */
081: public Object call_with(Procedure proc) throws Throwable {
082: return proc.applyN(toArray());
083: }
084:
085: public boolean equals(Object obj) {
086: if (obj instanceof Values)
087: return super .equals(obj);
088: if (size() != 0)
089: return false;
090: Object x = getNext(0, null);
091: return x != null && x.equals(obj);
092: }
093:
094: public void print(java.io.PrintWriter ps) {
095: if (this == empty) {
096: ps.print("#!void");
097: return;
098: }
099: Object[] vals = toArray(); // FIXME!
100: int size = vals.length;
101: ps.print("#<values");
102: for (int i = 0; i < size; i++) {
103: ps.print(" ");
104: SFormat.print(vals[i], ps);
105: }
106: ps.print(">");
107: }
108:
109: /**
110: * @serialData Write the length (using writeInt), followed by
111: * the values in order (written using writeObject).
112: */
113: public void writeExternal(ObjectOutput out) throws IOException {
114: Object[] vals = toArray(); // FIXME
115: int len = vals.length;
116: out.writeInt(len);
117: for (int i = 0; i < len; i++)
118: out.writeObject(vals[i]);
119: }
120:
121: public void readExternal(ObjectInput in) throws IOException,
122: ClassNotFoundException {
123: int len = in.readInt();
124: for (int i = 0; i < len; i++)
125: writeObject(in.readObject());
126: }
127:
128: public Object readResolve() throws ObjectStreamException {
129: return isEmpty() ? empty : this ;
130: }
131:
132: /** Helper method called by code using a SeriesTarget.
133: * The compiled code iterates through zero or more values.
134: * Return the index of the next value, or -1 if currently at eof.
135: * A non-Values object is treated as a singleton value,
136: * so in that case there is no next value.
137: */
138: public static int nextIndex(Object values, int curIndex) {
139: if (values instanceof Values)
140: return ((Values) values).nextDataIndex(curIndex);
141: else
142: return curIndex == 0 ? 1 : -1;
143: }
144:
145: /** Helper method called by code using a SeriesTarget.
146: * The compiled code iterates through zero or more values.
147: * Extract the object referenced by the curIndex.
148: * A non-Values object is treated as a singleton value.
149: */
150: public static Object nextValue(Object values, int curIndex) {
151: if (values instanceof Values)
152: return ((Values) values).getNext(curIndex << 1, null);
153: else
154: return values;
155: }
156:
157: public static void writeValues(Object value, Consumer out) {
158: if (value instanceof Values) {
159: ((Values) value).consume(out);
160: /*
161: Object[] values = ((Values) value).getValues();
162: for (int i = 0; i < values.length; i++)
163: writeValues(values[i], out);
164: */
165: }
166: /*
167: else if (value instanceof Consumable)
168: {
169: ((Consumable) value).consume(out);
170: }
171: */
172: else
173: out.writeObject(value);
174: }
175: }
|