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